5 # git merge driver for substitutions (like RCS/CVS)
6 # driver line: .... %O %A %B %L
10 my $rawin = 0; # feed diff to stdin for testing (do NOT set $debug=1)
12 # We want TRACE open so we don't need to test $debug everywhere, but we skip
13 # this first block because it's expensive and dumpfile() hangs with $rawin.
14 my $sink = ($^O
eq "MSWin32") ?
"NUL" : "/dev/null";
15 my $dbgfile = ($^O
eq "MSWin32") ?
"$ENV{TEMP}.$$" : "/tmp/trace.$$";
16 open TRACE
, ">>", $rawin?
"/dev/tty":(($debug==0)?
$sink : $dbgfile);
17 print TRACE
"TEST TRACE\n";
19 print TRACE
"START CLIENT ARGV:\n";
20 print TRACE
"[0] $0\n";
22 for(my $x=0;$x<scalar @ARGV;$x++){
24 print TRACE
"[$x1] $ARGV[$x]\n";
27 foreach my $k (sort keys %ENV){
28 next unless ($k =~ m/^GIT_/);
29 print TRACE
" $k => $ENV{$k}\n";
31 print TRACE
"CWD: " . `pwd`;
32 &dumpfile
($ARGV[0], "[0O]");
33 &dumpfile
($ARGV[1], "[1A]");
34 &dumpfile
($ARGV[2], "[2B]");
35 print TRACE
"L=$ARGV[3]\n";
39 my $mark_len = $ARGV[3];
40 $mark_len = 3 if($mark_len==0 && $rawin);
42 my $mark_start = '<' x
$mark_len;
43 my $mark_middle = '=' x
$mark_len;
44 my $mark_end = '>' x
$mark_len;
47 # pick up the prefix for substitutions in this repo
51 $PREFIX = `git config --local --get nethack.substprefix`;
60 #system "git merge-file -p .... > temp
61 my $tags = "-L CURRENT -L ANCESTOR -L OTHER"; # XXX should "CURRENT" be "MINE"?
62 @out = `git merge-file -p $tags $ARGV[1] $ARGV[0] $ARGV[2]`;
63 #NB: we don't check the exit value because it's useless
64 print TRACE
"MERGE-FILE START\n".join("",@out)."MERGE-FILE END\n";
67 ($cntout,@out) = &edit_merge
(@out);
70 print "COUNT: $cntout\n";
73 # spit @out to $ARGV[1] (careful: what about EOL character?)
74 open OUT
, ">$ARGV[1]" or die "Can't open $ARGV[1]";
78 print TRACE
"WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n";
79 &dumpfile
($ARGV[1], "READBACK");
81 print TRACE
"COUNT: $cntout\n";
83 exit( ($cntout>0) ?
1 : 0);
85 #git merge-file [-L <current-name> [-L <base-name> [-L <other-name>]]]
86 # [--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
87 # [--[no-]diff3] <current-file> <base-file> <other-file>
88 #The `merge.*.driver` variable's value is used to construct a command to run to merge ancestor's
89 # version (%O), current version (%A) and the other branches' version (%B). These three tokens are
90 # replaced with the names of temporary files that hold the contents of these versions when the
91 # command line is built. Additionally, %L will be replaced with the conflict marker size (see
94 # keep failing so we don't need to keep changing the setup while building this script
98 print TRACE
"FILE $tag START\n";
99 print TRACE
`hexdump -C $file`;
100 print TRACE
"FILE END\n";
105 # $::count is a bit ugly XXX
106 local $::count
= 0; # we need the number of conflicts for exit()
110 while($_ = shift @input){
111 if(m/^$mark_start /){
112 print TRACE
"FOUND A CONFLICT\n";
115 while($_ = shift @input){
121 push(@out, &edit_conflict
(@conflict));
126 print TRACE
"RETURN count=$::count\n";
127 return($::count
, @out);
133 print TRACE
"EDIT START: " . scalar(@in)."\n";
135 foreach my $x (@in){ my $xx = $x; chomp($xx); print TRACE
"-$xx-\n"; }
137 print TRACE
"EDIT END INPUT\n";
139 # one-line change - use as base case to develop the code
140 # ours ARGV[1] top-of-diff
141 # theirs ARGV[2] bottom-of-diff
144 # [1] $$PREFIX-Date: 1 ...
146 # [3] $$PREFIX-Date: 3 ...
148 if(scalar(@in) == 5 && $in[2] =~ m/^$mark_middle/){
149 my $back = &merge_one_line_maybe
($in[1],$in[3]); # (ours, theirs)
151 $::count
++; # leave the conflict
159 # Start at the top of both sections and work downwards. As long as the lines can be merged,
160 # push them out and keep going. If there are lines left, we will still have a conflict but
161 # we can try to make it smaller. Push out the start-conflict marker. Start at the
162 # bottom of both section and work upwards. As long as the lines can be merged, reverse push out
163 # the merged line and keep going. (We know there will be lines left at some point.) Push out
164 # remaining (middle) lines from OURS. Push out mark_middle. Push out remaining middle lines
165 # from THEIRS. Push out end-conflict marker. $::count++; return (@a,$b,@c,$d,@e,$f,@g)
174 # not matched - return the unchanged conflict
179 # XXX This is expensive. Add a quick check for "anything that looks like a subst var" and just
180 # declare the lines unmergeable if it fails.
181 sub merge_one_line_maybe
{
182 my($ours, $theirs) = @_;
192 my($ourstype, $theirtype);
193 my($oursvar, $theirvar);
194 my($oursval, $theirval);
197 ($ourstype, $theirtype) = (0,0);
198 ($oursvar, $theirvar) = (undef, undef);
199 ($oursvar, $theirvar) = (undef, undef);
201 if($ours =~ m/\G\$$PREFIX-([A-Z][a-z]+)\$/gc){
205 if($theirs =~ m/\G\$$PREFIX-([A-Z][a-z]+)\$/gc){
211 if($ours =~ m/\G\$$PREFIX-([A-Za-z]+):\s+(.*?)\s\$/gc){
218 if($theirs =~ m/\G\$$PREFIX-([A-Za-z]+):\s+(.*?)\s\$/gc){
226 if($ours =~ m/\G(\$?[^\x24]*)/gc){
232 if($theirs =~ m/\G(\$?[^\x24]*)/gc){
237 print TRACE
"MID: $ourstype/$oursval $theirtype/$theirval\n";
239 if(pos($ours)==length $ours && pos($theirs) == length $theirs){
242 if($ourstype == 0 && $theirtype == 0){
243 die "NHsubst MERGE FAILED - aborted infinite loop\n";
246 # now see if ours and their match or can be resolved
248 if($ourstype == 3 && $theirtype == 3){
249 #mismatch is \s vs \s\s - where is this coming from?
250 # HACK - hopefully temporary
251 if($oursval =~ m/^\s+$/ && $theirval =~ m/^\s+$/){
255 if($oursval eq $theirval){
261 if($ourstype == 3 || $theirtype == 3){
264 # XXX we could do better: on failure of one field, return 2 lines with the fields we _can_ fix
265 # substituted into those lines, leaving only the fail-to-match bits for the user to
268 if($oursvar ne $theirvar){
271 my $m = merge_one_var_maybe
($oursvar, $oursval, $theirval);
280 # return undef if we can't merge the values; $NAME: VALUE $ or $NAME$ (as appropriate) if we can.
281 sub merge_one_var_maybe
{
282 my($varname, $oursval, $theirval) = @_;
283 print TRACE
"MVM: -$varname-$oursval-$theirval-\n";
287 my $fn = "PREFIX::$varname";
289 $resolvedas = &$fn($PREFIX,$varname,$oursval, $theirval);
291 $resolvedas = undef; # can't resolve
295 if(!defined $resolvedas){
296 $::count
++; # we have an externally visible conflict
305 # Resolve the conflict of a single var's 2 values. Return undef to leave the conflict.
307 my($PREFIX, $varname, $mine, $theirs) = @_;
308 my $m = ($mine =~ m/(\d+)/)[0];
309 my $t = ($theirs =~ m/(\d+)/)[0];
310 return undef unless ($m>0) && ($t>0);
312 return "\$$PREFIX-$varname: " . (($m>$t)?
$mine:$theirs) .' $';
319 my($PREFIX, $varname, $mine, $theirs) = @_;
320 $mine =~ s/^\s+//; $mine =~ s/\s+$//;
321 $theirs =~ s/^\s+//; $theirs =~ s/\s+$//;
322 return "\$$PREFIX-$varname: $mine \$" if(length $mine);
323 return "\$$PREFIX-$varname: $theirs \$" if(length $theirs);
324 return "\$$PREFIX-$varname\$" if(length $theirs);
328 my($PREFIX, $varname, $mine, $theirs) = @_;
329 my($m) = ($mine =~ m/1.(\d+)/);
330 my($t) = ($theirs =~ m/1.(\d+)/);
331 if($m > 0 && $t > 0){
332 my $q = ($m > $t) ?
$m : $t;
333 return "\$$PREFIX-$varname: 1.$q \$";
336 return "\$$PREFIX-$varname: 1.$m \$";
339 return "\$$PREFIX-$varname: 1.$t \$";
341 return "\$$PREFIX-$varname\$";
380 $TEST-Date
: 3 $ yes
$TEST-Date
: 4 $
382 $TEST-Date
: 1 $ yes
$TEST-Date
: 5 $
389 $TEST-Branch
: theirs
$
394 /* NetHack 3.6 objnam.c $TEST-Date$ $TEST-Branch$:$TEST-Revision$ */
396 /* NetHack 3.6 objnam.c $TEST-Date: 1426977394 2015/03/21 22:36:34 $ $TEST-Branch: master $:$TEST-Revision: 1.108 $ */