зеркало из https://github.com/microsoft/git.git
Merge branch 'gb/gitweb-avatar'
* gb/gitweb-avatar: gitweb: add empty alt text to avatar img gitweb: picon avatar provider gitweb: gravatar url cache gitweb: (gr)avatar support gitweb: use git_print_authorship_rows in 'tag' view too gitweb: uniform author info for commit and commitdiff gitweb: refactor author name insertion
This commit is contained in:
Коммит
1d4bf0b362
|
@ -28,6 +28,10 @@ img.logo {
|
|||
border-width: 0px;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.page_header {
|
||||
height: 25px;
|
||||
padding: 8px;
|
||||
|
@ -132,11 +136,14 @@ div.list_head {
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.author_date, .author {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.author_date {
|
||||
padding: 8px;
|
||||
border: solid #d9d8d1;
|
||||
border-width: 0px 0px 1px 0px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
a.list {
|
||||
|
|
|
@ -195,6 +195,14 @@ our %known_snapshot_format_aliases = (
|
|||
'x-zip' => undef, '' => undef,
|
||||
);
|
||||
|
||||
# Pixel sizes for icons and avatars. If the default font sizes or lineheights
|
||||
# are changed, it may be appropriate to change these values too via
|
||||
# $GITWEB_CONFIG.
|
||||
our %avatar_size = (
|
||||
'default' => 16,
|
||||
'double' => 32
|
||||
);
|
||||
|
||||
# You define site-wide feature defaults here; override them with
|
||||
# $GITWEB_CONFIG as necessary.
|
||||
our %feature = (
|
||||
|
@ -365,6 +373,27 @@ our %feature = (
|
|||
'sub' => \&feature_patches,
|
||||
'override' => 0,
|
||||
'default' => [16]},
|
||||
|
||||
# Avatar support. When this feature is enabled, views such as
|
||||
# shortlog or commit will display an avatar associated with
|
||||
# the email of the committer(s) and/or author(s).
|
||||
|
||||
# Currently available providers are gravatar and picon.
|
||||
# If an unknown provider is specified, the feature is disabled.
|
||||
|
||||
# Gravatar depends on Digest::MD5.
|
||||
# Picon currently relies on the indiana.edu database.
|
||||
|
||||
# To enable system wide have in $GITWEB_CONFIG
|
||||
# $feature{'avatar'}{'default'} = ['<provider>'];
|
||||
# where <provider> is either gravatar or picon.
|
||||
# To have project specific config enable override in $GITWEB_CONFIG
|
||||
# $feature{'avatar'}{'override'} = 1;
|
||||
# and in project config gitweb.avatar = <provider>;
|
||||
'avatar' => {
|
||||
'sub' => \&feature_avatar,
|
||||
'override' => 0,
|
||||
'default' => ['']},
|
||||
);
|
||||
|
||||
sub gitweb_get_feature {
|
||||
|
@ -433,6 +462,12 @@ sub feature_patches {
|
|||
return ($_[0]);
|
||||
}
|
||||
|
||||
sub feature_avatar {
|
||||
my @val = (git_get_project_config('avatar'));
|
||||
|
||||
return @val ? @val : @_;
|
||||
}
|
||||
|
||||
# checking HEAD file with -e is fragile if the repository was
|
||||
# initialized long time ago (i.e. symlink HEAD) and was pack-ref'ed
|
||||
# and then pruned.
|
||||
|
@ -814,6 +849,19 @@ $git_dir = "$projectroot/$project" if $project;
|
|||
our @snapshot_fmts = gitweb_get_feature('snapshot');
|
||||
@snapshot_fmts = filter_snapshot_fmts(@snapshot_fmts);
|
||||
|
||||
# check that the avatar feature is set to a known provider name,
|
||||
# and for each provider check if the dependencies are satisfied.
|
||||
# if the provider name is invalid or the dependencies are not met,
|
||||
# reset $git_avatar to the empty string.
|
||||
our ($git_avatar) = gitweb_get_feature('avatar');
|
||||
if ($git_avatar eq 'gravatar') {
|
||||
$git_avatar = '' unless (eval { require Digest::MD5; 1; });
|
||||
} elsif ($git_avatar eq 'picon') {
|
||||
# no dependencies
|
||||
} else {
|
||||
$git_avatar = '';
|
||||
}
|
||||
|
||||
# dispatch
|
||||
if (!defined $action) {
|
||||
if (defined $hash) {
|
||||
|
@ -1469,6 +1517,82 @@ sub format_subject_html {
|
|||
}
|
||||
}
|
||||
|
||||
# Rather than recomputing the url for an email multiple times, we cache it
|
||||
# after the first hit. This gives a visible benefit in views where the avatar
|
||||
# for the same email is used repeatedly (e.g. shortlog).
|
||||
# The cache is shared by all avatar engines (currently gravatar only), which
|
||||
# are free to use it as preferred. Since only one avatar engine is used for any
|
||||
# given page, there's no risk for cache conflicts.
|
||||
our %avatar_cache = ();
|
||||
|
||||
# Compute the picon url for a given email, by using the picon search service over at
|
||||
# http://www.cs.indiana.edu/picons/search.html
|
||||
sub picon_url {
|
||||
my $email = lc shift;
|
||||
if (!$avatar_cache{$email}) {
|
||||
my ($user, $domain) = split('@', $email);
|
||||
$avatar_cache{$email} =
|
||||
"http://www.cs.indiana.edu/cgi-pub/kinzler/piconsearch.cgi/" .
|
||||
"$domain/$user/" .
|
||||
"users+domains+unknown/up/single";
|
||||
}
|
||||
return $avatar_cache{$email};
|
||||
}
|
||||
|
||||
# Compute the gravatar url for a given email, if it's not in the cache already.
|
||||
# Gravatar stores only the part of the URL before the size, since that's the
|
||||
# one computationally more expensive. This also allows reuse of the cache for
|
||||
# different sizes (for this particular engine).
|
||||
sub gravatar_url {
|
||||
my $email = lc shift;
|
||||
my $size = shift;
|
||||
$avatar_cache{$email} ||=
|
||||
"http://www.gravatar.com/avatar/" .
|
||||
Digest::MD5::md5_hex($email) . "?s=";
|
||||
return $avatar_cache{$email} . $size;
|
||||
}
|
||||
|
||||
# Insert an avatar for the given $email at the given $size if the feature
|
||||
# is enabled.
|
||||
sub git_get_avatar {
|
||||
my ($email, %opts) = @_;
|
||||
my $pre_white = ($opts{-pad_before} ? " " : "");
|
||||
my $post_white = ($opts{-pad_after} ? " " : "");
|
||||
$opts{-size} ||= 'default';
|
||||
my $size = $avatar_size{$opts{-size}} || $avatar_size{'default'};
|
||||
my $url = "";
|
||||
if ($git_avatar eq 'gravatar') {
|
||||
$url = gravatar_url($email, $size);
|
||||
} elsif ($git_avatar eq 'picon') {
|
||||
$url = picon_url($email);
|
||||
}
|
||||
# Other providers can be added by extending the if chain, defining $url
|
||||
# as needed. If no variant puts something in $url, we assume avatars
|
||||
# are completely disabled/unavailable.
|
||||
if ($url) {
|
||||
return $pre_white .
|
||||
"<img width=\"$size\" " .
|
||||
"class=\"avatar\" " .
|
||||
"src=\"$url\" " .
|
||||
"alt=\"\" " .
|
||||
"/>" . $post_white;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
# format the author name of the given commit with the given tag
|
||||
# the author name is chopped and escaped according to the other
|
||||
# optional parameters (see chop_str).
|
||||
sub format_author_html {
|
||||
my $tag = shift;
|
||||
my $co = shift;
|
||||
my $author = chop_and_escape_str($co->{'author_name'}, @_);
|
||||
return "<$tag class=\"author\">" .
|
||||
git_get_avatar($co->{'author_email'}, -pad_after => 1) .
|
||||
$author . "</$tag>";
|
||||
}
|
||||
|
||||
# format git diff header line, i.e. "diff --(git|combined|cc) ..."
|
||||
sub format_git_diff_header_line {
|
||||
my $line = shift;
|
||||
|
@ -2399,8 +2523,14 @@ sub parse_tag {
|
|||
$tag{'name'} = $1;
|
||||
} elsif ($line =~ m/^tagger (.*) ([0-9]+) (.*)$/) {
|
||||
$tag{'author'} = $1;
|
||||
$tag{'epoch'} = $2;
|
||||
$tag{'tz'} = $3;
|
||||
$tag{'author_epoch'} = $2;
|
||||
$tag{'author_tz'} = $3;
|
||||
if ($tag{'author'} =~ m/^([^<]+) <([^>]*)>/) {
|
||||
$tag{'author_name'} = $1;
|
||||
$tag{'author_email'} = $2;
|
||||
} else {
|
||||
$tag{'author_name'} = $tag{'author'};
|
||||
}
|
||||
} elsif ($line =~ m/--BEGIN/) {
|
||||
push @comment, $line;
|
||||
last;
|
||||
|
@ -3214,21 +3344,54 @@ sub git_print_header_div {
|
|||
"\n</div>\n";
|
||||
}
|
||||
|
||||
sub git_print_authorship {
|
||||
my $co = shift;
|
||||
|
||||
my %ad = parse_date($co->{'author_epoch'}, $co->{'author_tz'});
|
||||
print "<div class=\"author_date\">" .
|
||||
esc_html($co->{'author_name'}) .
|
||||
" [$ad{'rfc2822'}";
|
||||
if ($ad{'hour_local'} < 6) {
|
||||
sub print_local_time {
|
||||
my %date = @_;
|
||||
if ($date{'hour_local'} < 6) {
|
||||
printf(" (<span class=\"atnight\">%02d:%02d</span> %s)",
|
||||
$ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'});
|
||||
$date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'});
|
||||
} else {
|
||||
printf(" (%02d:%02d %s)",
|
||||
$ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'});
|
||||
$date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'});
|
||||
}
|
||||
}
|
||||
|
||||
# Outputs the author name and date in long form
|
||||
sub git_print_authorship {
|
||||
my $co = shift;
|
||||
my %opts = @_;
|
||||
my $tag = $opts{-tag} || 'div';
|
||||
|
||||
my %ad = parse_date($co->{'author_epoch'}, $co->{'author_tz'});
|
||||
print "<$tag class=\"author_date\">" .
|
||||
esc_html($co->{'author_name'}) .
|
||||
" [$ad{'rfc2822'}";
|
||||
print_local_time(%ad) if ($opts{-localtime});
|
||||
print "]" . git_get_avatar($co->{'author_email'}, -pad_before => 1)
|
||||
. "</$tag>\n";
|
||||
}
|
||||
|
||||
# Outputs table rows containing the full author or committer information,
|
||||
# in the format expected for 'commit' view (& similia).
|
||||
# Parameters are a commit hash reference, followed by the list of people
|
||||
# to output information for. If the list is empty it defalts to both
|
||||
# author and committer.
|
||||
sub git_print_authorship_rows {
|
||||
my $co = shift;
|
||||
# too bad we can't use @people = @_ || ('author', 'committer')
|
||||
my @people = @_;
|
||||
@people = ('author', 'committer') unless @people;
|
||||
foreach my $who (@people) {
|
||||
my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"});
|
||||
print "<tr><td>$who</td><td>" . esc_html($co->{$who}) . "</td>" .
|
||||
"<td rowspan=\"2\">" .
|
||||
git_get_avatar($co->{"${who}_email"}, -size => 'double') .
|
||||
"</td></tr>\n" .
|
||||
"<tr>" .
|
||||
"<td></td><td> $wd{'rfc2822'}";
|
||||
print_local_time(%wd);
|
||||
print "</td>" .
|
||||
"</tr>\n";
|
||||
}
|
||||
print "]</div>\n";
|
||||
}
|
||||
|
||||
sub git_print_page_path {
|
||||
|
@ -4142,11 +4305,9 @@ sub git_shortlog_body {
|
|||
print "<tr class=\"light\">\n";
|
||||
}
|
||||
$alternate ^= 1;
|
||||
my $author = chop_and_escape_str($co{'author_name'}, 10);
|
||||
# git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
|
||||
print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
|
||||
"<td><i>" . $author . "</i></td>\n" .
|
||||
"<td>";
|
||||
format_author_html('td', \%co, 10) . "<td>";
|
||||
print format_subject_html($co{'title'}, $co{'title_short'},
|
||||
href(action=>"commit", hash=>$commit), $ref);
|
||||
print "</td>\n" .
|
||||
|
@ -4193,11 +4354,9 @@ sub git_history_body {
|
|||
print "<tr class=\"light\">\n";
|
||||
}
|
||||
$alternate ^= 1;
|
||||
# shortlog uses chop_str($co{'author_name'}, 10)
|
||||
my $author = chop_and_escape_str($co{'author_name'}, 15, 3);
|
||||
print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
|
||||
"<td><i>" . $author . "</i></td>\n" .
|
||||
"<td>";
|
||||
# shortlog: format_author_html('td', \%co, 10)
|
||||
format_author_html('td', \%co, 15, 3) . "<td>";
|
||||
# originally git_history used chop_str($co{'title'}, 50)
|
||||
print format_subject_html($co{'title'}, $co{'title_short'},
|
||||
href(action=>"commit", hash=>$commit), $ref);
|
||||
|
@ -4350,9 +4509,8 @@ sub git_search_grep_body {
|
|||
print "<tr class=\"light\">\n";
|
||||
}
|
||||
$alternate ^= 1;
|
||||
my $author = chop_and_escape_str($co{'author_name'}, 15, 5);
|
||||
print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
|
||||
"<td><i>" . $author . "</i></td>\n" .
|
||||
format_author_html('td', \%co, 15, 5) .
|
||||
"<td>" .
|
||||
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
|
||||
-class => "list subject"},
|
||||
|
@ -4586,11 +4744,7 @@ sub git_tag {
|
|||
$tag{'type'}) . "</td>\n" .
|
||||
"</tr>\n";
|
||||
if (defined($tag{'author'})) {
|
||||
my %ad = parse_date($tag{'epoch'}, $tag{'tz'});
|
||||
print "<tr><td>author</td><td>" . esc_html($tag{'author'}) . "</td></tr>\n";
|
||||
print "<tr><td></td><td>" . $ad{'rfc2822'} .
|
||||
sprintf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}) .
|
||||
"</td></tr>\n";
|
||||
git_print_authorship_rows(\%tag, 'author');
|
||||
}
|
||||
print "</table>\n\n" .
|
||||
"</div>\n";
|
||||
|
@ -5094,9 +5248,9 @@ sub git_log {
|
|||
" | " .
|
||||
$cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") .
|
||||
"<br/>\n" .
|
||||
"</div>\n" .
|
||||
"<i>" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]</i><br/>\n" .
|
||||
"</div>\n";
|
||||
git_print_authorship(\%co, -tag => 'span');
|
||||
print "<br/>\n</div>\n";
|
||||
|
||||
print "<div class=\"log_body\">\n";
|
||||
git_print_log($co{'comment'}, -final_empty_line=> 1);
|
||||
|
@ -5115,8 +5269,6 @@ sub git_commit {
|
|||
$hash ||= $hash_base || "HEAD";
|
||||
my %co = parse_commit($hash)
|
||||
or die_error(404, "Unknown commit object");
|
||||
my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
|
||||
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
|
||||
|
||||
my $parent = $co{'parent'};
|
||||
my $parents = $co{'parents'}; # listref
|
||||
|
@ -5183,22 +5335,7 @@ sub git_commit {
|
|||
}
|
||||
print "<div class=\"title_text\">\n" .
|
||||
"<table class=\"object_header\">\n";
|
||||
print "<tr><td>author</td><td>" . esc_html($co{'author'}) . "</td></tr>\n".
|
||||
"<tr>" .
|
||||
"<td></td><td> $ad{'rfc2822'}";
|
||||
if ($ad{'hour_local'} < 6) {
|
||||
printf(" (<span class=\"atnight\">%02d:%02d</span> %s)",
|
||||
$ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'});
|
||||
} else {
|
||||
printf(" (%02d:%02d %s)",
|
||||
$ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'});
|
||||
}
|
||||
print "</td>" .
|
||||
"</tr>\n";
|
||||
print "<tr><td>committer</td><td>" . esc_html($co{'committer'}) . "</td></tr>\n";
|
||||
print "<tr><td></td><td> $cd{'rfc2822'}" .
|
||||
sprintf(" (%02d:%02d %s)", $cd{'hour_local'}, $cd{'minute_local'}, $cd{'tz_local'}) .
|
||||
"</td></tr>\n";
|
||||
git_print_authorship_rows(\%co);
|
||||
print "<tr><td>commit</td><td class=\"sha1\">$co{'id'}</td></tr>\n";
|
||||
print "<tr>" .
|
||||
"<td>tree</td>" .
|
||||
|
@ -5579,7 +5716,11 @@ sub git_commitdiff {
|
|||
git_header_html(undef, $expires);
|
||||
git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
|
||||
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
|
||||
git_print_authorship(\%co);
|
||||
print "<div class=\"title_text\">\n" .
|
||||
"<table class=\"object_header\">\n";
|
||||
git_print_authorship_rows(\%co);
|
||||
print "</table>".
|
||||
"</div>\n";
|
||||
print "<div class=\"page_body\">\n";
|
||||
if (@{$co{'comment'}} > 1) {
|
||||
print "<div class=\"log\">\n";
|
||||
|
|
|
@ -660,6 +660,7 @@ cat >>gitweb_config.perl <<EOF
|
|||
|
||||
\$feature{'blame'}{'override'} = 1;
|
||||
\$feature{'snapshot'}{'override'} = 1;
|
||||
\$feature{'avatar'}{'override'} = 1;
|
||||
EOF
|
||||
|
||||
test_expect_success \
|
||||
|
@ -671,6 +672,7 @@ test_expect_success \
|
|||
'config override: tree view, features disabled in repo config' \
|
||||
'git config gitweb.blame no &&
|
||||
git config gitweb.snapshot none &&
|
||||
git config gitweb.avatar gravatar &&
|
||||
gitweb_run "p=.git;a=tree"'
|
||||
test_debug 'cat gitweb.log'
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче