Skip to content

Commit 0368c49

Browse files
jnarebgitster
authored andcommitted
gitweb: Change the way "content tags" ('ctags') are handled
The major change is removing the ability to edit content tags (ctags) in a web browser. The interface was created by gitweb, while actual editing of tags was to be done by external script; the API was not defined, and neither was provided example implementation. Such split is also a bit fragile - interface and implementation have to be kept in sync. Gitweb provided only ability to add tags; you could not edit tags nor delete them. Format of ctags is now described in the comment above git_get_project_ctags subroutine. Gitweb now is more robust with respect to original ctags format; it also accepts two new formats: $GIT_DIR/ctags file, with one content tag per line, and multi-value `gitweb.ctag' config variable. Gathering all ctags of all project is now put in git_gather_all_ctags subroutine, making git_project_list_body more clear. git_populate_project_tagcloud subroutine now generates data used for tag cloud, including generation of ctag link, also in the case HTML::TagCloud module is unavailable. Links are now generated using href() subroutine - this is more robust, as ctags might contain '?', ';' and '=' special characters that need to be escaped in query param. Shown tags are HTML-escaped. The generation of tag cloud in git_show_project_tagcloud in the case when HTML::TagCloud is not available is now changed slightly. The 'content tags' field on project summary page is made more in line with other fields in "projects_list" table. Because one cannot now add new tags from web interface, this field is no longer displayed when there are no content tags for given project. Ctags-issue-Reported-by: Uwe Kleine-König <[email protected]> Ctags-issue-Reported-by: Jonathan Nieder <[email protected]> Signed-off-by: Jakub Narebski <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 12b1443 commit 0368c49

File tree

1 file changed

+97
-44
lines changed

1 file changed

+97
-44
lines changed

gitweb/gitweb.perl

Lines changed: 97 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -412,20 +412,23 @@ sub evaluate_uri {
412412
'override' => 0,
413413
'default' => []},
414414

415-
# Allow gitweb scan project content tags described in ctags/
416-
# of project repository, and display the popular Web 2.0-ish
417-
# "tag cloud" near the project list. Note that this is something
418-
# COMPLETELY different from the normal Git tags.
415+
# Allow gitweb scan project content tags of project repository,
416+
# and display the popular Web 2.0-ish "tag cloud" near the projects
417+
# list. Note that this is something COMPLETELY different from the
418+
# normal Git tags.
419419

420420
# gitweb by itself can show existing tags, but it does not handle
421-
# tagging itself; you need an external application for that.
422-
# For an example script, check Girocco's cgi/tagproj.cgi.
421+
# tagging itself; you need to do it externally, outside gitweb.
422+
# The format is described in git_get_project_ctags() subroutine.
423423
# You may want to install the HTML::TagCloud Perl module to get
424424
# a pretty tag cloud instead of just a list of tags.
425425

426426
# To enable system wide have in $GITWEB_CONFIG
427-
# $feature{'ctags'}{'default'} = ['path_to_tag_script'];
427+
# $feature{'ctags'}{'default'} = [1];
428428
# Project specific override is not supported.
429+
430+
# In the future whether ctags editing is enabled might depend
431+
# on the value, but using 1 should always mean no editing of ctags.
429432
'ctags' => {
430433
'override' => 0,
431434
'default' => [0]},
@@ -703,6 +706,7 @@ sub check_loadavg {
703706
snapshot_format => "sf",
704707
extra_options => "opt",
705708
search_use_regexp => "sr",
709+
ctag => "by_tag",
706710
# this must be last entry (for manipulation from JavaScript)
707711
javascript => "js"
708712
);
@@ -2572,23 +2576,66 @@ sub git_get_project_description {
25722576
return $descr;
25732577
}
25742578

2579+
# supported formats:
2580+
# * $GIT_DIR/ctags/<tagname> file (in 'ctags' subdirectory)
2581+
# - if its contents is a number, use it as tag weight,
2582+
# - otherwise add a tag with weight 1
2583+
# * $GIT_DIR/ctags file, each line is a tag (with weight 1)
2584+
# the same value multiple times increases tag weight
2585+
# * `gitweb.ctag' multi-valued repo config variable
25752586
sub git_get_project_ctags {
2576-
my $path = shift;
2587+
my $project = shift;
25772588
my $ctags = {};
25782589

2579-
$git_dir = "$projectroot/$path";
2580-
opendir my $dh, "$git_dir/ctags"
2581-
or return $ctags;
2582-
foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) {
2583-
open my $ct, '<', $_ or next;
2584-
my $val = <$ct>;
2585-
chomp $val;
2586-
close $ct;
2587-
my $ctag = $_; $ctag =~ s#.*/##;
2588-
$ctags->{$ctag} = $val;
2590+
$git_dir = "$projectroot/$project";
2591+
if (opendir my $dh, "$git_dir/ctags") {
2592+
my @files = grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh);
2593+
foreach my $tagfile (@files) {
2594+
open my $ct, '<', $tagfile
2595+
or next;
2596+
my $val = <$ct>;
2597+
chomp $val if $val;
2598+
close $ct;
2599+
2600+
(my $ctag = $tagfile) =~ s#.*/##;
2601+
if ($val =~ /\d+/) {
2602+
$ctags->{$ctag} = $val;
2603+
} else {
2604+
$ctags->{$ctag} = 1;
2605+
}
2606+
}
2607+
closedir $dh;
2608+
2609+
} elsif (open my $fh, '<', "$git_dir/ctags") {
2610+
while (my $line = <$fh>) {
2611+
chomp $line;
2612+
$ctags->{$line}++ if $line;
2613+
}
2614+
close $fh;
2615+
2616+
} else {
2617+
my $taglist = config_to_multi(git_get_project_config('ctag'));
2618+
foreach my $tag (@$taglist) {
2619+
$ctags->{$tag}++;
2620+
}
25892621
}
2590-
closedir $dh;
2591-
$ctags;
2622+
2623+
return $ctags;
2624+
}
2625+
2626+
# return hash, where keys are content tags ('ctags'),
2627+
# and values are sum of weights of given tag in every project
2628+
sub git_gather_all_ctags {
2629+
my $projects = shift;
2630+
my $ctags = {};
2631+
2632+
foreach my $p (@$projects) {
2633+
foreach my $ct (keys %{$p->{'ctags'}}) {
2634+
$ctags->{$ct} += $p->{'ctags'}->{$ct};
2635+
}
2636+
}
2637+
2638+
return $ctags;
25922639
}
25932640

25942641
sub git_populate_project_tagcloud {
@@ -2608,31 +2655,41 @@ sub git_populate_project_tagcloud {
26082655
my $cloud;
26092656
if (eval { require HTML::TagCloud; 1; }) {
26102657
$cloud = HTML::TagCloud->new;
2611-
foreach (sort keys %ctags_lc) {
2658+
foreach my $ctag (sort keys %ctags_lc) {
26122659
# Pad the title with spaces so that the cloud looks
26132660
# less crammed.
2614-
my $title = $ctags_lc{$_}->{topname};
2661+
my $title = esc_html($ctags_lc{$ctag}->{topname});
26152662
$title =~ s/ /&nbsp;/g;
26162663
$title =~ s/^/&nbsp;/g;
26172664
$title =~ s/$/&nbsp;/g;
2618-
$cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
2665+
$cloud->add($title, href(project=>undef, ctag=>$ctag),
2666+
$ctags_lc{$ctag}->{count});
26192667
}
26202668
} else {
2621-
$cloud = \%ctags_lc;
2669+
$cloud = {};
2670+
foreach my $ctag (keys %ctags_lc) {
2671+
my $title = $ctags_lc{$ctag}->{topname};
2672+
$cloud->{$ctag}{count} = $ctags_lc{$ctag}->{count};
2673+
$cloud->{$ctag}{ctag} =
2674+
$cgi->a({-href=>href(project=>undef, ctag=>$ctag)},
2675+
esc_html($title, -nbsp=>1));
2676+
}
26222677
}
2623-
$cloud;
2678+
return $cloud;
26242679
}
26252680

26262681
sub git_show_project_tagcloud {
26272682
my ($cloud, $count) = @_;
2628-
print STDERR ref($cloud)."..\n";
26292683
if (ref $cloud eq 'HTML::TagCloud') {
26302684
return $cloud->html_and_css($count);
26312685
} else {
2632-
my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
2633-
return '<p align="center">' . join (', ', map {
2634-
$cgi->a({-href=>"$home_link?by_tag=$_"}, $cloud->{$_}->{topname})
2635-
} splice(@tags, 0, $count)) . '</p>';
2686+
my @tags = sort { $cloud->{$a}->{'count'} <=> $cloud->{$b}->{'count'} } keys %$cloud;
2687+
return
2688+
'<div id="htmltagcloud"'.($project ? '' : ' align="center"').'>' .
2689+
join (', ', map {
2690+
$cloud->{$_}->{'ctag'}
2691+
} splice(@tags, 0, $count)) .
2692+
'</div>';
26362693
}
26372694
}
26382695

@@ -4920,13 +4977,8 @@ sub git_project_list_body {
49204977
@projects = sort_projects_list(\@projects, $order);
49214978

49224979
if ($show_ctags) {
4923-
my %ctags;
4924-
foreach my $p (@projects) {
4925-
foreach my $ct (keys %{$p->{'ctags'}}) {
4926-
$ctags{$ct} += $p->{'ctags'}->{$ct};
4927-
}
4928-
}
4929-
my $cloud = git_populate_project_tagcloud(\%ctags);
4980+
my $ctags = git_gather_all_ctags(\@projects);
4981+
my $cloud = git_populate_project_tagcloud($ctags);
49304982
print git_show_project_tagcloud($cloud, 64);
49314983
}
49324984

@@ -5521,13 +5573,14 @@ sub git_summary {
55215573
my $show_ctags = gitweb_check_feature('ctags');
55225574
if ($show_ctags) {
55235575
my $ctags = git_get_project_ctags($project);
5524-
my $cloud = git_populate_project_tagcloud($ctags);
5525-
print "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
5526-
print "</td>\n<td>" unless %$ctags;
5527-
print "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
5528-
print "</td>\n<td>" if %$ctags;
5529-
print git_show_project_tagcloud($cloud, 48);
5530-
print "</td></tr>";
5576+
if (%$ctags) {
5577+
# without ability to add tags, don't show if there are none
5578+
my $cloud = git_populate_project_tagcloud($ctags);
5579+
print "<tr id=\"metadata_ctags\">" .
5580+
"<td>content tags</td>" .
5581+
"<td>".git_show_project_tagcloud($cloud, 48)."</td>" .
5582+
"</tr>\n";
5583+
}
55315584
}
55325585

55335586
print "</table>\n";

0 commit comments

Comments
 (0)