From aef3bc1013d867bc5a293cb1f8a12e93a0c60a90 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Sat, 11 Jun 2011 22:14:19 -0700 Subject: [PATCH] Bug 663674 - Remove cross-commit, r=ted --- tools/cross-commit | 504 --------------------------------------------- 1 file changed, 504 deletions(-) delete mode 100755 tools/cross-commit diff --git a/tools/cross-commit b/tools/cross-commit deleted file mode 100755 index 62a8f657e8a..00000000000 --- a/tools/cross-commit +++ /dev/null @@ -1,504 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -use Getopt::Long; -Getopt::Long::Configure("bundling", "pass_through"); -use File::Spec; -use File::Temp qw(tempfile tempdir); - - -################################################################################ -# Configure Script - -# Whether or not to be chatty about what we're doing. -# Set this on the command line with --verbose. -our $VERBOSE = 1; - -# A horizontal rule for formatting lines. -my $ss = "--------------------------------------------------------------------"; - -# Whether or not to continue when we encounter a potentially serious problem. -# Set this on the command line with --live-dangerously. -our $DOUBLEOH7 = 0; - -# The branches to land on. -# Set this on the command line once for each branch with --branch . -our @branches; - -# Convenient shorthand for --branch HEAD and --branch MOZILLA_1_8_BRANCH. -# Set these on the command line with --trunk and --moz18. -my $TRUNK; -my $MOZ18; - -# The branches to land on if the user doesn't specify a branch. -my @DEFAULT_BRANCHES = qw(HEAD MOZILLA_1_8_BRANCH); - -# The CVS options. Some of these may not make sense in the context -# of this script. Use them at your own risk. Note that -f and -r are both -# CVS options and CVS commit options (i.e. they can go either before -# the command as general CVS options or after the commit command as different -# commit-specific options). To avoid ambiguity, you must specify -# the CVS options as --cvs-f and --cvs-r. -our $CVS_OPTION_allow_root; -our $CVS_OPTION_a; -our $CVS_OPTION_b; -our $CVS_OPTION_T; -our $CVS_OPTION_d; -our $CVS_OPTION_e; -our $CVS_OPTION_f; -our $CVS_OPTION_n; -our $CVS_OPTION_Q; -our $CVS_OPTION_q; -our $CVS_OPTION_r; -our $CVS_OPTION_s; -our $CVS_OPTION_t; -our $CVS_OPTION_v; -our $CVS_OPTION_w; -our $CVS_OPTION_x; -our $CVS_OPTION_z; - -our @CVS_OPTIONS; - -# The CVS commit options: -l -R -r -F -f and -m. -# Some of these may not make sense in the context of this script. -# Use them at your own risk. -our $CVS_COMMIT_OPTION_l; -our $CVS_COMMIT_OPTION_R; -our $CVS_COMMIT_OPTION_r; -our $CVS_COMMIT_OPTION_F; -our $CVS_COMMIT_OPTION_f; -our $CVS_COMMIT_OPTION_m; - -our @CVS_COMMIT_OPTIONS; - -# Retrieve configuration from a config file, if any. Config files are just -# regular Perl files and can override the values of all configuration variables -# declared above with "our". -my $cfg_file; -if (-e ".xcconfig") { $cfg_file = ".xcconfig" } -elsif (-e "~/.xcconfig") { $cfg_file = "~/.xcconfig" } -if ($cfg_file) { - my $return = do $cfg_file; - die "couldn't parse $cfg_file: $@" if $@; - die "couldn't do $cfg_file: $!" unless defined $return; - die "couldn't run $cfg_file" unless $return; -} - -# Parse options from the command line. -GetOptions( - # Options specific to this script. - "verbose" => \$VERBOSE, - "trunk" => \$TRUNK, - "moz18" => \$MOZ18, - "branch=s" => \@branches, - "live-dangerously" => \$DOUBLEOH7, - - # CVS options (those that go between "cvs" and "commit"). - "allow-root=s" => \$CVS_OPTION_allow_root, - "a" => \$CVS_OPTION_a, - "b=s" => \$CVS_OPTION_b, - "T=s" => \$CVS_OPTION_T, - "d=s" => \$CVS_OPTION_d, - "e=s" => \$CVS_OPTION_e, - "cvs-f" => \$CVS_OPTION_f, - "n" => \$CVS_OPTION_n, - "Q" => \$CVS_OPTION_Q, - "q" => \$CVS_OPTION_q, - "cvs-r" => \$CVS_OPTION_r, - "s" => \$CVS_OPTION_s, - "t" => \$CVS_OPTION_t, - "v|version" => \$CVS_OPTION_v, - "w" => \$CVS_OPTION_w, - "x" => \$CVS_OPTION_x, - "z" => \$CVS_OPTION_z, - - # CVS commit options (those that go after "commit"). - "l" => \$CVS_COMMIT_OPTION_l, - "R" => \$CVS_COMMIT_OPTION_R, - "r" => \$CVS_COMMIT_OPTION_r, - "F=s" => \$CVS_COMMIT_OPTION_F, - "f" => \$CVS_COMMIT_OPTION_f, - "m=s" => \$CVS_COMMIT_OPTION_m, - ); - - -# The rest of the command line should be files or directories to commit. -# You can also leave it blank, in which case it'll check the current directory, -# just like "cvs commit" does. - -push(@CVS_OPTIONS, - $CVS_OPTION_allow_root ? ("--allow-root", $CVS_OPTION_allow_root) : (), - $CVS_OPTION_a ? "-a" : (), - $CVS_OPTION_b ? ("-b", $CVS_OPTION_b) : (), - $CVS_OPTION_T ? ("-T", $CVS_OPTION_T) : (), - $CVS_OPTION_d ? ("-d", $CVS_OPTION_d) : (), - $CVS_OPTION_e ? ("-e", $CVS_OPTION_e) : (), - $CVS_OPTION_f ? "-f" : (), - $CVS_OPTION_n ? "-n" : (), - $CVS_OPTION_Q ? "-Q" : (), - $CVS_OPTION_q ? "-q" : (), - $CVS_OPTION_r ? "-r" : (), - $CVS_OPTION_s ? "-s" : (), - $CVS_OPTION_t ? "-t" : (), - $CVS_OPTION_v ? "-v" : (), - $CVS_OPTION_w ? "-w" : (), - $CVS_OPTION_x ? "-x" : (), - $CVS_OPTION_z ? ("-z", $CVS_OPTION_z) : (), -); - -push(@CVS_COMMIT_OPTIONS, - $CVS_COMMIT_OPTION_l ? "-l" : (), - $CVS_COMMIT_OPTION_R ? "-R" : (), - $CVS_COMMIT_OPTION_r ? "-r" : (), - $CVS_COMMIT_OPTION_F ? ("-F", $CVS_COMMIT_OPTION_F) : (), - $CVS_COMMIT_OPTION_f ? "-f" : (), - $CVS_COMMIT_OPTION_m ? ("-m", $CVS_COMMIT_OPTION_m) : (), -); - - -################################################################################ -# Initialize - -# Duplicate the VERBOSE filehandle to STDOUT if we're being verbose; -# otherwise point it to /dev/null. -my $devnull = File::Spec->devnull(); -open(VERBOSE, $VERBOSE ? ">-" : ">$devnull") or warn "Can't output verbose: $!"; - - -################################################################################ -# Get Modified Files and Current Branch - -my $files = get_modified_files(\@ARGV); -if (scalar(keys(%$files)) == 0) { - die "*** Didn't find any modified files.\n"; -} -else { - print VERBOSE "*** Modified Files:\n " . - join("\n ", sort(keys(%$files))) . "\n"; -} - -my $current_branch = get_current_branch($files); -print VERBOSE "*** Working Branch:\n $current_branch\n"; - - -################################################################################ -# Get Branches to Land On - -# Figure out what branches the user wants to land on. Branches can be specified -# via "--branch " or the "--trunk" and "--moz18" shortcuts. If the user -# doesn't specify any branches, we land on the trunk and the MOZILLA_1_8_BRANCH. -push(@branches, "HEAD") if $TRUNK and !grep($_ eq "HEAD", @branches); -push(@branches, "MOZILLA_1_8_BRANCH") - if $MOZ18 and !grep($_ eq "MOZILLA_1_8_BRANCH", @branches); -push(@branches, @DEFAULT_BRANCHES) if scalar(@branches) == 0; -print VERBOSE "*** Committing to Branches:\n " . join("\n ", @branches) . - "\n"; - -################################################################################ -# Check for Problems - -# Make sure the changes apply cleanly to all branches the user wants -# to land them on. -my @conflicts; -foreach my $branch (@branches) { - print VERBOSE "*** Checking for conflicts on $branch... "; - foreach my $spec (sort(keys(%$files))) { - my ($rv, $output, $errors) = - run_cvs("update", [cvs_branch($branch), $spec], 1, 1); - if ($rv != 0) { - # These are spurious errors that go away once we check in - # the removal to the working branch, so we can ignore them. - # XXX Can we really? Might they not also occur in other situations - # where we shouldn't ignore them? - if ($errors =~ m/removed $spec was modified by second party/) { - print VERBOSE "(we can safely ignore this conflict)\n"; - next; - } - push(@conflicts, $branch); - } - } -} -if (scalar(@conflicts) > 0) { - die "Conflicts found on " . join(", ", @conflicts) . ".\n" - . "Please resolve them, then try your commit again.\n"; -} -else { - print VERBOSE "No conflicts found; good.\n"; -} - - -################################################################################ -# Land on Some Branch - -# From now on, if we encounter an error, we should try to return the user's tree -# to its original state, so override the die handler with a function that tries -# to CVS update the tree back to the original working branch. -local $SIG{__DIE__} = sub { - my ($message) = @_; - - print $message; - print VERBOSE "*** Returning your tree to its original working branch... "; - run_cvs("update", [cvs_branch($current_branch), keys(%$files)]); - die; -}; - -# We gotta land somewhere once and then merge those changes into other branches. -my $land_branch; -if (grep($_ eq $current_branch, @branches)) { - # The changes are landing on the current branch. Groovy, let's land - # there first. It matters for additions and removals, I think. - $land_branch = $current_branch; -} -else { - # Just land on the first branch in the list. - $land_branch = $branches[0]; - print VERBOSE "*** Switching to $land_branch... "; - run_cvs("update", [cvs_branch($land_branch), keys(%$files)]); -} - -print VERBOSE "*** Committing to $land_branch... "; -my ($rv, $output, $errors) = - run_cvs("commit", [@CVS_COMMIT_OPTIONS, keys(%$files)]); - - -################################################################################ -# Extract Commit Info - -print VERBOSE "*** Extracting commit info.\n"; -my @lines = (split/\n/, $output); -for ( my $i = 0 ; $i < scalar(@lines); $i++ ) { - if ($lines[$i] =~ m/^(?:Checking in|Removing) (.*);$/) { - my $spec = $1; - print VERBOSE " $spec: "; - my $entry = $files->{$spec}; - $entry or die " not on the list of files committed!\n"; - $i += 2; - $lines[$i] =~ m/^(initial|new)\srevision:\s - ([\d\.]+|delete)(?:;\s - previous\srevision:\s - ([\d\.]+))?$/x; - if ($1 eq "new") { - print VERBOSE "$3 -> $2.\n"; - $entry->{new_rev} = $2 eq "delete" ? "" : $2; - $entry->{old_rev} = $3; - } - elsif ($1 eq "initial") { - print VERBOSE "new file -> $2.\n"; - $entry->{new_rev} = $2; - $entry->{old_rev} = ""; - } - else { - die "can't figure out its old and new revisions!\n"; - } - } -} - - -################################################################################ -# Check In to Other Branches - -foreach my $branch (@branches) { - next if $branch eq $land_branch; - - foreach my $spec (sort(keys(%$files))) { - my $entry = $files->{$spec}; - - if ($entry->{old_rev} && $entry->{new_rev}) { - print VERBOSE "*** Merging $spec changes from $entry->{old_rev} " . - "to $entry->{new_rev} into $branch... "; - run_cvs("update", [cvs_branch($branch), "-j", $entry->{old_rev}, - "-j", $entry->{new_rev}, $spec]); - } - elsif ($entry->{old_rev}) { - print VERBOSE "*** Removing $spec on $branch... "; - # CVS doesn't tag removed files with a new revision number, - # so we merge from the old revision to the branch itself. - run_cvs("update", [cvs_branch($branch), "-j", $entry->{old_rev}, - "-j", $land_branch, $spec]); - } - elsif ($entry->{new_rev}) { - print VERBOSE "*** Adding $spec on $branch... "; - run_cvs("update", [cvs_branch($branch), "-j", $entry->{new_rev}, - $spec]); - } - - print VERBOSE "*** Committing $spec on $branch... "; - run_cvs("commit", [@CVS_COMMIT_OPTIONS, $spec]); - } -} - -print VERBOSE "*** Returning your tree to its original working branch... "; -run_cvs("update", [cvs_branch($current_branch), keys(%$files)]); - -################################################################################ -# Utility Functions - -# Returns a hash of modified files indexed by file spec. -sub get_modified_files { - my ($args) = @_; - - # We figure out which files are modified by running "cvs update" - # and grepping for /^(M|A) /. We run the command in dry run mode so we - # don't actually update the files in the process. - # XXX perhaps we should update them, since we won't be able to commit them - # if they aren't up-to-date; on the other hand, CVS makes you update them - # manually rather than automatically upon commit, so perhaps there's method - # to its madness. - - print VERBOSE "*** Looking for modified files... "; - my ($rv, $output, $errors) = run_cvs("update", $args, 1); - # Break the output into lines and filter for lines about changes. - my @lines = grep(m/^(M|A|R) /, split(/\n/, $output)); - my %files; - foreach my $line (@lines) { - $line =~ m/^(M|A|R) (.*)/; - $files{$2} = get_cvs_file($2); - $files{$2}->{change_type} = $1; - } - return \%files; -} - -# Given a file spec, returns a hash of information about the file extracted -# from the CVS/Entries file. -sub get_cvs_file { - my ($spec) = @_; - my ($volume, $directories, $filename) = File::Spec->splitpath($spec); - my $cvsdir = $directories ? File::Spec->catdir($directories, "CVS") : "CVS"; - my $files = File::Spec->catpath($volume, $cvsdir, "Entries"); - open(ENTRIES, "<", $files) - or die "Can't read entries file $files for file $spec: $!"; - while () { - my ($name, $revision, $timestamp, $conflict, $options, $tagdate) = - ($_ =~ m|/([^/]*) # filename - /([^/]*) # revision - /([^/+]*) # timestamp - (\+[^/]*)? # (optional) conflict - /([^/]*) # options - /([^/]*) # tag/date - |x); - next if $name ne $filename; - close ENTRIES; - return { name => $name, revision => $revision, conflict => $conflict, - options => $options, tagdate => $tagdate }; - } - die "Couldn't find entry for file $spec in entries file $files."; -} - -# Given a set of files, extracts their current working branch, testing for -# multiple branches and date-based tags in the process. -sub get_current_branch { - my ($files) = @_; - my %branches; - foreach my $filename (keys %$files) { - my $entry = $files->{$filename}; - $entry->{tagdate} =~ m/^(T|D)?(.*)/; - if ($1 and $1 eq "D") { warn "$filename checked out by date $1\n" } - elsif ($2 eq "") { $branches{"HEAD"}++ } - else { $branches{$2}++ } - if (scalar(keys(%branches)) > 1 && !$DOUBLEOH7) { - die("Modified files checked out from multiple branches:\n " - . join("\n ", map("$_: $files->{$_}->{tagdate}", - sort(keys(%$files)))) - . "Sounds scary, so I'm stopping. Want me to continue?\n" - . "Run me again with --live-dangerously and tell my authors\n" - . "how it went.\n"); - } - } - return (keys(%branches))[0]; -} - -# Runs a CVS command and outputs the results. Runs the command in dry run mode -# if dry run is enabled globally ($DRY_RUN) or for this specific function call; -# and dies on error by default, but can be set to merely warn on error. -# Returns the return value of the CVS command, its output, and its errors. -sub run_cvs { - my ($cmd, $args, $dry_run, $warn_on_err) = @_; - # Let callers override dry run setting, since certain information gathering - # routines always run in dry run mode no matter what the global setting is. - - my ($rv, $output, $errors) = - system_capture("cvs", - @CVS_OPTIONS, - $dry_run && !$CVS_OPTION_n ? "-n" : (), - $cmd, - @$args); - if ($rv != 0) { - if (!$warn_on_err) { - die "\n$errors\n$ss\n"; - } - warn "\n$errors\n$ss\n" - } - else { - print VERBOSE "\n$output\n$ss\n"; - } - return ($rv, $output, $errors); -} - -# Returns the appropriate CVS command line argument for specifying a branch. -# Usually this is -r , but if we're dealing with the special HEAD -# branch it's -A instead. -sub cvs_branch { - my ($branch) = @_; - return $branch eq "HEAD" ? "-A" : ("-r", $branch); -} - -# Runs a command and captures its output and errors. -# Returns the command's exit code, output, and errors. -sub system_capture { - # XXX This should be using in-memory files, but they require that we close - # STDOUT and STDERR before reopening them on the in-memory files, and doing - # that on STDERR causes CVS to choke with return value 256. - - my ($command, @args) = @_; - - my ($rv, $output, $errors); - - # Back up the original STDOUT and STDERR so we can restore them later. - open(OLDOUT, ">&STDOUT") or die "Can't back up STDOUT to OLDOUT: $!"; - open(OLDERR, ">&STDERR") or die "Can't back up STDERR to OLDERR: $!"; - use vars qw( *OLDOUT *OLDERR ); # suppress "used only once" warnings - - # Close and reopen STDOUT and STDERR to in-memory files, which are just - # scalars that take output and append it to their value. - # XXX Disabled in-memory files in favor of temp files until in-memory issues - # can be worked out. - #close(STDOUT); - #close(STDERR); - #open(STDOUT, ">", \$output) or die "Can't open STDOUT to output var: $!"; - #open(STDERR, ">", \$errors) or die "Can't open STDERR to errors var: $!"; - my $outfile = tempfile(); - my $errfile = tempfile(); - # Perl 5.6.1 filehandle duplication doesn't support the three-argument form - # of open, so we can't just open(STDOUT, ">&", $outfile); instead we have to - # create an alias OUTFILE and then do open(STDOUT, ">&OUTFILE"). - local *OUTFILE = *$outfile; - local *ERRFILE = *$errfile; - use vars qw( *OUTFILE *ERRFILE ); # suppress "used only once" warnings - open(STDOUT, ">&OUTFILE") or open(STDOUT, ">&OLDOUT") - and die "Can't dupe STDOUT to output file: $!"; - open(STDERR, ">&ERRFILE") or open(STDOUT, ">&OLDOUT") - and open(STDERR, ">&OLDERR") - and die "Can't dupe STDERR to errors file: $!"; - - # Run the command. - print VERBOSE "$command " . join(" ", @args) . "\n"; - $rv = system($command, @args); - - # Grab output and errors from the temp files. In a block to localize $/. - # XXX None of this would be necessary if in-memory files was working. - { - local $/ = undef; - seek($outfile, 0, 0); - seek($errfile, 0, 0); - $output = <$outfile>; - $errors = <$errfile>; - } - - # Restore original STDOUT and STDERR. - close(STDOUT); - close(STDERR); - open(STDOUT, ">&OLDOUT") or die "Can't restore STDOUT from OLDOUT: $!"; - open(STDERR, ">&OLDERR") or die "Can't restore STDERR from OLDERR: $!"; - - return ($rv, $output, $errors); -}