Skip to content

Commit aed93de

Browse files
Petr Baudisspearce
authored andcommitted
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 <[email protected]> Signed-off-by: Shawn O. Pearce <[email protected]>
1 parent 52e8370 commit aed93de

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

gitweb/gitweb.perl

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,24 @@ BEGIN
282282
'forks' => {
283283
'override' => 0,
284284
'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]},
285303
);
286304

287305
sub gitweb_check_feature {
@@ -1762,6 +1780,67 @@ sub git_get_project_description {
17621780
return $descr;
17631781
}
17641782

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+
17651844
sub git_get_project_url_list {
17661845
my $path = shift;
17671846

@@ -3580,6 +3659,7 @@ sub fill_project_list_info {
35803659
my ($projlist, $check_forks) = @_;
35813660
my @projects;
35823661

3662+
my $show_ctags = gitweb_check_feature('ctags');
35833663
PROJECT:
35843664
foreach my $pr (@$projlist) {
35853665
my (@activity) = git_get_last_activity($pr->{'path'});
@@ -3606,6 +3686,7 @@ sub fill_project_list_info {
36063686
$pr->{'forks'} = 0;
36073687
}
36083688
}
3689+
$show_ctags and $pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
36093690
push @projects, $pr;
36103691
}
36113692

@@ -3652,6 +3733,18 @@ sub git_project_list_body {
36523733
$from = 0 unless defined $from;
36533734
$to = $#projects if (!defined $to || $#projects < $to);
36543735

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+
36553748
print "<table class=\"project_list\">\n";
36563749
unless ($no_header) {
36573750
print "<tr>\n";
@@ -3670,8 +3763,10 @@ sub git_project_list_body {
36703763
"</tr>\n";
36713764
}
36723765
my $alternate = 1;
3766+
my $tagfilter = $cgi->param('by_tag');
36733767
for (my $i = $from; $i <= $to; $i++) {
36743768
my $pr = $projects[$i];
3769+
next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
36753770
if ($alternate) {
36763771
print "<tr class=\"dark\">\n";
36773772
} else {
@@ -4093,6 +4188,20 @@ sub git_summary {
40934188
print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
40944189
$url_tag = "";
40954190
}
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+
40964205
print "</table>\n";
40974206

40984207
if (-s "$projectroot/$project/README.html") {

0 commit comments

Comments
 (0)