@matheusbsbs / matheus-bagliano / commits / 0368c492d6
Fork 0

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 <u.kleine-koenig@pengutronix.de> Ctags-issue-Reported-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jakub Narebski committed Apr 29, 2011 at 19:51 UTC 0368c492d664775924388b18494eeb4690692ab8
1 file changed +97 -44
gitweb/gitweb.perl
+97 -44
@@ -412,20 +412,23 @@ our %feature = (
412 'override' => 0,
413 'default' => []},
414
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.
419
420 # 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.
423 # You may want to install the HTML::TagCloud Perl module to get
424 # a pretty tag cloud instead of just a list of tags.
425
426 # To enable system wide have in $GITWEB_CONFIG
427 - # $feature{'ctags'}{'default'} = ['path_to_tag_script'];
427 + # $feature{'ctags'}{'default'} = [1];
428 # 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.
432 'ctags' => {
433 'override' => 0,
434 'default' => [0]},
@@ -703,6 +706,7 @@ our @cgi_param_mapping = (
706 snapshot_format => "sf",
707 extra_options => "opt",
708 search_use_regexp => "sr",
709 + ctag => "by_tag",
710 # this must be last entry (for manipulation from JavaScript)
711 javascript => "js"
712 );
@@ -2572,23 +2576,66 @@ sub git_get_project_description {
2576 return $descr;
2577 }
2578
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
2586 sub git_get_project_ctags {
2576 - my $path = shift;
2587 + my $project = shift;
2588 my $ctags = {};
2589
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 + }
2621 }
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;
2639 }
2640
2641 sub git_populate_project_tagcloud {
@@ -2608,31 +2655,41 @@ sub git_populate_project_tagcloud {
2655 my $cloud;
2656 if (eval { require HTML::TagCloud; 1; }) {
2657 $cloud = HTML::TagCloud->new;
2611 - foreach (sort keys %ctags_lc) {
2658 + foreach my $ctag (sort keys %ctags_lc) {
2659 # Pad the title with spaces so that the cloud looks
2660 # less crammed.
2614 - my $title = $ctags_lc{$_}->{topname};
2661 + my $title = esc_html($ctags_lc{$ctag}->{topname});
2662 $title =~ s/ /&nbsp;/g;
2663 $title =~ s/^/&nbsp;/g;
2664 $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});
2667 }
2668 } 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 + }
2677 }
2623 - $cloud;
2678 + return $cloud;
2679 }
2680
2681 sub git_show_project_tagcloud {
2682 my ($cloud, $count) = @_;
2628 - print STDERR ref($cloud)."..\n";
2683 if (ref $cloud eq 'HTML::TagCloud') {
2684 return $cloud->html_and_css($count);
2685 } 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>';
2693 }
2694 }
2695
@@ -4920,13 +4977,8 @@ sub git_project_list_body {
4977 @projects = sort_projects_list(\@projects, $order);
4978
4979 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);
4982 print git_show_project_tagcloud($cloud, 64);
4983 }
4984
@@ -5521,13 +5573,14 @@ sub git_summary {
5573 my $show_ctags = gitweb_check_feature('ctags');
5574 if ($show_ctags) {
5575 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 + }
5584 }
5585
5586 print "</table>\n";