Skip to content

Commit 6d55f05

Browse files
jnarebJunio C Hamano
authored andcommitted
gitweb: Buffer diff header to deal with split patches + git_patchset_body refactoring
There are some cases when one line from "raw" git-diff output (raw format) corresponds to more than one patch in the patchset git-diff output. To deal with this buffer git diff header and extended diff header (everything up to actual patch) to check from information from "index <hash>..<hash>" extended header line if the patch corresponds to the same or next difftree raw line. This could also be used to gather information needed for hyperlinking, and used for printing gitweb quoted filenames, from extended diff header instead of raw git-diff output. While at it, refactor git_patchset_body subroutine from the event-driven, AWK-like state-machine parsing to sequential parsing: for each patch parse (and output) git diff header, parse extended diff header, parse two-line from-file/to-file diff header, parse patch itself; patch ends with the end of input [file] or the line matching m/^diff /. For better understanding the code, there were added assertions in the comments a la Carp::Assert module. Just in case there is commented out code dealing with unexpected end of input (should not happen, hence commented out). Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <junkio@cox.net>
1 parent 04408c3 commit 6d55f05

File tree

1 file changed

+136
-99
lines changed

1 file changed

+136
-99
lines changed

gitweb/gitweb.perl

Lines changed: 136 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2202,31 +2202,56 @@ sub git_patchset_body {
22022202
my ($fd, $difftree, $hash, $hash_parent) = @_;
22032203

22042204
my $patch_idx = 0;
2205-
my $in_header = 0;
2206-
my $patch_found = 0;
2205+
my $patch_line;
22072206
my $diffinfo;
22082207
my (%from, %to);
2208+
my ($from_id, $to_id);
22092209

22102210
print "<div class=\"patchset\">\n";
22112211

2212-
LINE:
2213-
while (my $patch_line = <$fd>) {
2212+
# skip to first patch
2213+
while ($patch_line = <$fd>) {
22142214
chomp $patch_line;
22152215

2216-
if ($patch_line =~ m/^diff /) { # "git diff" header
2217-
# beginning of patch (in patchset)
2218-
if ($patch_found) {
2219-
# close extended header for previous empty patch
2220-
if ($in_header) {
2221-
print "</div>\n" # class="diff extended_header"
2222-
}
2223-
# close previous patch
2224-
print "</div>\n"; # class="patch"
2225-
} else {
2226-
# first patch in patchset
2227-
$patch_found = 1;
2216+
last if ($patch_line =~ m/^diff /);
2217+
}
2218+
2219+
PATCH:
2220+
while ($patch_line) {
2221+
my @diff_header;
2222+
2223+
# git diff header
2224+
#assert($patch_line =~ m/^diff /) if DEBUG;
2225+
#assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
2226+
push @diff_header, $patch_line;
2227+
2228+
# extended diff header
2229+
EXTENDED_HEADER:
2230+
while ($patch_line = <$fd>) {
2231+
chomp $patch_line;
2232+
2233+
last EXTENDED_HEADER if ($patch_line =~ m/^--- /);
2234+
2235+
if ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {
2236+
$from_id = $1;
2237+
$to_id = $2;
22282238
}
2229-
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
2239+
2240+
push @diff_header, $patch_line;
2241+
}
2242+
#last PATCH unless $patch_line;
2243+
my $last_patch_line = $patch_line;
2244+
2245+
# check if current patch belong to current raw line
2246+
# and parse raw git-diff line if needed
2247+
if (defined $diffinfo &&
2248+
$diffinfo->{'from_id'} eq $from_id &&
2249+
$diffinfo->{'to_id'} eq $to_id) {
2250+
# this is split patch
2251+
print "<div class=\"patch cont\">\n";
2252+
} else {
2253+
# advance raw git-diff output if needed
2254+
$patch_idx++ if defined $diffinfo;
22302255

22312256
# read and prepare patch information
22322257
if (ref($difftree->[$patch_idx]) eq "HASH") {
@@ -2247,100 +2272,112 @@ sub git_patchset_body {
22472272
hash=>$diffinfo->{'to_id'},
22482273
file_name=>$to{'file'});
22492274
}
2250-
$patch_idx++;
2251-
2252-
# print "git diff" header
2253-
$patch_line =~ s!^(diff (.*?) )"?a/.*$!$1!;
2254-
if ($from{'href'}) {
2255-
$patch_line .= $cgi->a({-href => $from{'href'}, -class => "path"},
2256-
'a/' . esc_path($from{'file'}));
2257-
} else { # file was added
2258-
$patch_line .= 'a/' . esc_path($from{'file'});
2259-
}
2260-
$patch_line .= ' ';
2261-
if ($to{'href'}) {
2262-
$patch_line .= $cgi->a({-href => $to{'href'}, -class => "path"},
2263-
'b/' . esc_path($to{'file'}));
2264-
} else { # file was deleted
2265-
$patch_line .= 'b/' . esc_path($to{'file'});
2266-
}
2267-
2268-
print "<div class=\"diff header\">$patch_line</div>\n";
2269-
print "<div class=\"diff extended_header\">\n";
2270-
$in_header = 1;
2271-
next LINE;
2275+
# this is first patch for raw difftree line with $patch_idx index
2276+
# we index @$difftree array from 0, but number patches from 1
2277+
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
22722278
}
22732279

2274-
if ($in_header) {
2275-
if ($patch_line !~ m/^---/) {
2276-
# match <path>
2277-
if ($patch_line =~ s!^((copy|rename) from ).*$!$1! && $from{'href'}) {
2278-
$patch_line .= $cgi->a({-href=>$from{'href'}, -class=>"path"},
2279-
esc_path($from{'file'}));
2280-
}
2281-
if ($patch_line =~ s!^((copy|rename) to ).*$!$1! && $to{'href'}) {
2282-
$patch_line = $cgi->a({-href=>$to{'href'}, -class=>"path"},
2283-
esc_path($to{'file'}));
2284-
}
2285-
# match <mode>
2286-
if ($patch_line =~ m/\s(\d{6})$/) {
2287-
$patch_line .= '<span class="info"> (' .
2288-
file_type_long($1) .
2289-
')</span>';
2280+
# print "git diff" header
2281+
$patch_line = shift @diff_header;
2282+
$patch_line =~ s!^(diff (.*?) )"?a/.*$!$1!;
2283+
if ($from{'href'}) {
2284+
$patch_line .= $cgi->a({-href => $from{'href'}, -class => "path"},
2285+
'a/' . esc_path($from{'file'}));
2286+
} else { # file was added
2287+
$patch_line .= 'a/' . esc_path($from{'file'});
2288+
}
2289+
$patch_line .= ' ';
2290+
if ($to{'href'}) {
2291+
$patch_line .= $cgi->a({-href => $to{'href'}, -class => "path"},
2292+
'b/' . esc_path($to{'file'}));
2293+
} else { # file was deleted
2294+
$patch_line .= 'b/' . esc_path($to{'file'});
2295+
}
2296+
print "<div class=\"diff header\">$patch_line</div>\n";
2297+
2298+
# print extended diff header
2299+
print "<div class=\"diff extended_header\">\n" if (@diff_header > 0);
2300+
EXTENDED_HEADER:
2301+
foreach $patch_line (@diff_header) {
2302+
# match <path>
2303+
if ($patch_line =~ s!^((copy|rename) from ).*$!$1! && $from{'href'}) {
2304+
$patch_line .= $cgi->a({-href=>$from{'href'}, -class=>"path"},
2305+
esc_path($from{'file'}));
2306+
}
2307+
if ($patch_line =~ s!^((copy|rename) to ).*$!$1! && $to{'href'}) {
2308+
$patch_line = $cgi->a({-href=>$to{'href'}, -class=>"path"},
2309+
esc_path($to{'file'}));
2310+
}
2311+
# match <mode>
2312+
if ($patch_line =~ m/\s(\d{6})$/) {
2313+
$patch_line .= '<span class="info"> (' .
2314+
file_type_long($1) .
2315+
')</span>';
2316+
}
2317+
# match <hash>
2318+
if ($patch_line =~ m/^index/) {
2319+
my ($from_link, $to_link);
2320+
if ($from{'href'}) {
2321+
$from_link = $cgi->a({-href=>$from{'href'}, -class=>"hash"},
2322+
substr($diffinfo->{'from_id'},0,7));
2323+
} else {
2324+
$from_link = '0' x 7;
22902325
}
2291-
# match <hash>
2292-
if ($patch_line =~ m/^index/) {
2293-
my ($from_link, $to_link);
2294-
if ($from{'href'}) {
2295-
$from_link = $cgi->a({-href=>$from{'href'}, -class=>"hash"},
2296-
substr($diffinfo->{'from_id'},0,7));
2297-
} else {
2298-
$from_link = '0' x 7;
2299-
}
2300-
if ($to{'href'}) {
2301-
$to_link = $cgi->a({-href=>$to{'href'}, -class=>"hash"},
2302-
substr($diffinfo->{'to_id'},0,7));
2303-
} else {
2304-
$to_link = '0' x 7;
2305-
}
2306-
my ($from_id, $to_id) = ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
2307-
$patch_line =~ s!$from_id\.\.$to_id!$from_link..$to_link!;
2326+
if ($to{'href'}) {
2327+
$to_link = $cgi->a({-href=>$to{'href'}, -class=>"hash"},
2328+
substr($diffinfo->{'to_id'},0,7));
2329+
} else {
2330+
$to_link = '0' x 7;
23082331
}
2309-
print $patch_line . "<br/>\n";
2310-
2311-
} else {
2312-
#$in_header && $patch_line =~ m/^---/;
2313-
print "</div>\n"; # class="diff extended_header"
2314-
$in_header = 0;
2332+
#affirm {
2333+
# my ($from_hash, $to_hash) =
2334+
# ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/);
2335+
# my ($from_id, $to_id) =
2336+
# ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
2337+
# ($from_hash eq $from_id) && ($to_hash eq $to_id);
2338+
#} if DEBUG;
2339+
my ($from_id, $to_id) = ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
2340+
$patch_line =~ s!$from_id\.\.$to_id!$from_link..$to_link!;
2341+
}
2342+
print $patch_line . "<br/>\n";
2343+
}
2344+
print "</div>\n" if (@diff_header > 0); # class="diff extended_header"
2345+
2346+
# from-file/to-file diff header
2347+
$patch_line = $last_patch_line;
2348+
#assert($patch_line =~ m/^---/) if DEBUG;
2349+
if ($from{'href'}) {
2350+
$patch_line = '--- a/' .
2351+
$cgi->a({-href=>$from{'href'}, -class=>"path"},
2352+
esc_path($from{'file'}));
2353+
}
2354+
print "<div class=\"diff from_file\">$patch_line</div>\n";
23152355

2316-
if ($from{'href'}) {
2317-
$patch_line = '--- a/' .
2318-
$cgi->a({-href=>$from{'href'}, -class=>"path"},
2319-
esc_path($from{'file'}));
2320-
}
2321-
print "<div class=\"diff from_file\">$patch_line</div>\n";
2356+
$patch_line = <$fd>;
2357+
#last PATCH unless $patch_line;
2358+
chomp $patch_line;
23222359

2323-
$patch_line = <$fd>;
2324-
chomp $patch_line;
2360+
#assert($patch_line =~ m/^+++/) if DEBUG;
2361+
if ($to{'href'}) {
2362+
$patch_line = '+++ b/' .
2363+
$cgi->a({-href=>$to{'href'}, -class=>"path"},
2364+
esc_path($to{'file'}));
2365+
}
2366+
print "<div class=\"diff to_file\">$patch_line</div>\n";
23252367

2326-
#$patch_line =~ m/^+++/;
2327-
if ($to{'href'}) {
2328-
$patch_line = '+++ b/' .
2329-
$cgi->a({-href=>$to{'href'}, -class=>"path"},
2330-
esc_path($to{'file'}));
2331-
}
2332-
print "<div class=\"diff to_file\">$patch_line</div>\n";
2368+
# the patch itself
2369+
LINE:
2370+
while ($patch_line = <$fd>) {
2371+
chomp $patch_line;
23332372

2334-
}
2373+
next PATCH if ($patch_line =~ m/^diff /);
23352374

2336-
next LINE;
2375+
print format_diff_line($patch_line);
23372376
}
23382377

2339-
print format_diff_line($patch_line);
2378+
} continue {
2379+
print "</div>\n"; # class="patch"
23402380
}
2341-
print "</div>\n" if $in_header; # extended header
2342-
2343-
print "</div>\n" if $patch_found; # class="patch"
23442381

23452382
print "</div>\n"; # class="patchset"
23462383
}

0 commit comments

Comments
 (0)