From 1c49a4e1f324dcaa000ce92ed44d0e5b9eb16843 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:48 +0200 Subject: gitweb: refactor author name insertion Collect all author display code in appropriate functions, making it easier to extend these functions on the CGI side. We also move some of the presentation code from hard-coded HTML to CSS, for easier customization. A side effect of the refactoring is that now localtime is always displayed with the 'at night' warning. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 5 ++- gitweb/gitweb.perl | 93 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 59 insertions(+), 39 deletions(-) (limited to 'gitweb') diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index a01eac814e..68b22ffece 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -132,11 +132,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 { diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 1e7e2d8387..7fd53f68de 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1469,6 +1469,16 @@ sub format_subject_html { } } +# 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\">" . $author . ""; +} + # format git diff header line, i.e. "diff --(git|combined|cc) ..." sub format_git_diff_header_line { my $line = shift; @@ -3214,21 +3224,50 @@ sub git_print_header_div { "\n\n"; } +sub print_local_time { + my %date = @_; + if ($date{'hour_local'} < 6) { + printf(" (%02d:%02d %s)", + $date{'hour_local'}, $date{'minute_local'}, $date{'tz_local'}); + } else { + printf(" (%02d:%02d %s)", + $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 "
" . + print "<$tag class=\"author_date\">" . esc_html($co->{'author_name'}) . " [$ad{'rfc2822'}"; - if ($ad{'hour_local'} < 6) { - printf(" (%02d:%02d %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_local_time(%ad) if ($opts{-localtime}); + print "]\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 "$who" . esc_html($co->{$who}) . "\n". + "" . + " $wd{'rfc2822'}"; + print_local_time(%wd); + print "" . + "\n"; } - print "]
\n"; } sub git_print_page_path { @@ -4142,11 +4181,9 @@ sub git_shortlog_body { print "\n"; } $alternate ^= 1; - my $author = chop_and_escape_str($co{'author_name'}, 10); # git_summary() used print "$co{'age_string'}\n" . print "$co{'age_string_date'}\n" . - "" . $author . "\n" . - ""; + format_author_html('td', \%co, 10) . ""; print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); print "\n" . @@ -4193,11 +4230,9 @@ sub git_history_body { print "\n"; } $alternate ^= 1; - # shortlog uses chop_str($co{'author_name'}, 10) - my $author = chop_and_escape_str($co{'author_name'}, 15, 3); print "$co{'age_string_date'}\n" . - "" . $author . "\n" . - ""; + # shortlog: format_author_html('td', \%co, 10) + format_author_html('td', \%co, 15, 3) . ""; # 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 +4385,8 @@ sub git_search_grep_body { print "\n"; } $alternate ^= 1; - my $author = chop_and_escape_str($co{'author_name'}, 15, 5); print "$co{'age_string_date'}\n" . - "" . $author . "\n" . + format_author_html('td', \%co, 15, 5) . "" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, @@ -5094,9 +5128,9 @@ sub git_log { " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . "
\n" . - "\n" . - "" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]
\n" . "\n"; + git_print_authorship(\%co, -tag => 'span'); + print "
\n\n"; print "
\n"; git_print_log($co{'comment'}, -final_empty_line=> 1); @@ -5115,8 +5149,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 +5215,7 @@ sub git_commit { } print "
\n" . "\n"; - print "\n". - "" . - "" . - "\n"; - print "\n"; - print "\n"; + git_print_authorship_rows(\%co); print "\n"; print "" . "" . @@ -5579,7 +5596,7 @@ 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); + git_print_authorship(\%co, -localtime => 1); print "
\n"; if (@{$co{'comment'}} > 1) { print "
\n"; -- cgit v1.2.3 From f88bafadd9b2562a0cd2500c5a9669d3741243b5 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:49 +0200 Subject: gitweb: uniform author info for commit and commitdiff Switch from 'log'-like layout A U Thor [date time] to 'commit'-like layout author A U Thor date time committer C O Mitter committer date time Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gitweb') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7fd53f68de..9a8d775ad8 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5596,7 +5596,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, -localtime => 1); + print "
\n" . + "
author" . esc_html($co{'author'}) . "
$ad{'rfc2822'}"; - if ($ad{'hour_local'} < 6) { - printf(" (%02d:%02d %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 "
committer" . esc_html($co{'committer'}) . "
$cd{'rfc2822'}" . - sprintf(" (%02d:%02d %s)", $cd{'hour_local'}, $cd{'minute_local'}, $cd{'tz_local'}) . - "
commit$co{'id'}
tree
\n"; + git_print_authorship_rows(\%co); + print "
". + "
\n"; print "
\n"; if (@{$co{'comment'}} > 1) { print "
\n"; -- cgit v1.2.3 From ba9247339dfbd2c2671603e012d011b4b474fa4b Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:50 +0200 Subject: gitweb: use git_print_authorship_rows in 'tag' view too parse_tag must be adapted to use the hash keys expected by git_print_authorship_rows. This is not a problem since git_tag is the only user of this sub. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'gitweb') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9a8d775ad8..a393ac6f29 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2409,8 +2409,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; @@ -4620,11 +4626,7 @@ sub git_tag { $tag{'type'}) . "\n" . "\n"; if (defined($tag{'author'})) { - my %ad = parse_date($tag{'epoch'}, $tag{'tz'}); - print "author" . esc_html($tag{'author'}) . "\n"; - print "" . $ad{'rfc2822'} . - sprintf(" (%02d:%02d %s)", $ad{'hour_local'}, $ad{'minute_local'}, $ad{'tz_local'}) . - "\n"; + git_print_authorship_rows(\%tag, 'author'); } print "\n\n" . "
\n"; -- cgit v1.2.3 From e9fdd74e5374dd1efe1577057d14a2836b4cae78 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:51 +0200 Subject: gitweb: (gr)avatar support Introduce avatar support: the feature adds the appropriate img tag next to author and committer in commit(diff), history, shortlog, log and tag views. Multiple avatar providers are possible, but only gravatar is implemented at the moment. Gravatar support depends on Digest::MD5, which is a core package since Perl 5.8. If gravatars are activated but Digest::MD5 cannot be found, the feature will be automatically disabled. No avatar provider is selected by default, except in the t9500 test. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 4 +++ gitweb/gitweb.perl | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 3 deletions(-) (limited to 'gitweb') diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 68b22ffece..d05bc37646 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -28,6 +28,10 @@ img.logo { border-width: 0px; } +img.avatar { + vertical-align: middle; +} + div.page_header { height: 25px; padding: 8px; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a393ac6f29..92695a3ae8 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -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,24 @@ 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 only the gravatar provider is available, and it + # depends on Digest::MD5. If an unknown provider is specified, + # the feature is disabled. + + # To enable system wide have in $GITWEB_CONFIG + # $feature{'avatar'}{'default'} = ['gravatar']; + # To have project specific config enable override in $GITWEB_CONFIG + # $feature{'avatar'}{'override'} = 1; + # and in project config gitweb.avatar = gravatar; + 'avatar' => { + 'sub' => \&feature_avatar, + 'override' => 0, + 'default' => ['']}, ); sub gitweb_get_feature { @@ -433,6 +459,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 +846,17 @@ $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; }); +} else { + $git_avatar = ''; +} + # dispatch if (!defined $action) { if (defined $hash) { @@ -1469,6 +1512,34 @@ sub format_subject_html { } } +# 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 = "http://www.gravatar.com/avatar/" . + Digest::MD5::md5_hex(lc $email) . "?s=$size"; + } + # Currently only gravatars are supported, but other forms such as + # picons can be added by putting an else up here and defining $url + # as needed. If no variant puts something in $url, we assume avatars + # are completely disabled/unavailable. + if ($url) { + return $pre_white . + "" . $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). @@ -1476,7 +1547,9 @@ sub format_author_html { my $tag = shift; my $co = shift; my $author = chop_and_escape_str($co->{'author_name'}, @_); - return "<$tag class=\"author\">" . $author . ""; + return "<$tag class=\"author\">" . + git_get_avatar($co->{'author_email'}, -pad_after => 1) . + $author . ""; } # format git diff header line, i.e. "diff --(git|combined|cc) ..." @@ -3252,7 +3325,8 @@ sub git_print_authorship { esc_html($co->{'author_name'}) . " [$ad{'rfc2822'}"; print_local_time(%ad) if ($opts{-localtime}); - print "]\n"; + print "]" . git_get_avatar($co->{'author_email'}, -pad_before => 1) + . "\n"; } # Outputs table rows containing the full author or committer information, @@ -3267,7 +3341,10 @@ sub git_print_authorship_rows { @people = ('author', 'committer') unless @people; foreach my $who (@people) { my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"}); - print "$who" . esc_html($co->{$who}) . "\n". + print "$who" . esc_html($co->{$who}) . "" . + "" . + git_get_avatar($co->{"${who}_email"}, -size => 'double') . + "\n" . "" . " $wd{'rfc2822'}"; print_local_time(%wd); -- cgit v1.2.3 From 5a371b7bbbffeddfb356b327995a95cf7bae71d5 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:52 +0200 Subject: gitweb: gravatar url cache Views which contain many occurrences of the same email address (e.g. shortlog view) benefit from not having to recalculate the MD5 of the email address every time. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'gitweb') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 92695a3ae8..4d7e4ff7a0 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1512,6 +1512,27 @@ 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 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 { @@ -1522,8 +1543,7 @@ sub git_get_avatar { my $size = $avatar_size{$opts{-size}} || $avatar_size{'default'}; my $url = ""; if ($git_avatar eq 'gravatar') { - $url = "http://www.gravatar.com/avatar/" . - Digest::MD5::md5_hex(lc $email) . "?s=$size"; + $url = gravatar_url($email, $size); } # Currently only gravatars are supported, but other forms such as # picons can be added by putting an else up here and defining $url -- cgit v1.2.3 From 679a1a1d420616be1647bdf8b2e93f1f86c7bdae Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:53 +0200 Subject: gitweb: picon avatar provider Simple implementation of picon that only relies on the indiana.edu database. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'gitweb') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 4d7e4ff7a0..862ea99f8a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -378,15 +378,18 @@ our %feature = ( # shortlog or commit will display an avatar associated with # the email of the committer(s) and/or author(s). - # Currently only the gravatar provider is available, and it - # depends on Digest::MD5. If an unknown provider is specified, - # the feature is disabled. + # 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'} = ['gravatar']; + # $feature{'avatar'}{'default'} = ['']; + # where 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 = gravatar; + # and in project config gitweb.avatar = ; 'avatar' => { 'sub' => \&feature_avatar, 'override' => 0, @@ -853,6 +856,8 @@ our @snapshot_fmts = gitweb_get_feature('snapshot'); 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 = ''; } @@ -1520,6 +1525,20 @@ sub format_subject_html { # 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 @@ -1544,9 +1563,10 @@ sub git_get_avatar { my $url = ""; if ($git_avatar eq 'gravatar') { $url = gravatar_url($email, $size); + } elsif ($git_avatar eq 'picon') { + $url = picon_url($email); } - # Currently only gravatars are supported, but other forms such as - # picons can be added by putting an else up here and defining $url + # 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) { -- cgit v1.2.3 From 7d25ef41c84850ec1405400efc95d78fa6523efc Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Tue, 30 Jun 2009 00:00:54 +0200 Subject: gitweb: add empty alt text to avatar img The empty alt text optimizes screen estate in text-only browsers. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 1 + 1 file changed, 1 insertion(+) (limited to 'gitweb') diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 862ea99f8a..6a1b5b5b49 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1574,6 +1574,7 @@ sub git_get_avatar { "" . $post_white; } else { return ""; -- cgit v1.2.3