Merge branch 'jn/web' into HEAD

* jn/web:
  gitweb: Fix and simplify "split patch" detection
This commit is contained in:
Junio C Hamano 2007-10-30 21:37:58 -07:00
Родитель 791e421611 0cec6db5cf
Коммит 6beb66968d
1 изменённых файлов: 67 добавлений и 85 удалений

Просмотреть файл

@ -2017,6 +2017,19 @@ sub parse_difftree_raw_line {
return wantarray ? %res : \%res;
}
# wrapper: return parsed line of git-diff-tree "raw" output
# (the argument might be raw line, or parsed info)
sub parsed_difftree_line {
my $line_or_ref = shift;
if (ref($line_or_ref) eq "HASH") {
# pre-parsed (or generated by hand)
return $line_or_ref;
} else {
return parse_difftree_raw_line($line_or_ref);
}
}
# parse line of git-ls-tree output
sub parse_ls_tree_line ($;%) {
my $line = shift;
@ -2060,6 +2073,7 @@ sub parse_from_to_diffinfo {
}
}
} else {
# ordinary (not combined) diff
$from->{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};
if ($diffinfo->{'status'} ne "A") { # not new (added) file
$from->{'href'} = href(action=>"blob", hash_base=>$hash_parent,
@ -2783,6 +2797,7 @@ sub git_print_tree_entry {
## ......................................................................
## functions printing large fragments of HTML
# get pre-image filenames for merge (combined) diff
sub fill_from_file_info {
my ($diff, @parents) = @_;
@ -2799,28 +2814,25 @@ sub fill_from_file_info {
return $diff;
}
# parameters can be strings, or references to arrays of strings
sub from_ids_eq {
my ($a, $b) = @_;
if (ref($a) eq "ARRAY" && ref($b) eq "ARRAY" && @$a == @$b) {
for (my $i = 0; $i < @$a; ++$i) {
return 0 unless ($a->[$i] eq $b->[$i]);
}
return 1;
} elsif (!ref($a) && !ref($b)) {
return $a eq $b;
} else {
return 0;
}
}
# is current raw difftree line of file deletion
sub is_deleted {
my $diffinfo = shift;
return $diffinfo->{'to_id'} eq ('0' x 40);
}
# does patch correspond to [previous] difftree raw line
# $diffinfo - hashref of parsed raw diff format
# $patchinfo - hashref of parsed patch diff format
# (the same keys as in $diffinfo)
sub is_patch_split {
my ($diffinfo, $patchinfo) = @_;
return defined $diffinfo && defined $patchinfo
&& ($diffinfo->{'to_file'} || $diffinfo->{'file'}) eq $patchinfo->{'to_file'};
}
sub git_difftree_body {
my ($difftree, $hash, @parents) = @_;
my ($parent) = $parents[0];
@ -2857,13 +2869,7 @@ sub git_difftree_body {
my $alternate = 1;
my $patchno = 0;
foreach my $line (@{$difftree}) {
my $diff;
if (ref($line) eq "HASH") {
# pre-parsed (or generated by hand)
$diff = $line;
} else {
$diff = parse_difftree_raw_line($line);
}
my $diff = parsed_difftree_line($line);
if ($alternate) {
print "<tr class=\"dark\">\n";
@ -3134,10 +3140,12 @@ sub git_patchset_body {
my ($fd, $difftree, $hash, @hash_parents) = @_;
my ($hash_parent) = $hash_parents[0];
my $is_combined = (@hash_parents > 1);
my $patch_idx = 0;
my $patch_number = 0;
my $patch_line;
my $diffinfo;
my $to_name;
my (%from, %to);
print "<div class=\"patchset\">\n";
@ -3151,73 +3159,46 @@ sub git_patchset_body {
PATCH:
while ($patch_line) {
my @diff_header;
my ($from_id, $to_id);
# git diff header
#assert($patch_line =~ m/^diff /) if DEBUG;
#assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
$patch_number++;
push @diff_header, $patch_line;
# extended diff header
EXTENDED_HEADER:
while ($patch_line = <$fd>) {
chomp $patch_line;
last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /);
if ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {
$from_id = $1;
$to_id = $2;
} elsif ($patch_line =~ m/^index ((?:[0-9a-fA-F]{40},)+[0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {
$from_id = [ split(',', $1) ];
$to_id = $2;
}
push @diff_header, $patch_line;
# parse "git diff" header line
if ($patch_line =~ m/^diff --git (\"(?:[^\\\"]*(?:\\.[^\\\"]*)*)\"|[^ "]*) (.*)$/) {
# $1 is from_name, which we do not use
$to_name = unquote($2);
$to_name =~ s!^b/!!;
} elsif ($patch_line =~ m/^diff --(cc|combined) ("?.*"?)$/) {
# $1 is 'cc' or 'combined', which we do not use
$to_name = unquote($2);
} else {
$to_name = undef;
}
my $last_patch_line = $patch_line;
# check if current patch belong to current raw line
# and parse raw git-diff line if needed
if (defined $diffinfo &&
defined $from_id && defined $to_id &&
from_ids_eq($diffinfo->{'from_id'}, $from_id) &&
$diffinfo->{'to_id'} eq $to_id) {
if (is_patch_split($diffinfo, { 'to_file' => $to_name })) {
# this is continuation of a split patch
print "<div class=\"patch cont\">\n";
} else {
# advance raw git-diff output if needed
$patch_idx++ if defined $diffinfo;
# read and prepare patch information
$diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
# compact combined diff output can have some patches skipped
# find which patch (using pathname of result) we are at now
my $to_name;
if ($diff_header[0] =~ m!^diff --cc "?(.*)"?$!) {
$to_name = $1;
}
do {
# read and prepare patch information
if (ref($difftree->[$patch_idx]) eq "HASH") {
# pre-parsed (or generated by hand)
$diffinfo = $difftree->[$patch_idx];
} else {
$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
}
# check if current raw line has no patch (it got simplified)
if (defined $to_name && $to_name ne $diffinfo->{'to_file'}) {
# find which patch (using pathname of result) we are at now;
if ($is_combined) {
while ($to_name ne $diffinfo->{'to_file'}) {
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
format_diff_cc_simplified($diffinfo, @hash_parents) .
"</div>\n"; # class="patch"
$patch_idx++;
$patch_number++;
last if $patch_idx > $#$difftree;
$diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
}
} until (!defined $to_name || $to_name eq $diffinfo->{'to_file'} ||
$patch_idx > $#$difftree);
}
# modifies %from, %to hashes
parse_from_to_diffinfo($diffinfo, \%from, \%to, @hash_parents);
@ -3227,30 +3208,36 @@ sub git_patchset_body {
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
}
# git diff header
#assert($patch_line =~ m/^diff /) if DEBUG;
#assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
$patch_number++;
# print "git diff" header
$patch_line = shift @diff_header;
print format_git_diff_header_line($patch_line, $diffinfo,
\%from, \%to);
# print extended diff header
print "<div class=\"diff extended_header\">\n" if (@diff_header > 0);
print "<div class=\"diff extended_header\">\n";
EXTENDED_HEADER:
foreach $patch_line (@diff_header) {
while ($patch_line = <$fd>) {
chomp $patch_line;
last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /);
print format_extended_diff_header_line($patch_line, $diffinfo,
\%from, \%to);
}
print "</div>\n" if (@diff_header > 0); # class="diff extended_header"
print "</div>\n"; # class="diff extended_header"
# from-file/to-file diff header
$patch_line = $last_patch_line;
if (! $patch_line) {
print "</div>\n"; # class="patch"
last PATCH;
}
next PATCH if ($patch_line =~ m/^diff /);
#assert($patch_line =~ m/^---/) if DEBUG;
#assert($patch_line eq $last_patch_line) if DEBUG;
my $last_patch_line = $patch_line;
$patch_line = <$fd>;
chomp $patch_line;
#assert($patch_line =~ m/^\+\+\+/) if DEBUG;
@ -3275,16 +3262,11 @@ sub git_patchset_body {
# for compact combined (--cc) format, with chunk and patch simpliciaction
# patchset might be empty, but there might be unprocessed raw lines
for ($patch_idx++ if $patch_number > 0;
for (++$patch_idx if $patch_number > 0;
$patch_idx < @$difftree;
$patch_idx++) {
++$patch_idx) {
# read and prepare patch information
if (ref($difftree->[$patch_idx]) eq "HASH") {
# pre-parsed (or generated by hand)
$diffinfo = $difftree->[$patch_idx];
} else {
$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
}
$diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
# generate anchor for "patch" links in difftree / whatchanged part
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .