summaryrefslogtreecommitdiff
path: root/devtools/bin/checkin.pl
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/bin/checkin.pl')
-rw-r--r--devtools/bin/checkin.pl660
1 files changed, 660 insertions, 0 deletions
diff --git a/devtools/bin/checkin.pl b/devtools/bin/checkin.pl
new file mode 100644
index 0000000..8b4eddd
--- /dev/null
+++ b/devtools/bin/checkin.pl
@@ -0,0 +1,660 @@
+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();
+}
+
+