#! /usr/bin/perl -w use strict; if (@ARGV < 1 or $ARGV[0] eq 'default') { print "usage: p4rollback \n"; exit; } foreach my $to (sort @ARGV) { my ($from, $age); print "Looking up current changelist...\n"; if (`p4 changes -m 1` =~ /Change ([0-9]+) on/) { $age = $1 - $to + 2; } else { print "Unable to lookup current changelist\n"; exit; } print "Looking for previous changelist...\n"; open CHANGELIST, "p4 changes -m $age |"; while () { if (/Change ([0-9]+) on/ and $1 < $to) { $from = $1; last; } } close CHANGELIST; if ($from) { print "\nUndoing changes between changelist $from and changelist $to...\n"; } else { print "Unable to lookup previous changelist\n"; exit; } my (@edited, @deleted, @added, @branched, @integrated); my $message = ''; print "\nReading changelist description...\n"; open CHANGELIST, "p4 describe -s $to |"; while () { last if (/Affected files/); $message .= " $_"; } while () { my $line = Strip($_); if ($line =~ /^\.\.\. (.*)#[0-9]+ (edit|add|delete|branch|integrat)/) { print "$1 was $2ed\n"; if ($2 eq "edit") { push @edited, $1; } elsif ($2 eq "integrat") { push @integrated, $1; } elsif ($2 eq "add") { push @added, $1; } elsif ($2 eq "delete") { push @deleted, $1; } elsif ($2 eq "branch") { push @branched, $1; } } } close CHANGELIST; open CHANGELIST, '>changelist.tmp'; print CHANGELIST "Change: new\nDescription:\n Reverting change $to\n\n Original change description:\n\n"; print CHANGELIST $message; close CHANGELIST; my $changelist = `p4 change -i < changelist.tmp`; unlink 'changelist.tmp'; if ($changelist =~ /Change ([0-9]+) created./) { $changelist = $1; print "\nCreated new changelist: $changelist\n"; } else { print "Unable to create new changelist: $changelist\n"; exit; } if (@edited or @deleted or @integrated) { print "\nSyncing edited, integrated, and deleted files to old revision \@$from...\n"; system("p4", "sync", map { "$_\@$from" } (@edited, @deleted, @integrated)); print "\nAuto resolving edited, integrated, and deleted files...\n"; system("p4", "resolve", "-am", @edited, @deleted, @integrated); if (@edited or @integrated) { print "\nOpening edited and integrated files for edit...\n"; system("p4", "edit", "-c", $changelist, @edited, @integrated); } if (@deleted) { print "\nOpening deleted files for add...\n"; system("p4", "add", "-c", $changelist, @deleted); } print "\nSyncing edited, integrated, and deleted files to new revision \@$to...\n"; system("p4", "sync", map { "$_\@$to" } (@edited, @deleted, @integrated)); print "\nResolving edited, integrated, and deleted files ignoring changes on server...\n"; system("p4", "resolve", "-ay", @edited, @deleted, @integrated); } if (@added or @branched) { print "\nDeleting added and branched files...\n"; system("p4", "delete", "-c", $changelist, @added, @branched); } system("p4", "changelist", "-d", $changelist); } sub Strip { my $in = shift; $in =~ s/[^ -~]//go; return $in; }