#!/usr/bin/env cmperl
#-*-mode:perl-*-
#***************************************************************************
# (c) Copyright 2003 Reshape Inc., All Rights Reserved.
# www.reshape.com
#***************************************************************************
#
# File : revert_changelist
# Author : Jeremy Russell
# Date : February 12, 2003
#
# Description : Obliterates changes made to a server. This is not a mere
# revert of a change list. This actually obliterates a set
# of files.
#
#***************************************************************************
use strict;
use Carp;
use P4;
use Getopt::Long;
use Dumpvalue;
my (%opts);
GetOptions( \%opts,
'revert=i', # Change number.
'client=s', # Client under which to execute.
'debug=i', # Spits out debug messages.
'execute', # Does the actual obliterate.
'changelist=i', # Previously created changelist in which to open the reverts.
'submit', # Submit the revert change list as needed.
'user=s', # User under which to execute.
'port=s', # Port of the Perforce server on which to execute.
);
sub main
{
my (%opts) = @_;
$opts{debug} = 0 if not $opts{debug};
# Create a set up a Perforce client connection.
my ($p4) = P4->new();
$p4->SetClient($opts{client}) if $opts{client};
$p4->SetPort($opts{port}) if $opts{port};
$p4->SetUser($opts{user}) if $opts{user};
$p4->ParseForms();
my ($count) = 1;
while (($count < 5) && (not ($p4->Init()))){
$count++;
}
my ($change) = $p4->Describe('-s', $opts{revert});
Dumpvalue->new->dumpValue($change) if $opts{debug} > 4;
# Iterate through each file and revert it in the specified style.
if ($opts{execute}) {
my ($number);
if ($opts{changelist}) {
$number = $opts{changelist};
} else {
# Create change list.
my ($form) = $p4->FetchChange();
delete $form->{Files};
$form->{Description} = "SW Internal\n\n\tAutomated revert of a bad checkin from change number $opts{revert}.";
my ($msg) = $p4->SaveChange($form);
$msg =~ /(\d+)/;
$number = $1;
}
print "Change List Number: $number\n";
for (my $x = 0; $x < scalar @{$change->{depotFile}}; $x++) {
# Handle integrates and edits alike.
if (($change->{action}->[$x] eq 'integrate') || ($change->{action}->[$x] eq 'edit')) {
my ($backrev) = $change->{rev}->[$x] - 1;
my ($file) = "$change->{depotFile}->[$x]#$backrev";
my ($local) = $p4->Fstat($change->{depotFile}->[$x])->{clientFile};
# Sync to the previous revision and open it for edit into the desired change list.
$p4->Sync('-f', $file);
$p4->Edit('-c', $number, $change->{depotFile}->[$x]);
# Sync and Resolve sequence for text files. For some reason this method does not work for binaries (.pdf).
$p4->Sync('-f', $local);
$p4->Resolve('-ay', $local);
# Sync and Resolve sequence for binaries. For some reason this method does not work on text files.
$p4->Sync('-f', $change->{depotFile}->[$x]);
$p4->Resolve('-ay', $change->{depotFile}->[$x]);
# We do not want to revert files that turn out ot be the same as the current revision and three revisions identical.
$p4->Revert('-a', $local);
print uc($change->{action}->[$x] ) . " (edit previous version): $file\n" if $opts{debug} > 1;
# Handle deletes.
} elsif ($change->{action}->[$x] eq 'delete') {
my ($backrev) = $change->{rev}->[$x] - 1;
my ($file) = "$change->{depotFile}->[$x]#$backrev";
$p4->Sync('-f', $file);
$p4->Add('-c', $number, $change->{depotFile}->[$x]);
print uc($change->{action}->[$x] ) . " (adds file): $file\n" if $opts{debug} > 1;
# Handle branch and add actions alike.
} elsif (($change->{action}->[$x] eq 'branch') || ($change->{action}->[$x] eq 'add')) {
my ($file) = "$change->{depotFile}->[$x]#$change->{rev}->[$x]";
$p4->Delete('-c', $number, $change->{depotFile}->[$x]);
print uc($change->{action}->[$x] ) . " (deletes file): $file\n" if $opts{debug} > 1;
}
}
if ($opts{submit}) {
my (@output) = $p4->Submit('-c', $number);
print join ("\n", @output), "\n";
}
} else {
for (my $x = 0; $x < scalar @{$change->{depotFile}}; $x++) {
my ($local) = $p4->Fstat($change->{depotFile}->[$x])->{clientFile};
# Handle integrates and edits alike.
if (($change->{action}->[$x] eq 'integrate') || ($change->{action}->[$x] eq 'edit')) {
my ($backrev) = $change->{rev}->[$x] - 1;
my ($file) = "$change->{depotFile}->[$x]#$backrev";
print "[Preview] " . uc($change->{action}->[$x] ) . " (edit previous version): $file $local\n";
# Handle deletes.
} elsif ($change->{action}->[$x] eq 'delete') {
my ($backrev) = $change->{rev}->[$x] - 1;
my ($file) = "$change->{depotFile}->[$x]#$backrev";
print "[Preview] " . uc($change->{action}->[$x] ) . " (adds file): $file $local\n";
# Handle branch and add actions alike.
} elsif (($change->{action}->[$x] eq 'branch') || ($change->{action}->[$x] eq 'add')) {
my ($file) = "$change->{depotFile}->[$x]#$change->{rev}->[$x]";
print "[Preview] " . uc($change->{action}->[$x] ) . " (deletes file): $file $local\n";
}
}
}
$p4->Final();
return 1;
}
exit not main(%opts);