#!/usr/bin/perl -w # This script is used to turn one or more of the "patch/*" branches # into one or more diffs in the "patches" directory. Pass the option # --gen if you want generated files in the diffs. Pass the name of # one or more diffs if you want to just update a subset of all the # diffs. use strict; use Getopt::Long; my $patches_dir = 'patches'; my $tmp_dir = "patches.$$"; &Getopt::Long::Configure('bundling'); &usage if !&GetOptions( 'skip-check' => \( my $skip_branch_check ), 'gen:s' => \( my $incl_generated_files ), 'help|h' => \( my $help_opt ), ); &usage if $help_opt; if (defined $incl_generated_files) { $patches_dir = $incl_generated_files if $incl_generated_files ne ''; $incl_generated_files = 1; } die "No '$patches_dir' directory was found.\n" unless -d $patches_dir; die "No '.git' directory present in the current dir.\n" unless -d '.git'; open(IN, '-|', 'git status') or die $!; my $status = join('', ); close IN; unless ($skip_branch_check) { die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/; } my($starting_branch) = $status =~ /^# On branch (.+)\n/; my @extra_files; open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n"; while () { if (s/^GENFILES=//) { while (s/\\$//) { $_ .= ; } @extra_files = split(' ', $_); last; } } close IN; if ($incl_generated_files) { die "'$tmp_dir' must not exist in the current directory.\n" if -e $tmp_dir; mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n"; system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/master/" and exit 1; } my $last_touch = time; my(@patches, %local_patch); # Start by finding all patches so that we can load all possible parents. open(PIPE, '-|', 'git', 'branch', '-a') or die $!; while () { if (m# origin/patch/(.*)#) { push(@patches, $1); } elsif (m# patch/(.*)#) { $local_patch{$1} = 1; } } close PIPE; my(%parent, %description); foreach my $patch (@patches) { my $branch = ($local_patch{$patch} ? '' : 'origin/') . "patch/$patch"; my $desc = ''; open(PIPE, '-|', 'git', 'diff', '-U1000', "master...$branch", '--', "PATCH.$patch") or die $!; while () { last if /^@@ /; } while () { next unless s/^[ +]//; if (m#patch -p1 ', "$patches_dir/$patch.diff") or die $!; print OUT $description{$patch}, "\n"; if (system("git merge $parent") != 0) { print qq|"git merge $parent" incomplete -- please fix.\n|; $ENV{PS1} = "[$parent] patch/$patch: "; system $ENV{SHELL} and exit 1; } if ($incl_generated_files) { system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/$patch/" and exit 1; } $last_touch = time; open(PIPE, '-|', 'git', 'diff', $parent) or die $!; DIFF: while () { while (m{^diff --git a/PATCH}) { while () { last if m{^diff --git a/}; } last DIFF if !defined $_; } next if /^index /; print OUT $_; } close PIPE; if ($incl_generated_files) { $parent =~ s#.*/##; open(PIPE, '-|', 'diff', '-up', "$tmp_dir/$parent", "$tmp_dir/$patch") or die $!; while () { s#^(diff -up) $tmp_dir/[^/]+/(.*?) $tmp_dir/[^/]+/(.*)#$1 a/$2 b/$3#o; s#^\Q---\E $tmp_dir/[^/]+/([^\t]+)\t.*#--- a/$1#o; s#^\Q+++\E $tmp_dir/[^/]+/([^\t]+)\t.*#+++ b/$1#o; print OUT $_; } close PIPE; } close OUT; } exit; sub usage { die <