#!/usr/bin/env perl # p4rollback.pl - roll back a submitted Perforce changelist. $USAGE=</Rollback change $change./; open TEMP, ">p4rollbacktempfile.tmp" or die "Can't make temp file."; print TEMP $_; close TEMP; open NEWCHANGE, "p4 change -i < p4rollbacktempfile.tmp |" or die "Can't create new changelist."; while ( ) { if ( /^Change ([0-9]+) created.*/ ) { $rbchange = $1; } } close NEWCHANGE; unlink ( "p4rollbacktempfile.tmp " ); # Step 1 accomplished. # $rbchange is the change that's doing the work. # @files is the raw "p4 files" output of what to roll back. # Step 2: Roll back deletes. foreach ( @files ) { $file = $_; chomp $file; if ( $file !~ /(.*)#[0-9]+ - delete change.*/ ) { next; } #test whether file has been readded $head = `p4 files \"$1\"`; chomp $head; if ( $head ne $file and $ncadds == 0 ) #skip nonconf add { print "Skipping re-add of $1 because it has been modified.\n"; $addsskipped++; next; } print "Rolling back delete of $1.\n"; `p4 sync \"$1\@$prev\"`; if ( $head eq $file or $head =~/(.*)#[0-9]+ - delete change.*/ ) { system( "p4 add -c $rbchange \"$1\"" ); } else { system( "p4 edit -c $rbchange \"$1\"" ); } $delsrolled++; print ( "\n" ); } #step 3: Roll back adds/branches/imports. foreach ( @files ) { $file = $_; chomp $file; if ( $file !~ /(.*)#[0-9]+ - add change.*/ and $file !~ /(.*)#[0-9]+ - branch change.*/ and $file !~ /(.*)#[0-9]+ - import change.*/ ) { next; } #test whether file has been edited $head = `p4 files \"$1\"`; chomp $head; if ( $head ne $file and $ncdels == 0 ) #skip nonconf del { print "Skipping delete of $1 because it has been modified.\n"; $delsskipped++; next; } print "Rolling back add of $1.\n"; `p4 flush $1`; system( "p4 delete -c $rbchange \"$1\"" ); $addsrolled++; print ( "\n" ); } #step 4: Roll back edits/integs/purges. foreach ( @files ) { $file = $_; chomp $file; if ( $file !~ /(.*)#[0-9]+ - edit change.*/ and $file !~ /(.*)#[0-9]+ - integrate change.*/ and $file !~ /(.*)#[0-9]+ - purge change.*/ ) { next; } print "Rolling back edit of $1.\n"; $sync = `p4 sync \"$1\@$prev\"`; if ( $sync =~ /^$1#[0-9] - deleted as .*/ ) { #Must have been a purge. print "Can't roll back $1 because nothing exists at change $prev. (tempobj?)\n"; next; } `p4 edit -c $rbchange \"$1\"`; `p4 sync \"$1\@$change\"`; `p4 resolve -ay \"$1\"`; $editsrolled++; print ( "\n" ); } # Step the last: Summary of what has been done. print "\nSUMMARY:\n"; if ( $editsrolled ) { print "Rolled back $editsrolled edits.\n"; } if ( $addsrolled ) { print "Rolled back $addsrolled adds\/branches.\n"; } if ( $delsskipped ) { print "Skipped $delsskipped add\/branch rollbacks. Use -d or -Ds to do 'em anyway.\n"; } if ( $delsrolled ) { print "Rolled back $delsrolled deletes.\n"; } if ( $addsskipped ) { print "Skipped $addsskipped delete rollbacks. Use -d or -Dt to do 'em anyway.\n"; } print "\nThe above changes have been put into changelist $rbchange. Submit when ready.\n";