X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/18fa91296bb0e85130f8e98e710528a18a20028f..c202b4fa967c3cf98a9504a9ac98d5b931819a5e:/support/patch-update diff --git a/support/patch-update b/support/patch-update index 2fba7b30..4892d668 100755 --- a/support/patch-update +++ b/support/patch-update @@ -6,105 +6,208 @@ # 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 ), + 'shell|s' => \( my $launch_shell ), + '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' directory present in the current dir.\n" unless -d 'patches'; +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, '<', 'prepare-source.mak') or die "Couldn't open prepare-source.mak: $!\n"; -$_ = join('', ); +my($status, $is_clean, $starting_branch) = &check_git_status; +if (!$skip_branch_check && !$is_clean) { + die "The checkout is not clean:\n", $status; +} + +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; -my @extra_files = m{\n([^\s:]+):.*\n\t\S}g; -my $incl_generated_files; +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; -$incl_generated_files = shift if @ARGV && $ARGV[0] eq '--gen'; +my(%patches, %local_patch); -system "git-checkout master" and exit 1; -my $last_touch = time; +# 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/(.*)#) { + $patches{$1} = 1; + } elsif (m# patch/(.*)#) { + $patches{$1} = $local_patch{$1} = 1; + } +} +close PIPE; -if ($incl_generated_files) { - die "'a' must not exist in the current directory.\n" if -e 'a'; - die "'b' must not exist in the current directory.\n" if -e 'b'; - system "./prepare-source && rsync -a @extra_files a/" and exit 1; +my @patches = sort keys %patches; + +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 ) { - if (m# origin/patch/(.*)#) { - push(@patches, $1); - } elsif (m# patch/(.*)#) { - $local_patch{$1} = 1; - } } -close PIPE; +my %completed; foreach my $patch (@patches) { + next if $completed{$patch}++; + last unless update_patch($patch); +} + +if ($incl_generated_files) { + system "rm -rf $tmp_dir"; +} + +sleep 1 if $last_touch == time; +system "git checkout $starting_branch" and exit 1; + +exit; + + +sub update_patch +{ + my($patch) = @_; + + my $parent = $parent{$patch}; + if (defined $parent) { + unless ($completed{$parent}++) { + update_patch($parent); + } + $parent = "patch/$parent"; + } else { + $parent = 'master'; + } + print "======== $patch ========\n"; + sleep 1 if $incl_generated_files && $last_touch == time; if ($local_patch{$patch}) { - system "git-checkout patch/$patch" and exit 1; + system "git checkout patch/$patch" and return 0; } else { - system "git-checkout --track -b patch/$patch origin/patch/$patch" and exit 1; + system "git checkout --track -b patch/$patch origin/patch/$patch" and return 0; } - $last_touch = time; - - my $parent = 'master'; - open(IN, '<', 'PATCH') or next; - open(OUT, '>', "patches/$patch.diff") or die $!; - while () { - if (m#patch -p1 ; + next unless /^y/i; + return 0; + } + ($status, $is_clean) = &check_git_status; + last if $is_clean; + print $status; } - print OUT $_; } - close IN; - print OUT "\n"; - if (system("git-rebase -m $parent") != 0) { - print qq|"git-rebase -m $parent" incomplete -- please fix.\n|; - $ENV{PS1} = "[$parent] patch/$patch: "; - system $ENV{SHELL} and exit 1; + open(OUT, '>', "$patches_dir/$patch.diff") or die $!; + print OUT $description{$patch}, "\n"; + + if ($incl_generated_files) { + system "./config.status Makefile && make gen && rsync -a @extra_files $tmp_dir/$patch/"; } + $last_touch = time; - open(PIPE, '-|', 'git-diff', 'master') or die $!; - while () { - last if m{^diff --git a/PATCH b/PATCH$}; + 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 $_; } - while () { - last if m{^diff --git a/}; - } - print OUT $_, ; close PIPE; if ($incl_generated_files) { - system "./prepare-source && rsync -a @extra_files b/" and exit 1; - open(PIPE, '-|', 'diff', '-up', 'a', 'b') or die $!; + $parent =~ s#.*/##; + open(PIPE, '-|', 'diff', '-up', "$tmp_dir/$parent", "$tmp_dir/$patch") or die $!; while () { - s/^((?:---|\+\+\+) [^\t]+)\t.*/$1/; + 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; + + 1; } -if ($incl_generated_files) { - system "rm -rf a b"; +exit; + +sub check_git_status +{ + open(IN, '-|', 'git status') or die $!; + my $status = join('', ); + close IN; + my $is_clean = $status =~ /\nnothing to commit \(working directory clean\)/; + my($starting_branch) = $status =~ /^# On branch (.+)\n/; + ($status, $is_clean, $starting_branch); } -print "-------- master --------\n"; -sleep 1 if $last_touch == time; -system "git-checkout master && ./prepare-source"; +sub usage +{ + die <