diff options
Diffstat (limited to 'devtools/bin/checkin.pl')
| -rw-r--r-- | devtools/bin/checkin.pl | 660 |
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(); +} + + |