#!/usr/bin/perl # # Try to resolve trivial conflicts automatically. # # Example: # # # Process all files in src/backend # grep -r -I -l "^<<<<<<<" src/backend/ | xargs -Ifoo resolve-whitespace-diffs.pl foo # use strict; use warnings; use File::Copy; use File::Temp qw/ tempfile /; my $glob_outfh; # Try to resolve one hunk. # # Args are three strings: # # head - the "head" version of the code # upstream - the "upstream" version of the code # hunk - the whole diff hunk, including the "<<<<<<", "=======" and # ">>>>>>" markers. # # The function prints the result we want, to $glob_outfh. If we don't # know how to resolve this hunk, prints $hunk. Or if we want to take # the upstream version of this, prints $upstream. # sub resolve_hunk { my ($head, $upstream, $hunk) = @_; if (diff_w($head, $upstream)) { # Only whitespace (or other acceptable) changes. Take the upstream version. print $glob_outfh "$upstream"; } else { # cannot resolve this hunk. print $glob_outfh "$hunk"; } } # Are the two input strings identical, in a way that we should just # take the upstream version? sub diff_w { my ($a, $b) = @_; # Ignore all spaces and tabs, like "diff -w". $a =~ s/\h+/ /g; $b =~ s/\h+/ /g; # Mask out CVS keywords. $a =~ s/\$PostgreSQL: .* Exp \$/\$PostgreSQL\$/; $b =~ s/\$PostgreSQL: .* Exp \$/\$PostgreSQL\$/; # Ignore differences in copyright year. $a =~ s/Copyright \(c\) 1996-\d\d\d\d, PostgreSQL Global Development Group/Copyright PGDG/; $b =~ s/Copyright \(c\) 1996-\d\d\d\d, PostgreSQL Global Development Group/Copyright PGDG/; return $a eq $b; } # Resolve hunks in given file. The file is modified in-place! (Or rather, we # make a temporary copy, and copy it over.) sub process_file { my ($infile) = @_; # Open input file open(my $infh, '<', $infile) or die "Could not open file '$infile' $!"; # Open a temporary file to write to. my ($tmpfh, $tmpfilename) = tempfile(); $glob_outfh = $tmpfh; # Process the file. my $state = 'normal'; my $head = ''; my $upstream = ''; my $hunk = ''; while (my $line = <$infh>) { # Look for diff hunk markers, and enter the desired state. if ($line eq "<<<<<<< HEAD\n") { $state = 'head'; $hunk .= $line; next; } if ($line eq "=======\n") { $state = 'upstream'; $hunk .= $line; next; } if ($line =~ /^>>>>>>> .*\n/) { $hunk .= $line; # $hunk now contains the whole hunk, with diff markers and all. # Try to resolve this hunk. resolve_hunk($head, $upstream, $hunk); # Reset the hunk variables, and state. $head = ''; $upstream = ''; $hunk = ''; $state = 'normal'; next; } # Not a marker. if ($state eq 'head') { $head .= $line; $hunk .= $line; } if ($state eq 'upstream') { $upstream .= $line; $hunk .= $line; } if ($state eq 'normal') { print $glob_outfh "$line"; } } close $infh; close $tmpfh; # Copy the temporary file over the original. copy($tmpfilename, $infile) or die "Copy failed: $!"; unlink $tmpfilename; } process_file($ARGV[0])