Merge branch 'jn/web' (early part)
* 'jn/web' (early part): gitweb: Add "next" link to commit view gitweb: Add title attribute to ref marker with full ref name gitweb: Do not show difftree for merges in "commit" view gitweb: SHA-1 in commit log message links to "object" view gitweb: Hyperlink target of symbolic link in "tree" view (if possible) gitweb: Add generic git_object subroutine to display object of any type gitweb: Show target of symbolic link in "tree" view gitweb: Don't use Content-Encoding: header in git_snapshot
This commit is contained in:
commit
9057695012
@ -434,6 +434,7 @@ my %actions = (
|
|||||||
"tags" => \&git_tags,
|
"tags" => \&git_tags,
|
||||||
"tree" => \&git_tree,
|
"tree" => \&git_tree,
|
||||||
"snapshot" => \&git_snapshot,
|
"snapshot" => \&git_snapshot,
|
||||||
|
"object" => \&git_object,
|
||||||
# those below don't need $project
|
# those below don't need $project
|
||||||
"opml" => \&git_opml,
|
"opml" => \&git_opml,
|
||||||
"project_list" => \&git_project_list,
|
"project_list" => \&git_project_list,
|
||||||
@ -827,15 +828,13 @@ sub format_log_line_html {
|
|||||||
my $line = shift;
|
my $line = shift;
|
||||||
|
|
||||||
$line = esc_html($line, -nbsp=>1);
|
$line = esc_html($line, -nbsp=>1);
|
||||||
if ($line =~ m/([0-9a-fA-F]{40})/) {
|
if ($line =~ m/([0-9a-fA-F]{8,40})/) {
|
||||||
my $hash_text = $1;
|
my $hash_text = $1;
|
||||||
if (git_get_type($hash_text) eq "commit") {
|
|
||||||
my $link =
|
my $link =
|
||||||
$cgi->a({-href => href(action=>"commit", hash=>$hash_text),
|
$cgi->a({-href => href(action=>"object", hash=>$hash_text),
|
||||||
-class => "text"}, $hash_text);
|
-class => "text"}, $hash_text);
|
||||||
$line =~ s/$hash_text/$link/;
|
$line =~ s/$hash_text/$link/;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return $line;
|
return $line;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,7 +855,8 @@ sub format_ref_marker {
|
|||||||
$name = $ref;
|
$name = $ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
$markers .= " <span class=\"$type\">" . esc_html($name) . "</span>";
|
$markers .= " <span class=\"$type\" title=\"$ref\">" .
|
||||||
|
esc_html($name) . "</span>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1989,12 +1989,73 @@ sub git_print_log ($;%) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# return link target (what link points to)
|
||||||
|
sub git_get_link_target {
|
||||||
|
my $hash = shift;
|
||||||
|
my $link_target;
|
||||||
|
|
||||||
|
# read link
|
||||||
|
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
|
||||||
|
or return;
|
||||||
|
{
|
||||||
|
local $/;
|
||||||
|
$link_target = <$fd>;
|
||||||
|
}
|
||||||
|
close $fd
|
||||||
|
or return;
|
||||||
|
|
||||||
|
return $link_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
# given link target, and the directory (basedir) the link is in,
|
||||||
|
# return target of link relative to top directory (top tree);
|
||||||
|
# return undef if it is not possible (including absolute links).
|
||||||
|
sub normalize_link_target {
|
||||||
|
my ($link_target, $basedir, $hash_base) = @_;
|
||||||
|
|
||||||
|
# we can normalize symlink target only if $hash_base is provided
|
||||||
|
return unless $hash_base;
|
||||||
|
|
||||||
|
# absolute symlinks (beginning with '/') cannot be normalized
|
||||||
|
return if (substr($link_target, 0, 1) eq '/');
|
||||||
|
|
||||||
|
# normalize link target to path from top (root) tree (dir)
|
||||||
|
my $path;
|
||||||
|
if ($basedir) {
|
||||||
|
$path = $basedir . '/' . $link_target;
|
||||||
|
} else {
|
||||||
|
# we are in top (root) tree (dir)
|
||||||
|
$path = $link_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
# remove //, /./, and /../
|
||||||
|
my @path_parts;
|
||||||
|
foreach my $part (split('/', $path)) {
|
||||||
|
# discard '.' and ''
|
||||||
|
next if (!$part || $part eq '.');
|
||||||
|
# handle '..'
|
||||||
|
if ($part eq '..') {
|
||||||
|
if (@path_parts) {
|
||||||
|
pop @path_parts;
|
||||||
|
} else {
|
||||||
|
# link leads outside repository (outside top dir)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push @path_parts, $part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$path = join('/', @path_parts);
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
# print tree entry (row of git_tree), but without encompassing <tr> element
|
# print tree entry (row of git_tree), but without encompassing <tr> element
|
||||||
sub git_print_tree_entry {
|
sub git_print_tree_entry {
|
||||||
my ($t, $basedir, $hash_base, $have_blame) = @_;
|
my ($t, $basedir, $hash_base, $have_blame) = @_;
|
||||||
|
|
||||||
my %base_key = ();
|
my %base_key = ();
|
||||||
$base_key{hash_base} = $hash_base if defined $hash_base;
|
$base_key{'hash_base'} = $hash_base if defined $hash_base;
|
||||||
|
|
||||||
# The format of a table row is: mode list link. Where mode is
|
# The format of a table row is: mode list link. Where mode is
|
||||||
# the mode of the entry, list is the name of the entry, an href,
|
# the mode of the entry, list is the name of the entry, an href,
|
||||||
@ -2005,7 +2066,22 @@ sub git_print_tree_entry {
|
|||||||
print "<td class=\"list\">" .
|
print "<td class=\"list\">" .
|
||||||
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
||||||
file_name=>"$basedir$t->{'name'}", %base_key),
|
file_name=>"$basedir$t->{'name'}", %base_key),
|
||||||
-class => "list"}, esc_path($t->{'name'})) . "</td>\n";
|
-class => "list"}, esc_path($t->{'name'}));
|
||||||
|
if (S_ISLNK(oct $t->{'mode'})) {
|
||||||
|
my $link_target = git_get_link_target($t->{'hash'});
|
||||||
|
if ($link_target) {
|
||||||
|
my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
|
||||||
|
if (defined $norm_target) {
|
||||||
|
print " -> " .
|
||||||
|
$cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
|
||||||
|
file_name=>$norm_target),
|
||||||
|
-title => $norm_target}, esc_path($link_target));
|
||||||
|
} else {
|
||||||
|
print " -> " . esc_path($link_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "</td>\n";
|
||||||
print "<td class=\"link\">";
|
print "<td class=\"link\">";
|
||||||
print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
||||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||||
@ -3414,8 +3490,7 @@ sub git_snapshot {
|
|||||||
my $filename = basename($project) . "-$hash.tar.$suffix";
|
my $filename = basename($project) . "-$hash.tar.$suffix";
|
||||||
|
|
||||||
print $cgi->header(
|
print $cgi->header(
|
||||||
-type => 'application/x-tar',
|
-type => "application/$ctype",
|
||||||
-content_encoding => $ctype,
|
|
||||||
-content_disposition => 'inline; filename="' . "$filename" . '"',
|
-content_disposition => 'inline; filename="' . "$filename" . '"',
|
||||||
-status => '200 OK');
|
-status => '200 OK');
|
||||||
|
|
||||||
@ -3498,14 +3573,45 @@ sub git_commit {
|
|||||||
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
|
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
|
||||||
|
|
||||||
my $parent = $co{'parent'};
|
my $parent = $co{'parent'};
|
||||||
|
my $parents = $co{'parents'}; # listref
|
||||||
|
|
||||||
|
# we need to prepare $formats_nav before any parameter munging
|
||||||
|
my $formats_nav;
|
||||||
|
if (!defined $parent) {
|
||||||
|
# --root commitdiff
|
||||||
|
$formats_nav .= '(initial)';
|
||||||
|
} elsif (@$parents == 1) {
|
||||||
|
# single parent commit
|
||||||
|
$formats_nav .=
|
||||||
|
'(parent: ' .
|
||||||
|
$cgi->a({-href => href(action=>"commit",
|
||||||
|
hash=>$parent)},
|
||||||
|
esc_html(substr($parent, 0, 7))) .
|
||||||
|
')';
|
||||||
|
} else {
|
||||||
|
# merge commit
|
||||||
|
$formats_nav .=
|
||||||
|
'(merge: ' .
|
||||||
|
join(' ', map {
|
||||||
|
$cgi->a({-href => href(action=>"commitdiff",
|
||||||
|
hash=>$_)},
|
||||||
|
esc_html(substr($_, 0, 7)));
|
||||||
|
} @$parents ) .
|
||||||
|
')';
|
||||||
|
}
|
||||||
|
|
||||||
if (!defined $parent) {
|
if (!defined $parent) {
|
||||||
$parent = "--root";
|
$parent = "--root";
|
||||||
}
|
}
|
||||||
|
my @difftree;
|
||||||
|
if (@$parents <= 1) {
|
||||||
|
# difftree output is not printed for merges
|
||||||
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
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");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
my @difftree = map { chomp; $_ } <$fd>;
|
@difftree = map { chomp; $_ } <$fd>;
|
||||||
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
||||||
|
}
|
||||||
|
|
||||||
# non-textual hash id's can be cached
|
# non-textual hash id's can be cached
|
||||||
my $expires;
|
my $expires;
|
||||||
@ -3517,16 +3623,10 @@ sub git_commit {
|
|||||||
|
|
||||||
my $have_snapshot = gitweb_have_snapshot();
|
my $have_snapshot = gitweb_have_snapshot();
|
||||||
|
|
||||||
my @views_nav = ();
|
|
||||||
if (defined $file_name && defined $co{'parent'}) {
|
|
||||||
push @views_nav,
|
|
||||||
$cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
|
|
||||||
"blame");
|
|
||||||
}
|
|
||||||
git_header_html(undef, $expires);
|
git_header_html(undef, $expires);
|
||||||
git_print_page_nav('commit', '',
|
git_print_page_nav('commit', '',
|
||||||
$hash, $co{'tree'}, $hash,
|
$hash, $co{'tree'}, $hash,
|
||||||
join (' | ', @views_nav));
|
$formats_nav);
|
||||||
|
|
||||||
if (defined $co{'parent'}) {
|
if (defined $co{'parent'}) {
|
||||||
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
|
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
|
||||||
@ -3567,7 +3667,7 @@ sub git_commit {
|
|||||||
}
|
}
|
||||||
print "</td>" .
|
print "</td>" .
|
||||||
"</tr>\n";
|
"</tr>\n";
|
||||||
my $parents = $co{'parents'};
|
|
||||||
foreach my $par (@$parents) {
|
foreach my $par (@$parents) {
|
||||||
print "<tr>" .
|
print "<tr>" .
|
||||||
"<td>parent</td>" .
|
"<td>parent</td>" .
|
||||||
@ -3589,11 +3689,61 @@ sub git_commit {
|
|||||||
git_print_log($co{'comment'});
|
git_print_log($co{'comment'});
|
||||||
print "</div>\n";
|
print "</div>\n";
|
||||||
|
|
||||||
|
if (@$parents <= 1) {
|
||||||
|
# do not output difftree/whatchanged for merges
|
||||||
git_difftree_body(\@difftree, $hash, $parent);
|
git_difftree_body(\@difftree, $hash, $parent);
|
||||||
|
}
|
||||||
|
|
||||||
git_footer_html();
|
git_footer_html();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub git_object {
|
||||||
|
# object is defined by:
|
||||||
|
# - hash or hash_base alone
|
||||||
|
# - hash_base and file_name
|
||||||
|
my $type;
|
||||||
|
|
||||||
|
# - hash or hash_base alone
|
||||||
|
if ($hash || ($hash_base && !defined $file_name)) {
|
||||||
|
my $object_id = $hash || $hash_base;
|
||||||
|
|
||||||
|
my $git_command = git_cmd_str();
|
||||||
|
open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
|
||||||
|
or die_error('404 Not Found', "Object does not exist");
|
||||||
|
$type = <$fd>;
|
||||||
|
chomp $type;
|
||||||
|
close $fd
|
||||||
|
or die_error('404 Not Found', "Object does not exist");
|
||||||
|
|
||||||
|
# - hash_base and file_name
|
||||||
|
} elsif ($hash_base && defined $file_name) {
|
||||||
|
$file_name =~ s,/+$,,;
|
||||||
|
|
||||||
|
system(git_cmd(), "cat-file", '-e', $hash_base) == 0
|
||||||
|
or die_error('404 Not Found', "Base object does not exist");
|
||||||
|
|
||||||
|
# here errors should not hapen
|
||||||
|
open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
|
||||||
|
or die_error(undef, "Open git-ls-tree failed");
|
||||||
|
my $line = <$fd>;
|
||||||
|
close $fd;
|
||||||
|
|
||||||
|
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
|
||||||
|
unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
|
||||||
|
die_error('404 Not Found', "File or directory for given base does not exist");
|
||||||
|
}
|
||||||
|
$type = $2;
|
||||||
|
$hash = $3;
|
||||||
|
} else {
|
||||||
|
die_error('404 Not Found', "Not enough information to find object");
|
||||||
|
}
|
||||||
|
|
||||||
|
print $cgi->redirect(-uri => href(action=>$type, -full=>1,
|
||||||
|
hash=>$hash, hash_base=>$hash_base,
|
||||||
|
file_name=>$file_name),
|
||||||
|
-status => '302 Found');
|
||||||
|
}
|
||||||
|
|
||||||
sub git_blobdiff {
|
sub git_blobdiff {
|
||||||
my $format = shift || 'html';
|
my $format = shift || 'html';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user