hl2_src-leak-2017/src/devtools/bin/checkin.pl

661 lines
15 KiB
Perl

use strict;
###################################################
# CONFIG VARS
###################################################
# FIXME: load these from a separate file so that each user can have their own config without editingthis file.
my $g_P4UserName = "gary";
my $g_LocalBaseDir = "u:\\hl2";
my $g_LocalBranchSubdir = "src5";
my $g_LocalBranchName = "gary_src5";
my $g_LocalBranchClient = "gary_work_src5";
my $g_MainCopyBaseDir = "u:\\hl2";
my $g_LocalBranchMainCopySubdir = "src5_main";
my $g_LocalBranchMainCopyName = "gary_src5_main";
#my $g_LocalBranchMainCopyClient = "gary_work_src5_main";
my $g_MainBaseDir = "u:\\hl2_main";
my $g_MainBranchSubdir = "src_main";
#my $g_MainBranchName = "gary_src_main";
#my $g_MainBranchClient = "gary_work_src_main";
my $g_UseIncredibuildForMain = 1;
# FIXME: need to make this work for those that don't work on HL2.
my $g_LocalBranchHasHL1Port = 0;
my $g_LocalBranchHasCSPort = 0;
my $g_LocalBranchHasTF2 = 0;
my $g_CheckinFileStampTimes = "c:\\checkin_filetimes.txt";
# either use VSS directly via the command-line, or use Tom's tool.
my $g_UseVSS = 0;
###################################################
# Helper vars made up of config vars
###################################################
my $g_LocalBranchDir = "$g_LocalBaseDir\\$g_LocalBranchSubdir";
my $g_LocalBranchMainCopyDir = "$g_MainCopyBaseDir\\$g_LocalBranchMainCopySubdir";
my $g_MainBranchDir = "$g_MainBaseDir\\$g_MainBranchSubdir";
###################################################
my $g_DebugStub = 0;
my $stage = shift;
if( $stage != 1 &&
$stage != 2 &&
$stage != 3 &&
$stage ne "syncmain" &&
$stage ne "syncmainsrc" &&
$stage ne "synclocal" &&
$stage ne "synclocalrelease" &&
$stage ne "synclocaldebug" &&
$stage ne "synclocalsrc" &&
$stage ne "synclocalsrcrelease" &&
$stage ne "sync" &&
$stage ne "syncmaincontent" )
{
print "checkin.pl 1 : to get started with a checkin\n";
print "checkin.pl 2 : second stage of checkin\n";
print "checkin.pl 3 : third stage of checkin\n";
print "checkin.pl syncmain : sync main source and content, then build\n";
print "checkin.pl syncmainsrc : sync main source then build\n";
print "checkin.pl syncmaincontent : sync main content only\n";
print "checkin.pl synclocal : merge personal branch, sync content,\n";
print " then build.\n";
print "checkin.pl synclocalrelease : merge personal branch, sync content,\n";
print " then build (release only).\n";
print "checkin.pl synclocaldebug : merge personal branch, sync content,\n";
print " then build (debug only).\n";
print "checkin.pl synclocalsrc : merge personal branch, then build.\n";
print "checkin.pl synclocalsrcrelease : merge personal branch, then build\n";
print " (release only).\n";
print "checkin.pl sync : merge personal branch, sync main src,\n";
print " sync content for both, and then build\n";
print " the whole thing.\n";
die;
}
sub RunCmd
{
my $cmd = shift;
print $cmd . "\n";
if( !$g_DebugStub )
{
return system $cmd;
}
}
sub CD
{
my $dir = shift;
print "cd $dir\n";
if( !$g_DebugStub )
{
chdir $dir;
}
}
sub SSGet
{
my $vssdir = shift;
my $localdir = shift;
&CD( $localdir );
&RunCmd( "ss WorkFold $vssdir $localdir" );
print "\n";
my $cmd = "ss get $vssdir -R";
local( *SS );
open SS, "$cmd|";
my $workingdir;
while( <SS> )
{
# FIXME: clean up this output.
$_ =~ s/\n//;
if( m/^\$/ )
{
$workingdir = $_;
# print "WORKING DIR: $_\n";
}
elsif( m/^getting/i )
{
print "GETTING: $workingdir $_\n";
}
elsif( m/^replacing local file/i )
{
print "REPLACING: $workingdir $_\n";
}
elsif( m/^File/ )
{
print "ALREADY EXISTS: $workingdir $_\n";
}
else
{
# print "WTF: $_\n";
}
}
close SS;
}
sub FastSSGet
{
my $localdir = shift;
my $option = shift;
&RunCmd( "\\\\hl2vss\\hl2vss\\win32\\syncfrommirror.bat $option $localdir" );
}
sub FileIsWritable
{
my $file = shift;
my @statresult = stat $file;
die if !@statresult;
my $perms = oct( $statresult[2] );
if( $perms & 2 )
{
return 1;
}
else
{
return 0;
}
}
sub CompareDirs
{
my $filesThatHaveChanged = shift;
my $filesThatHaveNotChanged = shift;
my @out = `robocopy $g_MainBaseDir\\checkinbins\\. $g_MainBaseDir\\. /S /L /V`;
my $line;
my $cwd;
foreach $line ( @out )
{
next if( $line =~ /\*EXTRA Dir/ );
next if( $line =~ /\*EXTRA Dir/ );
next if( $line =~ /\*EXTRA File/ );
if( $line =~ m/\s*\d+\s+(\S+\\)/ )
{
$cwd = $1;
next;
}
if( $line =~ m/\s+Older\s+\d+\s+(\S+)/ )
{
my $testfilename = $cwd . $1;
my $filename = $testfilename;
$filename =~ s/\\checkinbins//i;
my $diffresult = system "diff $testfilename $filename > nil";
if( $diffresult != 0 )
{
push @{$filesThatHaveChanged}, $filename;
}
else
{
if( &FileIsWritable( $filename ) )
{
push @{$filesThatHaveNotChanged}, $filename;
}
}
next;
}
elsif( $line =~ m/\s+same\s+\d+\s+(\S+)/ )
{
my $filename = $cwd . $1;
$filename =~ s/\\checkinbins//i;
if( &FileIsWritable( $filename ) )
{
push @{$filesThatHaveNotChanged}, $filename;
}
next;
}
if( $line =~ m/\s+New File\s+\d+\s+(\S+)/ )
{
die "$cwd $1 didn't build!\n";
}
print "DEBUG: unhandled line: $line\n";
}
}
sub CheckoutFile
{
my $file = shift;
print "-----------------\nchecking out $file\n";
if( $file =~ /src_main/i )
{
# need to use p4 to check this one out.
my $dir = $file;
$dir =~ s/\\([^\\]*)$//;
&CD( $dir );
&RunCmd( "p4 edit $1" );
}
else
{
my $dir = $file;
$dir =~ s/\\([^\\]*)$//;
&CD( $dir );
$file =~ s,\\,/,g;
if( $file =~ m/cstrike/i || $file =~ m/hl1/i )
{
$file =~ s,u:/hl2_main/,\$/hl1ports/release/dev/,gi;
&RunCmd( "ss WorkFold \$/hl1ports/release/dev $g_MainBaseDir" );
}
elsif( $file =~ m/\/tf2/i )
{
$file =~ s,u:/hl2_main/,\$/tf2/release/dev/,gi;
&RunCmd( "ss WorkFold \$/tf2/release/dev $g_MainBaseDir" );
}
else
{
$file =~ s,u:/hl2_main/,\$/hl2/release/dev/,gi;
&RunCmd( "ss WorkFold \$/hl2/release/dev $g_MainBaseDir" );
}
print "\n";
&RunCmd( "ss Checkout -G- $file" );
}
}
sub RevertFile
{
my $file = shift;
print "-----------------\nreverting $file\n";
if( $file =~ /src_main/i )
{
# need to use p4 to revert this one
my $dir = $file;
$dir =~ s/\\([^\\]*)$//;
&CD( $dir );
&RunCmd( "p4 sync -f $1" );
}
else
{
my $dir = $file;
$dir =~ s/\\([^\\]*)$//;
&CD( $dir );
$file =~ s,\\,/,g;
my $vssfile = $file;
if( $file =~ m/cstrike/i || $file =~ m/hl1/i )
{
$vssfile =~ s,u:/hl2_main/,\$/hl1ports/release/dev/,gi;
&RunCmd( "ss WorkFold \$/hl1ports/release/dev $g_MainBaseDir" );
}
elsif( $file =~ m/\/tf2/i )
{
$vssfile =~ s,u:/hl2_main/,\$/tf2/release/dev/,gi;
&RunCmd( "ss WorkFold \$/tf2/release/dev $g_MainBaseDir" );
}
else
{
$vssfile =~ s,u:/hl2_main/,\$/hl2/release/dev/,gi;
&RunCmd( "ss WorkFold \$/hl2/release/dev $g_MainBaseDir" );
}
print "\n";
unlink $file;
&RunCmd( "ss Get -I- $vssfile" );
}
}
sub SyncMainSource
{
# SYNC MAIN
&CD( $g_MainBranchDir );
&RunCmd( "p4 sync" );
}
sub SyncMainContent
{
# SYNC VSS
&CD( $g_MainBranchDir );
&RunCmd( "clean.bat" );
if( $g_UseVSS )
{
&SSGet( "\$/hl2/release/dev", $g_MainBaseDir );
&SSGet( "\$/hl1ports/release/dev", $g_MainBaseDir );
# NOTE: only get tf2 bin since we aren't testing tf2 right now
&SSGet( "\$/tf2/release/dev/tf2/bin", "$g_MainBaseDir/tf2/bin" );
}
else
{
&FastSSGet( $g_MainBaseDir, "all" );
}
}
sub BuildMain
{
if( $g_UseIncredibuildForMain )
{
$ENV{"USE_INCREDIBUILD"} = "1";
}
&CD( $g_MainBranchDir );
&RunCmd( "clean.bat" );
&RunCmd( "build_hl2.bat" );
&RunCmd( "build_hl1_game.bat" );
&RunCmd( "build_cs_game.bat" );
&RunCmd( "build_tf2_game.bat" );
if( $g_UseIncredibuildForMain )
{
undef $ENV{"USE_INCREDIBUILD"};
}
}
sub SyncLocalBranchSource
{
&CD( $g_LocalBranchDir );
&RunCmd( "p4mf.bat $g_LocalBranchName $g_LocalBranchClient pause" );
# FIXME: This needs to specify the changelist since p4mf makes a new changelist.
# &RunCmd( "p4 submit" );
}
sub SyncMainCopySource
{
&CD( $g_LocalBranchMainCopyDir );
&RunCmd( "p4 integrate -d -i -b $g_LocalBranchMainCopyName" );
&RunCmd( "p4 resolve -at ..." );
# Update the changelist and submit
&RunCmd( "p4 change -o | sed -e \"s/<enter description here>/Merge from main/g\" | p4 submit -i" );
}
sub SyncLocalBranchContent
{
&CD( $g_LocalBranchDir );
# CLEAN LOCAL BRANCH
&RunCmd( "clean.bat" );
# SYNC VSS
if( $g_UseVSS )
{
&SSGet( "\$/hl2/release/dev", $g_LocalBaseDir );
if( $g_LocalBranchHasHL1Port || $g_LocalBranchHasCSPort )
{
&SSGet( "\$/hl1ports/release/dev", $g_LocalBaseDir );
}
if( $g_LocalBranchHasTF2 )
{
&SSGet( "\$/tf2/release/dev", $g_LocalBaseDir );
}
}
else
{
if( $g_LocalBranchHasHL1Port || $g_LocalBranchHasCSPort )
{
&FastSSGet( $g_LocalBaseDir, "all" );
}
else
{
&FastSSGet( $g_LocalBaseDir, "hl2" );
}
# FIXME: screwed on tf2 here.
}
}
sub BuildLocalBranch
{
&CD( $g_LocalBranchDir );
# BUILD DEBUG if we don't want release only
if( !( $stage =~ /release/i ) )
{
# CLEAN LOCAL BRANCH
&RunCmd( "clean.bat" );
&RunCmd( "build_hl2.bat debug" );
if( $g_LocalBranchHasHL1Port )
{
&RunCmd( "build_hl1_game.bat debug" );
}
if( $g_LocalBranchHasCSPort )
{
&RunCmd( "build_cs_game.bat debug" );
}
if( $g_LocalBranchHasTF2 )
{
&RunCmd( "build_tf2_game.bat debug" );
}
}
if( !( $stage =~ /debug/i ) )
{
# CLEAN LOCAL BRANCH
&RunCmd( "clean.bat" );
# BUILD RELEASE
&RunCmd( "build_hl2.bat" );
if( $g_LocalBranchHasHL1Port )
{
&RunCmd( "build_hl1_game.bat" );
}
if( $g_LocalBranchHasCSPort )
{
&RunCmd( "build_cs_game.bat" );
}
if( $g_LocalBranchHasTF2 )
{
&RunCmd( "build_tf2_game.bat" );
}
}
}
sub GetMainUpToDate
{
&SyncMainSource();
&SyncMainContent();
&BuildMain();
}
sub LockPerforce
{
while( 1 )
{
my $thing = `p4mutex lock main_src 0 $g_P4UserName 207.173.178.12:1666`;
print $thing;
last if $thing =~ /Success/;
sleep 30;
}
}
sub SaveMainTimeStampsBeforeIntegrate
{
&CD( $g_MainBranchDir );
# Get a list of files that are going to be integrated into main so that we can save off their time stamp info.
my @filestointegrate = `p4 integrate -n -r -b $g_LocalBranchName`;
my $file;
local( * TIMESTAMPS );
open TIMESTAMPS, ">$g_CheckinFileStampTimes";
foreach $file ( @filestointegrate )
{
$file =~ s,//ValveGames/main/src/([^#]*)\#.*,$1,gi;
$file =~ s/\n//;
$file =~ s,\\,/,g;
my $localfilename = "$g_MainBranchDir/$file";
my @statinfo = stat $localfilename;
next if !@statinfo;
my $mtime = $statinfo[9];
print TIMESTAMPS $file . "|" . $mtime . "\n";
}
close TIMESTAMPS;
}
sub SetMainTimeStampsOnRevertedFiles
{
&CD( $g_MainBranchDir );
# Get a list of files that we might have to revert times on if they aren't in the changelist.
local( *TIMESTAMPS );
open TIMESTAMPS, "<$g_CheckinFileStampTimes";
my @timestamps = <TIMESTAMPS>;
my %filetotimestamp;
my $i;
for( $i = 0; $i < scalar( @timestamps ); $i++ )
{
$timestamps[$i] =~ s/\n//;
$timestamps[$i] =~ m/^(.*)\|(.*)$/;
$filetotimestamp{$1} = $2;
}
close TIMESTAMPS;
my $key;
foreach $key( keys( %filetotimestamp ) )
{
print "before: \'$key\" \"$filetotimestamp{$key}\"\n";
}
local( *CHANGELIST );
open CHANGELIST, "p4 change -o|";
while( <CHANGELIST> )
{
if( m,//ValveGames/main/src/(.*)\s+\#,i )
{
if( defined $filetotimestamp{$1} )
{
undef $filetotimestamp{$1};
}
}
}
close CHANGELIST;
foreach $key( keys( %filetotimestamp ) )
{
if( defined $filetotimestamp{$key} )
{
my $filename = $g_MainBranchDir . "/" . $key;
$filename =~ s,/,\\,g;
my @statresults;
if( @statresults = stat $filename )
{
my $mode = $statresults[2];
my $atime = $statresults[8];
my $mtime = $statresults[9];
print "reverting timestamp for $filename\n";
chmod 0666, $filename || die $!;
utime $atime, $filetotimestamp{$key}, $filename || die $!;
chmod $mode, $filename || die $!;
}
}
}
}
if( $stage eq "synclocal" || $stage eq "synclocalrelease" || $stage eq "synclocaldebug" || $stage eq "sync" )
{
&SyncLocalBranchSource();
&SyncMainCopySource();
&SyncLocalBranchContent();
&BuildLocalBranch();
}
if( $stage eq "synclocalsrc" || $stage eq "synclocalsrcrelease" )
{
&SyncLocalBranchSource();
&SyncMainCopySource();
&BuildLocalBranch();
}
if( $stage eq "syncmainsrc" )
{
&SyncMainSource();
&BuildMain();
}
if( $stage eq "syncmain" || $stage eq "sync" )
{
&GetMainUpToDate();
}
if( $stage eq "syncmaincontent" )
{
&SyncMainContent();
}
if( $stage == 1 )
{
# lock p4
# &LockPerforce();
&GetMainUpToDate();
# merge main into local branch
&SyncLocalBranchSource();
# TODO: need a way to detect if there are conflicts or not. If there are, pause here.
# Make a copy of targets so that we can tell which ones changed.
&RunCmd( "robocopy $g_MainBaseDir\\ $g_MainBaseDir\\checkinbins\\ /purge" );
&RunCmd( "robocopy $g_MainBaseDir\\bin\\. $g_MainBaseDir\\checkinbins\\bin\\. /mir" );
&RunCmd( "robocopy $g_MainBaseDir\\hl2\\bin\\. $g_MainBaseDir\\checkinbins\\hl2\\bin\\. /mir" );
&RunCmd( "robocopy $g_MainBaseDir\\hl1\\bin\\. $g_MainBaseDir\\checkinbins\\hl1\\bin\\. /mir" );
&RunCmd( "robocopy $g_MainBaseDir\\cstrike\\bin\\. $g_MainBaseDir\\checkinbins\\cstrike\\bin\\. /mir" );
&RunCmd( "robocopy $g_MainBaseDir\\tf2\\bin\\. $g_MainBaseDir\\checkinbins\\tf2\\bin\\. /mir" );
&RunCmd( "robocopy $g_MainBaseDir\\platform\\servers\\. $g_MainBaseDir\\checkinbins\\platform\\servers\\. /mir" );
&RunCmd( "robocopy $g_MainBranchDir\\lib\\. $g_MainBaseDir\\checkinbins\\$g_MainBranchSubdir\\lib\\. /mir" );
# integrate from personal branch into main. . accept theirs.
# TODO: need to check if main has a changelist or not and warn!
&CD( $g_MainBranchDir );
&SaveMainTimeStampsBeforeIntegrate();
&RunCmd( "p4 integrate -r -b $g_LocalBranchName" );
&RunCmd( "p4 resolve -at ..." );
# revert unchanged files.
my @unchanged = `p4 diff -sr`;
my $file;
foreach $file ( @unchanged )
{
&RunCmd( "p4 revert $file" );
}
print "Do \"checkin.pl 2\" when you are done reverting unchanging files and fixing up any other diffs in your main client.\n";
}
elsif( $stage == 2 )
{
&SetMainTimeStampsOnRevertedFiles();
# build main with the new changes
&BuildMain();
# compare what we just built to what we saved off earlier
my @filesToCheckOut;
my @filesThatHaveNotChanged;
&CompareDirs( \@filesToCheckOut, \@filesThatHaveNotChanged );
my $file;
# $g_DebugStub = 1;
foreach $file ( @filesThatHaveNotChanged )
{
&RevertFile( $file );
}
foreach $file ( @filesToCheckOut )
{
&CheckoutFile( $file );
}
print "-----------------\n";
print "Do \"checkin.pl 3\" when you are finished testing to checkin files and release the mutex.\n";
}
elsif( $stage == 3 )
{
my @filesToCheckOut;
my @filesThatHaveNotChanged;
&CompareDirs( \@filesToCheckOut, \@filesThatHaveNotChanged );
# TODO: check stuff in here and unlock p4
# TODO: go ahead and sync src_main to main so that they match
# TODO: merge main into src again so any changes that you made while checking in are propogated
&SyncMainCopySource();
}