@matheusbsbs / matheus-bagliano / commits / aed93de428
Fork 0

gitweb: Support for tag clouds

The "Content tags" (nothing to do with usual Git tags!) are free-form strings that are attached to random projects and displayed in the well-known Web2.0-ish tag cloud above project list. The feature will make use of HTML::TagCloud if available, but will still display (less pretty) list of tags in case the module is not installed. The tagging itself is not done by gitweb - user-provided external helper CGI needs to be provided; one example is the tagproj.cgi of Girocco. This functionality might get integrated to gitweb in the future. The tags are stored one-per-file in ctags/ subdirectory. The reason they are not stored in the project config file is that you usually want to give anyone (even CGI scripts) permission to create new tags and they are non-essential information, and thus you would make the ctags/ subdirectory world-writable. Signed-off-by: Petr Baudis <petr.baudis@novartis.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>

Petr Baudis committed Oct 2, 2008 at 17:13 UTC aed93de428d7d12ee23d84d27265af1e37eb348f
1 file changed +109
gitweb/gitweb.perl
+109
@@ -282,6 +282,24 @@ our %feature = (
282 'forks' => {
283 'override' => 0,
284 'default' => [0]},
285 +
286 + # Allow gitweb scan project content tags described in ctags/
287 + # of project repository, and display the popular Web 2.0-ish
288 + # "tag cloud" near the project list. Note that this is something
289 + # COMPLETELY different from the normal Git tags.
290 +
291 + # gitweb by itself can show existing tags, but it does not handle
292 + # tagging itself; you need an external application for that.
293 + # For an example script, check Girocco's cgi/tagproj.cgi.
294 + # You may want to install the HTML::TagCloud Perl module to get
295 + # a pretty tag cloud instead of just a list of tags.
296 +
297 + # To enable system wide have in $GITWEB_CONFIG
298 + # $feature{'ctags'}{'default'} = ['path_to_tag_script'];
299 + # Project specific override is not supported.
300 + 'ctags' => {
301 + 'override' => 0,
302 + 'default' => [0]},
303 );
304
305 sub gitweb_check_feature {
@@ -1762,6 +1780,67 @@ sub git_get_project_description {
1780 return $descr;
1781 }
1782
1783 +sub git_get_project_ctags {
1784 + my $path = shift;
1785 + my $ctags = {};
1786 +
1787 + $git_dir = "$projectroot/$path";
1788 + foreach (<$git_dir/ctags/*>) {
1789 + open CT, $_ or next;
1790 + my $val = <CT>;
1791 + chomp $val;
1792 + close CT;
1793 + my $ctag = $_; $ctag =~ s#.*/##;
1794 + $ctags->{$ctag} = $val;
1795 + }
1796 + $ctags;
1797 +}
1798 +
1799 +sub git_populate_project_tagcloud {
1800 + my $ctags = shift;
1801 +
1802 + # First, merge different-cased tags; tags vote on casing
1803 + my %ctags_lc;
1804 + foreach (keys %$ctags) {
1805 + $ctags_lc{lc $_}->{count} += $ctags->{$_};
1806 + if (not $ctags_lc{lc $_}->{topcount}
1807 + or $ctags_lc{lc $_}->{topcount} < $ctags->{$_}) {
1808 + $ctags_lc{lc $_}->{topcount} = $ctags->{$_};
1809 + $ctags_lc{lc $_}->{topname} = $_;
1810 + }
1811 + }
1812 +
1813 + my $cloud;
1814 + if (eval { require HTML::TagCloud; 1; }) {
1815 + $cloud = HTML::TagCloud->new;
1816 + foreach (sort keys %ctags_lc) {
1817 + # Pad the title with spaces so that the cloud looks
1818 + # less crammed.
1819 + my $title = $ctags_lc{$_}->{topname};
1820 + $title =~ s/ /&nbsp;/g;
1821 + $title =~ s/^/&nbsp;/g;
1822 + $title =~ s/$/&nbsp;/g;
1823 + $cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
1824 + }
1825 + } else {
1826 + $cloud = \%ctags_lc;
1827 + }
1828 + $cloud;
1829 +}
1830 +
1831 +sub git_show_project_tagcloud {
1832 + my ($cloud, $count) = @_;
1833 + print STDERR ref($cloud)."..\n";
1834 + if (ref $cloud eq 'HTML::TagCloud') {
1835 + return $cloud->html_and_css($count);
1836 + } else {
1837 + my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
1838 + return '<p align="center">' . join (', ', map {
1839 + "<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
1840 + } splice(@tags, 0, $count)) . '</p>';
1841 + }
1842 +}
1843 +
1844 sub git_get_project_url_list {
1845 my $path = shift;
1846
@@ -3580,6 +3659,7 @@ sub fill_project_list_info {
3659 my ($projlist, $check_forks) = @_;
3660 my @projects;
3661
3662 + my $show_ctags = gitweb_check_feature('ctags');
3663 PROJECT:
3664 foreach my $pr (@$projlist) {
3665 my (@activity) = git_get_last_activity($pr->{'path'});
@@ -3606,6 +3686,7 @@ sub fill_project_list_info {
3686 $pr->{'forks'} = 0;
3687 }
3688 }
3689 + $show_ctags and $pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
3690 push @projects, $pr;
3691 }
3692
@@ -3652,6 +3733,18 @@ sub git_project_list_body {
3733 $from = 0 unless defined $from;
3734 $to = $#projects if (!defined $to || $#projects < $to);
3735
3736 + my $show_ctags = gitweb_check_feature('ctags');
3737 + if ($show_ctags) {
3738 + my %ctags;
3739 + foreach my $p (@projects) {
3740 + foreach my $ct (keys %{$p->{'ctags'}}) {
3741 + $ctags{$ct} += $p->{'ctags'}->{$ct};
3742 + }
3743 + }
3744 + my $cloud = git_populate_project_tagcloud(\%ctags);
3745 + print git_show_project_tagcloud($cloud, 64);
3746 + }
3747 +
3748 print "<table class=\"project_list\">\n";
3749 unless ($no_header) {
3750 print "<tr>\n";
@@ -3670,8 +3763,10 @@ sub git_project_list_body {
3763 "</tr>\n";
3764 }
3765 my $alternate = 1;
3766 + my $tagfilter = $cgi->param('by_tag');
3767 for (my $i = $from; $i <= $to; $i++) {
3768 my $pr = $projects[$i];
3769 + next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
3770 if ($alternate) {
3771 print "<tr class=\"dark\">\n";
3772 } else {
@@ -4093,6 +4188,20 @@ sub git_summary {
4188 print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
4189 $url_tag = "";
4190 }
4191 +
4192 + # Tag cloud
4193 + my $show_ctags = (gitweb_check_feature('ctags'))[0];
4194 + if ($show_ctags) {
4195 + my $ctags = git_get_project_ctags($project);
4196 + my $cloud = git_populate_project_tagcloud($ctags);
4197 + print "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
4198 + print "</td>\n<td>" unless %$ctags;
4199 + print "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
4200 + print "</td>\n<td>" if %$ctags;
4201 + print git_show_project_tagcloud($cloud, 48);
4202 + print "</td></tr>";
4203 + }
4204 +
4205 print "</table>\n";
4206
4207 if (-s "$projectroot/$project/README.html") {