diff options
Diffstat (limited to 'gitweb/gitweb.perl')
-rwxr-xr-x | gitweb/gitweb.perl | 263 |
1 files changed, 150 insertions, 113 deletions
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index ec46b8091b..3dfa59f616 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -554,12 +554,17 @@ sub esc_url { } # replace invalid utf8 character with SUBSTITUTION sequence -sub esc_html { +sub esc_html ($;%) { my $str = shift; + my %opts = @_; + $str = to_utf8($str); $str = escapeHTML($str); $str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file) $str =~ s/\033/^[/g; # "escape" ESCAPE (\e) character (e.g. commit 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1) + if ($opts{'-nbsp'}) { + $str =~ s/ / /g; + } return $str; } @@ -784,7 +789,7 @@ sub format_diff_line { $diff_class = " incomplete"; } $line = untabify($line); - return "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n"; + return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n"; } ## ---------------------------------------------------------------------- @@ -860,7 +865,7 @@ sub git_get_hash_by_path { close $fd or return undef; #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' - $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/; + $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/; if (defined $type && $type ne $2) { # type doesn't match return undef; @@ -1111,7 +1116,9 @@ sub parse_commit { @commit_lines = @$commit_text; } else { local $/ = "\0"; - open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", "--max-count=1", $commit_id + open my $fd, "-|", git_cmd(), "rev-list", + "--header", "--parents", "--max-count=1", + $commit_id, "--" or return; @commit_lines = split '\n', <$fd>; close $fd or return; @@ -1275,7 +1282,7 @@ sub parse_ls_tree_line ($;%) { my %res; #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c' - $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/; + $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/s; $res{'mode'} = $1; $res{'type'} = $2; @@ -1292,47 +1299,88 @@ sub parse_ls_tree_line ($;%) { ## ...................................................................... ## parse to array of hashes functions -sub git_get_refs_list { - my $type = shift || ""; - my %refs; - my @reflist; +sub git_get_heads_list { + my $limit = shift; + my @headslist; - my @refs; - open my $fd, "-|", $GIT, "peek-remote", "$projectroot/$project/" + open my $fd, '-|', git_cmd(), 'for-each-ref', + ($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate', + '--format=%(objectname) %(refname) %(subject)%00%(committer)', + 'refs/heads' or return; while (my $line = <$fd>) { - chomp $line; - if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?([^\^]+))(\^\{\})?$/) { - if (defined $refs{$1}) { - push @{$refs{$1}}, $2; - } else { - $refs{$1} = [ $2 ]; - } + my %ref_item; - if (! $4) { # unpeeled, direct reference - push @refs, { hash => $1, name => $3 }; # without type - } elsif ($3 eq $refs[-1]{'name'}) { - # most likely a tag is followed by its peeled - # (deref) one, and when that happens we know the - # previous one was of type 'tag'. - $refs[-1]{'type'} = "tag"; - } + chomp $line; + my ($refinfo, $committerinfo) = split(/\0/, $line); + my ($hash, $name, $title) = split(' ', $refinfo, 3); + my ($committer, $epoch, $tz) = + ($committerinfo =~ /^(.*) ([0-9]+) (.*)$/); + $name =~ s!^refs/heads/!!; + + $ref_item{'name'} = $name; + $ref_item{'id'} = $hash; + $ref_item{'title'} = $title || '(no commit message)'; + $ref_item{'epoch'} = $epoch; + if ($epoch) { + $ref_item{'age'} = age_string(time - $ref_item{'epoch'}); + } else { + $ref_item{'age'} = "unknown"; } + + push @headslist, \%ref_item; } close $fd; - foreach my $ref (@refs) { - my $ref_file = $ref->{'name'}; - my $ref_id = $ref->{'hash'}; + return wantarray ? @headslist : \@headslist; +} + +sub git_get_tags_list { + my $limit = shift; + my @tagslist; + + open my $fd, '-|', git_cmd(), 'for-each-ref', + ($limit ? '--count='.($limit+1) : ()), '--sort=-creatordate', + '--format=%(objectname) %(objecttype) %(refname) '. + '%(*objectname) %(*objecttype) %(subject)%00%(creator)', + 'refs/tags' + or return; + while (my $line = <$fd>) { + my %ref_item; + + chomp $line; + my ($refinfo, $creatorinfo) = split(/\0/, $line); + my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6); + my ($creator, $epoch, $tz) = + ($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/); + $name =~ s!^refs/tags/!!; + + $ref_item{'type'} = $type; + $ref_item{'id'} = $id; + $ref_item{'name'} = $name; + if ($type eq "tag") { + $ref_item{'subject'} = $title; + $ref_item{'reftype'} = $reftype; + $ref_item{'refid'} = $refid; + } else { + $ref_item{'reftype'} = $type; + $ref_item{'refid'} = $id; + } - my $type = $ref->{'type'} || git_get_type($ref_id) || next; - my %ref_item = parse_ref($ref_file, $ref_id, $type); + if ($type eq "tag" || $type eq "commit") { + $ref_item{'epoch'} = $epoch; + if ($epoch) { + $ref_item{'age'} = age_string(time - $ref_item{'epoch'}); + } else { + $ref_item{'age'} = "unknown"; + } + } - push @reflist, \%ref_item; + push @tagslist, \%ref_item; } - # sort refs by age - @reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist; - return (\@reflist, \%refs); + close $fd; + + return wantarray ? @tagslist : \@tagslist; } ## ---------------------------------------------------------------------- @@ -1943,19 +1991,19 @@ sub git_difftree_body { print "</td>\n"; print "<td>$mode_chnge</td>\n"; print "<td class=\"link\">"; - if ($diff{'to_id'} ne $diff{'from_id'}) { # modified - if ($action eq 'commitdiff') { - # link to patch - $patchno++; - print $cgi->a({-href => "#patch$patchno"}, "patch"); - } else { - print $cgi->a({-href => href(action=>"blobdiff", - hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, hash_parent_base=>$parent, - file_name=>$diff{'file'})}, - "diff"); - } - print " | "; + if ($action eq 'commitdiff') { + # link to patch + $patchno++; + print $cgi->a({-href => "#patch$patchno"}, "patch") . + " | "; + } elsif ($diff{'to_id'} ne $diff{'from_id'}) { + # "commit" view and modified file (not onlu mode changed) + print $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, + file_name=>$diff{'file'})}, + "diff") . + " | "; } print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'}, hash_base=>$hash, file_name=>$diff{'file'})}, @@ -1986,19 +2034,19 @@ sub git_difftree_body { -class => "list"}, esc_html($diff{'from_file'})) . " with " . (int $diff{'similarity'}) . "% similarity$mode_chng]</span></td>\n" . "<td class=\"link\">"; - if ($diff{'to_id'} ne $diff{'from_id'}) { - if ($action eq 'commitdiff') { - # link to patch - $patchno++; - print $cgi->a({-href => "#patch$patchno"}, "patch"); - } else { - print $cgi->a({-href => href(action=>"blobdiff", - hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, - hash_base=>$hash, hash_parent_base=>$parent, - file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})}, - "diff"); - } - print " | "; + if ($action eq 'commitdiff') { + # link to patch + $patchno++; + print $cgi->a({-href => "#patch$patchno"}, "patch") . + " | "; + } elsif ($diff{'to_id'} ne $diff{'from_id'}) { + # "commit" view and modified file (not only pure rename or copy) + print $cgi->a({-href => href(action=>"blobdiff", + hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'}, + hash_base=>$hash, hash_parent_base=>$parent, + file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})}, + "diff") . + " | "; } print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'}, hash_base=>$parent, file_name=>$diff{'from_file'})}, @@ -2049,13 +2097,6 @@ sub git_patchset_body { } $patch_idx++; - # for now, no extended header, hence we skip empty patches - # companion to next LINE if $in_header; - if ($diffinfo->{'from_id'} eq $diffinfo->{'to_id'}) { # no change - $in_header = 1; - next LINE; - } - if ($diffinfo->{'status'} eq "A") { # added print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" . $cgi->a({-href => href(action=>"blob", hash_base=>$hash, @@ -2262,8 +2303,7 @@ sub git_tags_body { for (my $i = $from; $i <= $to; $i++) { my $entry = $taglist->[$i]; my %tag = %$entry; - my $comment_lines = $tag{'comment'}; - my $comment = shift @$comment_lines; + my $comment = $tag{'subject'}; my $comment_short; if (defined $comment) { $comment_short = chop_str($comment, 30, 5); @@ -2296,7 +2336,7 @@ sub git_tags_body { $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'}); if ($tag{'reftype'} eq "commit") { print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . - " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'refid'})}, "log"); + " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log"); } elsif ($tag{'reftype'} eq "blob") { print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw"); } @@ -2321,23 +2361,23 @@ sub git_heads_body { my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $headlist->[$i]; - my %tag = %$entry; - my $curr = $tag{'id'} eq $head; + my %ref = %$entry; + my $curr = $ref{'id'} eq $head; if ($alternate) { print "<tr class=\"dark\">\n"; } else { print "<tr class=\"light\">\n"; } $alternate ^= 1; - print "<td><i>$tag{'age'}</i></td>\n" . - ($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") . - $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}), - -class => "list name"},esc_html($tag{'name'})) . + print "<td><i>$ref{'age'}</i></td>\n" . + ($curr ? "<td class=\"current_head\">" : "<td>") . + $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}), + -class => "list name"},esc_html($ref{'name'})) . "</td>\n" . "<td class=\"link\">" . - $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " . - $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " . - $cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") . + $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " . + $cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " . + $cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") . "</td>\n" . "</tr>"; } @@ -2487,18 +2527,9 @@ sub git_summary { my $owner = git_get_project_owner($project); - my ($reflist, $refs) = git_get_refs_list(); - - my @taglist; - my @headlist; - foreach my $ref (@$reflist) { - if ($ref->{'name'} =~ s!^heads/!!) { - push @headlist, $ref; - } else { - $ref->{'name'} =~ s!^tags/!!; - push @taglist, $ref; - } - } + my $refs = git_get_references(); + my @taglist = git_get_tags_list(15); + my @headlist = git_get_heads_list(15); git_header_html(); git_print_page_nav('summary','', $head); @@ -2529,7 +2560,7 @@ sub git_summary { } open my $fd, "-|", git_cmd(), "rev-list", "--max-count=17", - git_get_head_hash($project) + git_get_head_hash($project), "--" or die_error(undef, "Open git-rev-list failed"); my @revlist = map { chomp; $_ } <$fd>; close $fd; @@ -2659,7 +2690,7 @@ HTML print "<tr class=\"$rev_color[$current_color]\">\n"; if ($group_size) { print "<td class=\"sha1\""; - print " title=\"$author, $date\""; + print " title=\"". esc_html($author) . ", $date\""; print " rowspan=\"$group_size\"" if ($group_size > 1); print ">"; print $cgi->a({-href => href(action=>"commit", @@ -2790,9 +2821,9 @@ sub git_tags { git_print_page_nav('','', $head,undef,$head); git_print_header_div('summary', $project); - my ($taglist) = git_get_refs_list("tags"); - if (@$taglist) { - git_tags_body($taglist); + my @tagslist = git_get_tags_list(); + if (@tagslist) { + git_tags_body(\@tagslist); } git_footer_html(); } @@ -2803,9 +2834,9 @@ sub git_heads { git_print_page_nav('','', $head,undef,$head); git_print_header_div('summary', $project); - my ($headlist) = git_get_refs_list("heads"); - if (@$headlist) { - git_heads_body($headlist, $head); + my @headslist = git_get_heads_list(); + if (@headslist) { + git_heads_body(\@headslist, $head); } git_footer_html(); } @@ -2918,7 +2949,7 @@ sub git_blob { $nr++; $line = untabify($line); printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n", - $nr, $nr, $nr, esc_html($line); + $nr, $nr, $nr, esc_html($line, -nbsp=>1); } close $fd or print "Reading blob failed.\n"; @@ -3072,7 +3103,7 @@ sub git_log { my $refs = git_get_references(); my $limit = sprintf("--max-count=%i", (100 * ($page+1))); - open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash + open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--" or die_error(undef, "Open git-rev-list failed"); my @revlist = map { chomp; $_ } <$fd>; close $fd; @@ -3130,7 +3161,7 @@ sub git_commit { $parent = "--root"; } open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id", - @diff_opts, $parent, $hash + @diff_opts, $parent, $hash, "--" or die_error(undef, "Open git-diff-tree failed"); my @difftree = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading git-diff-tree failed"); @@ -3235,7 +3266,8 @@ sub git_blobdiff { if (defined $hash_base && defined $hash_parent_base) { if (defined $file_name) { # read raw output - open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base, + open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, + $hash_parent_base, $hash_base, "--", $file_name or die_error(undef, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; @@ -3249,7 +3281,8 @@ sub git_blobdiff { # try to find filename from $hash # read filtered raw output - open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base + open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, + $hash_parent_base, $hash_base, "--" or die_error(undef, "Open git-diff-tree failed"); @difftree = # ':100644 100644 03b21826... 3b93d5e7... M ls-files.c' @@ -3319,7 +3352,8 @@ sub git_blobdiff { } # open patch output - open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts, $hash_parent, $hash + open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts, + $hash_parent, $hash, "--" or die_error(undef, "Open git-diff failed"); } else { die_error('404 Not Found', "Missing one of the blob diff parameters") @@ -3450,8 +3484,8 @@ sub git_commitdiff { my @difftree; if ($format eq 'html') { open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, - "--no-commit-id", - "--patch-with-raw", "--full-index", $hash_parent, $hash + "--no-commit-id", "--patch-with-raw", "--full-index", + $hash_parent, $hash, "--" or die_error(undef, "Open git-diff-tree failed"); while (chomp(my $line = <$fd>)) { @@ -3462,7 +3496,7 @@ sub git_commitdiff { } elsif ($format eq 'plain') { open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, - '-p', $hash_parent, $hash + '-p', $hash_parent, $hash, "--" or die_error(undef, "Open git-diff-tree failed"); } else { @@ -3639,7 +3673,9 @@ sub git_search { my $alternate = 1; if ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') { $/ = "\0"; - open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", $hash or next; + open my $fd, "-|", git_cmd(), "rev-list", + "--header", "--parents", $hash, "--" + or next; while (my $commit_text = <$fd>) { if (!grep m/$searchtext/i, $commit_text) { next; @@ -3785,7 +3821,7 @@ sub git_shortlog { my $refs = git_get_references(); my $limit = sprintf("--max-count=%i", (100 * ($page+1))); - open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash + open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--" or die_error(undef, "Open git-rev-list failed"); my @revlist = map { chomp; $_ } <$fd>; close $fd; @@ -3813,7 +3849,8 @@ sub git_shortlog { sub git_rss { # http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ - open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150", git_get_head_hash($project) + open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150", + git_get_head_hash($project), "--" or die_error(undef, "Open git-rev-list failed"); my @revlist = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading git-rev-list failed"); @@ -3837,7 +3874,7 @@ XML } my %cd = parse_date($co{'committer_epoch'}); open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, - $co{'parent'}, $co{'id'} + $co{'parent'}, $co{'id'}, "--" or next; my @difftree = map { chomp; $_ } <$fd>; close $fd |