threads / patch / 15762

patchRe: [PATCH] gitweb: Identify all summary metadata table rows

Subject: Re: [PATCH] gitweb: Identify all summary metadata table rows

## tl;dr

6 messages between Oct 2, 2008 and Oct 3, 2008. Diffs are folded; open one to read it.

replies: 5people: 3as markdown or json

Petr Baudis· Oct 2, 2008, 14:25 UTC · lore

[PATCH] gitweb: Identify all summary metadata table rows

In the metadata table of the summary page, all rows have their id (or class in case of URL) set now. This for example lets sites easily disable fields they do not want to show in their custom stylesheet (e.g. they are overly technical or irrelevant for the site).

Many of my other patches depend on this, so I would appreciate to hear as soon as possible if someone has an issue with this patch.

Signed-off-by: Petr Baudis <petr.baudis@novartis.com>
---
 gitweb/gitweb.perl |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
Show changes to gitweb/gitweb.perl +4 −4
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index da474d0..bd8124a 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4070,10 +4070,10 @@ sub git_summary {
 
 	print "<div class=\"title\">&nbsp;</div>\n";
 	print "<table class=\"projects_list\">\n" .
-	      "<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
-	      "<tr><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
+	      "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
+	      "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
 	if (defined $cd{'rfc2822'}) {
-		print "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
+		print "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
 	}
 
 	# use per project git URL list in $projectroot/$project/cloneurl
@@ -4083,7 +4083,7 @@ sub git_summary {
 	@url_list = map { "$_/$project" } @git_base_url_list unless @url_list;
 	foreach my $git_url (@url_list) {
 		next unless $git_url;
-		print "<tr><td>$url_tag</td><td>$git_url</td></tr>\n";
+		print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
 		$url_tag = "";
 	}
 	print "</table>\n";
-- 
tg: (c427559..) t/summary/css-metadata (depends on: vanilla/master)
Petr Baudis· Oct 2, 2008, 15:13 UTC · re: Petr Baudis · lore

[PATCH] 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>
---
 gitweb/gitweb.perl |  109 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 109 insertions(+), 0 deletions(-)
Show changes to gitweb/gitweb.perl +109 −0
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index bd8124a..5ba094e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -275,6 +275,24 @@ our %feature = (
 	'forks' => {
 		'override' => 0,
 		'default' => [0]},
+
+	# Allow gitweb scan project content tags described in ctags/
+	# of project repository, and display the popular Web 2.0-ish
+	# "tag cloud" near the project list. Note that this is something
+	# COMPLETELY different from the normal Git tags.
+
+	# gitweb by itself can show existing tags, but it does not handle
+	# tagging itself; you need an external application for that.
+	# For an example script, check Girocco's cgi/tagproj.cgi.
+	# You may want to install the HTML::TagCloud Perl module to get
+	# a pretty tag cloud instead of just a list of tags.
+
+	# To enable system wide have in $GITWEB_CONFIG
+	# $feature{'ctags'}{'default'} = ['path_to_tag_script'];
+	# Project specific override is not supported.
+	'ctags' => {
+		'override' => 0,
+		'default' => [0]},
 );
 
 sub gitweb_check_feature {
@@ -1755,6 +1773,67 @@ sub git_get_project_description {
 	return $descr;
 }
 
+sub git_get_project_ctags {
+	my $path = shift;
+	my $ctags = {};
+
+	$git_dir = "$projectroot/$path";
+	foreach (<$git_dir/ctags/*>) {
+		open CT, $_ or next;
+		my $val = <CT>;
+		chomp $val;
+		close CT;
+		my $ctag = $_; $ctag =~ s#.*/##;
+		$ctags->{$ctag} = $val;
+	}
+	$ctags;
+}
+
+sub git_populate_project_tagcloud {
+	my $ctags = shift;
+
+	# First, merge different-cased tags; tags vote on casing
+	my %ctags_lc;
+	foreach (keys %$ctags) {
+		$ctags_lc{lc $_}->{count} += $ctags->{$_};
+		if (not $ctags_lc{lc $_}->{topcount}
+		    or $ctags_lc{lc $_}->{topcount} < $ctags->{$_}) {
+			$ctags_lc{lc $_}->{topcount} = $ctags->{$_};
+			$ctags_lc{lc $_}->{topname} = $_;
+		}
+	}
+
+	my $cloud;
+	if (eval { require HTML::TagCloud; 1; }) {
+		$cloud = HTML::TagCloud->new;
+		foreach (sort keys %ctags_lc) {
+			# Pad the title with spaces so that the cloud looks
+			# less crammed.
+			my $title = $ctags_lc{$_}->{topname};
+			$title =~ s/ /&nbsp;/g;
+			$title =~ s/^/&nbsp;/g;
+			$title =~ s/$/&nbsp;/g;
+			$cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
+		}
+	} else {
+		$cloud = \%ctags_lc;
+	}
+	$cloud;
+}
+
+sub git_show_project_tagcloud {
+	my ($cloud, $count) = @_;
+	print STDERR ref($cloud)."..\n";
+	if (ref $cloud eq 'HTML::TagCloud') {
+		return $cloud->html_and_css($count);
+	} else {
+		my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
+		return '<p align="center">' . join (', ', map {
+			"<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
+		} splice(@tags, 0, $count)) . '</p>';
+	}
+}
+
 sub git_get_project_url_list {
 	my $path = shift;
 
@@ -3573,6 +3652,7 @@ sub fill_project_list_info {
 	my ($projlist, $check_forks) = @_;
 	my @projects;
 
+	my $show_ctags = gitweb_check_feature('ctags');
  PROJECT:
 	foreach my $pr (@$projlist) {
 		my (@activity) = git_get_last_activity($pr->{'path'});
@@ -3599,6 +3679,7 @@ sub fill_project_list_info {
 				$pr->{'forks'} = 0;
 			}
 		}
+		$show_ctags and $pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
 		push @projects, $pr;
 	}
 
@@ -3645,6 +3726,18 @@ sub git_project_list_body {
 	$from = 0 unless defined $from;
 	$to = $#projects if (!defined $to || $#projects < $to);
 
+	my $show_ctags = gitweb_check_feature('ctags');
+	if ($show_ctags) {
+		my %ctags;
+		foreach my $p (@projects) {
+			foreach my $ct (keys %{$p->{'ctags'}}) {
+				$ctags{$ct} += $p->{'ctags'}->{$ct};
+			}
+		}
+		my $cloud = git_populate_project_tagcloud(\%ctags);
+		print git_show_project_tagcloud($cloud, 64);
+	}
+
 	print "<table class=\"project_list\">\n";
 	unless ($no_header) {
 		print "<tr>\n";
@@ -3663,8 +3756,10 @@ sub git_project_list_body {
 		      "</tr>\n";
 	}
 	my $alternate = 1;
+	my $tagfilter = $cgi->param('by_tag');
 	for (my $i = $from; $i <= $to; $i++) {
 		my $pr = $projects[$i];
+		next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
 		if ($alternate) {
 			print "<tr class=\"dark\">\n";
 		} else {
@@ -4086,6 +4181,20 @@ sub git_summary {
 		print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
 		$url_tag = "";
 	}
+
+	# Tag cloud
+	my $show_ctags = (gitweb_check_feature('ctags'))[0];
+	if ($show_ctags) {
+		my $ctags = git_get_project_ctags($project);
+		my $cloud = git_populate_project_tagcloud($ctags);
+		print "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
+		print "</td>\n<td>" unless %$ctags;
+		print "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
+		print "</td>\n<td>" if %$ctags;
+		print git_show_project_tagcloud($cloud, 48);
+		print "</td></tr>";
+	}
+
 	print "</table>\n";
 
 	if (-s "$projectroot/$project/README.html") {
-- 
tg: (c5a1246..) t/tagcloud/tagcloud (depends on: vanilla/master t/summary/css-metadata)
Petr Baudis· Oct 2, 2008, 15:17 UTC · re: Petr Baudis · lore

[PATCH] gitweb: Make the by_tag filter delve in forks as well

This requires us to build a full index including forks and then weed them out only when printing.

Signed-off-by: Petr Baudis <petr.baudis@novartis.com>
---
 gitweb/gitweb.perl |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)
Show changes to gitweb/gitweb.perl +10 −3
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 02083d5..07fa1e6 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1880,9 +1880,7 @@ sub git_get_projects_list {
 
 				my $subdir = substr($File::Find::name, $pfxlen + 1);
 				# we check related file in $projectroot
-				if ($check_forks and $subdir =~ m#/.#) {
-					$File::Find::prune = 1;
-				} elsif (check_export_ok("$projectroot/$filter/$subdir")) {
+				if (check_export_ok("$projectroot/$filter/$subdir")) {
 					push @list, { path => ($filter ? "$filter/" : '') . $subdir };
 					$File::Find::prune = 1;
 				}
@@ -3715,6 +3713,7 @@ sub print_sort_th_num {
 }
 
 sub git_project_list_body {
+	# actually uses global variable $project
 	my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
 
 	my ($check_forks) = gitweb_check_feature('forks');
@@ -3757,7 +3756,15 @@ sub git_project_list_body {
 	my $tagfilter = $cgi->param('by_tag');
 	for (my $i = $from; $i <= $to; $i++) {
 		my $pr = $projects[$i];
+
 		next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
+		# Weed out forks
+		if ($check_forks) {
+			my $forkbase = $project; $forkbase ||= ''; $forkbase =~ s#\.git$#/#;
+			$forkbase="^$forkbase" if $forkbase;
+			next if not $tagfilter and $pr->{'path'} =~ m#$forkbase.*/.*#; # regexp-safe
+		}
+
 		if ($alternate) {
 			print "<tr class=\"dark\">\n";
 		} else {
-- 
tg: (f429121..) t/tagcloud/forks (depends on: t/tagcloud/tagcloud)
Petr Baudis· Oct 3, 2008, 07:29 UTC · re: Petr Baudis · lore

[PATCH] gitweb: Support for simple project search form

This is a trivial patch adding support for searching projects by name and description, making use of the "infrastructure" provided by the tag cloud generation.

Signed-off-by: Petr Baudis <petr.baudis@novartis.com>
---
 gitweb/gitweb.css  |    4 ++++
 gitweb/gitweb.perl |   12 ++++++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)
Show changes to 2 files +14 −2

gitweb/gitweb.css, gitweb/gitweb.perl

diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 07f5b53..a01eac8 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -435,6 +435,10 @@ div.search {
 	right: 12px
 }
 
+p.projsearch {
+	text-align: center;
+}
+
 td.linenr {
 	text-align: right;
 }
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 07fa1e6..4bc8a12 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -3758,11 +3758,14 @@ sub git_project_list_body {
 		my $pr = $projects[$i];
 
 		next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
-		# Weed out forks
+		next if $searchtext and not $pr->{'path'} =~ /$searchtext/
+			and not $pr->{'descr_long'} =~ /$searchtext/;
+		# Weed out forks or non-matching entries of search
 		if ($check_forks) {
 			my $forkbase = $project; $forkbase ||= ''; $forkbase =~ s#\.git$#/#;
 			$forkbase="^$forkbase" if $forkbase;
-			next if not $tagfilter and $pr->{'path'} =~ m#$forkbase.*/.*#; # regexp-safe
+			next if not $searchtext and not $tagfilter and $show_ctags
+				and $pr->{'path'} =~ m#$forkbase.*/.*#; # regexp-safe
 		}
 
 		if ($alternate) {
@@ -4099,6 +4102,11 @@ sub git_project_list {
 		close $fd;
 		print "</div>\n";
 	}
+	print $cgi->startform(-method => "get") .
+	      "<p class=\"projsearch\">Search:\n" .
+	      $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+	      "</p>" .
+	      $cgi->end_form() . "\n";
 	git_project_list_body(\@list, $order);
 	git_footer_html();
 }
-- 
tg: (0d352a0..) t/misc/projsearch (depends on: t/tagcloud/forks)
Shawn O. Pearce· Oct 3, 2008, 00:30 UTC · re: Petr Baudis · lore
Petr Baudis <pasky@suse.cz> wrote:
Show 7 quoted lines
> In the metadata table of the summary page, all rows have their
> id (or class in case of URL) set now. This for example lets sites
> easily disable fields they do not want to show in their custom
> stylesheet (e.g. they are overly technical or irrelevant for the site).
> 
> Many of my other patches depend on this, so I would appreciate to hear
> as soon as possible if someone has an issue with this patch.
Its pretty trivial and painless.  So its applied.  Marking up unique
elements so you can control them via CSS isn't rocket science.  ;-)
 
Show 27 quoted lines
> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
> index da474d0..bd8124a 100755
> --- a/gitweb/gitweb.perl
> +++ b/gitweb/gitweb.perl
> @@ -4070,10 +4070,10 @@ sub git_summary {
>  
>  	print "<div class=\"title\">&nbsp;</div>\n";
>  	print "<table class=\"projects_list\">\n" .
> -	      "<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
> -	      "<tr><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
> +	      "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
> +	      "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
>  	if (defined $cd{'rfc2822'}) {
> -		print "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
> +		print "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
>  	}
>  
>  	# use per project git URL list in $projectroot/$project/cloneurl
> @@ -4083,7 +4083,7 @@ sub git_summary {
>  	@url_list = map { "$_/$project" } @git_base_url_list unless @url_list;
>  	foreach my $git_url (@url_list) {
>  		next unless $git_url;
> -		print "<tr><td>$url_tag</td><td>$git_url</td></tr>\n";
> +		print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
>  		$url_tag = "";
>  	}
>  	print "</table>\n";
-- 
Shawn.
Jakub Narebski· Oct 3, 2008, 01:04 UTC · re: Shawn O. Pearce · lore
"Shawn O. Pearce" <spearce@spearce.org> writes:
> Petr Baudis <pasky@suse.cz> wrote:
Show 10 quoted lines
> > In the metadata table of the summary page, all rows have their
> > id (or class in case of URL) set now. This for example lets sites
> > easily disable fields they do not want to show in their custom
> > stylesheet (e.g. they are overly technical or irrelevant for the site).
> > 
> > Many of my other patches depend on this, so I would appreciate to hear
> > as soon as possible if someone has an issue with this patch.
> 
> Its pretty trivial and painless.  So its applied.  Marking up unique
> elements so you can control them via CSS isn't rocket science.  ;-)
Somehow original patch didn't appear (yet) on git mailing list;
perhaps it ran afoul vger anti-SPAM filter...
 
> > +	      "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
> > +	      "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
> > +		print "<tr id=\"metadata_lchange\"><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n";
> > +		print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";

I like the idea, and I think this can be seen as beginning to use either microformats, or RDFa. You have marked those fragments for CSS to show or hide; microformats are about marking those fragments for machine to parse. Although microformats usually use 'class' (or 'rel' for links), not 'id' attribute for classifying data...

-- 
Jakub Narebski
Poland
ShadeHawk on #git

← back to recent threads