git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0] Some gitweb patches
@ 2006-07-29 20:39 Jakub Narebski
  2006-07-29 20:43 ` [PATCH 1] gitweb: whitespace cleanup Jakub Narebski
                   ` (23 more replies)
  0 siblings, 24 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-29 20:39 UTC (permalink / raw)
  To: git

This series of patches, based on 'next' branch (v1.4.2-rc2-g688a750 or 
688a75071490101dbc660e3304aafb7a13e28807) is the beginning of gitweb 
cleanup. It would hopefully introduce no new features.

Open-ended series...

-- 
Jakub Narebski
Poland

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 1] gitweb: whitespace cleanup
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
@ 2006-07-29 20:43 ` Jakub Narebski
  2006-07-29 20:51 ` [PATCH 2] gitweb: Use list for of open for running git commands, thorougly Jakub Narebski
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-29 20:43 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Use tab for indenting commands, spaces for align
(because the fact that some elements are aligned 
should not depend on the tab width).

 gitweb/gitweb.cgi |   58 +++++++++++++++++++++++++++--------------------------
 1 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index e5fca63..f92eeab 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -36,7 +36,7 @@ our $git_version = qx($GIT --version) =~
 # location for temporary files needed for diffs
 our $git_temp = "/tmp/gitweb";
 if (! -d $git_temp) {
-    mkdir($git_temp, 0700) || die_error("Couldn't mkdir $git_temp");
+	mkdir($git_temp, 0700) || die_error("Couldn't mkdir $git_temp");
 }
 
 # target of the home link on top of all pages
@@ -104,7 +104,7 @@ if (defined $project) {
 		die_error(undef, "No such project.");
 	}
 	$rss_link = "<link rel=\"alternate\" title=\"" . esc_param($project) . " log\" href=\"" .
-		    "$my_uri?" . esc_param("p=$project;a=rss") . "\" type=\"application/rss+xml\"/>";
+	            "$my_uri?" . esc_param("p=$project;a=rss") . "\" type=\"application/rss+xml\"/>";
 	$ENV{'GIT_DIR'} = "$projectroot/$project";
 } else {
 	git_project_list();
@@ -303,7 +303,7 @@ sub git_header_html {
 	} else {
 		$content_type = 'text/html';
 	}
-	print $cgi->header(-type=>$content_type,  -charset => 'utf-8', -status=> $status, -expires => $expires);
+	print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires);
 	print <<EOF;
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@@ -1138,17 +1138,17 @@ sub git_summary {
 				      "</td>\n" .
 				      "<td>";
 				if (defined($comment)) {
-				      print $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, esc_html($comment));
+					print $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, esc_html($comment));
 				}
 				print "</td>\n" .
 				      "<td class=\"link\">";
 				if ($tag{'type'} eq "tag") {
-				      print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag") . " | ";
+					print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag") . " | ";
 				}
 				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
 				if ($tag{'reftype'} eq "commit") {
-				      print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
-					    " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
+					print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
+					      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
 				}
 				print "</td>\n" .
 				      "</tr>";
@@ -1457,17 +1457,17 @@ sub git_tags {
 			      "</td>\n" .
 			      "<td>";
 			if (defined($comment)) {
-			      print $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, $comment);
+				print $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, $comment);
 			}
 			print "</td>\n" .
 			      "<td class=\"link\">";
 			if ($tag{'type'} eq "tag") {
-			      print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag") . " | ";
+				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag") . " | ";
 			}
 			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
 			if ($tag{'reftype'} eq "commit") {
-			      print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
-				    " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
+				print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
+				      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
 			}
 			print "</td>\n" .
 			      "</tr>";
@@ -1613,13 +1613,14 @@ sub git_blob_plain_mimetype {
 
 sub git_blob_plain {
 	if (!defined $hash) {
-                if (defined $file_name) {
-                        my $base = $hash_base || git_read_head($project);
-                        $hash = git_get_hash_by_path($base, $file_name, "blob") || die_error(undef, "Error lookup file.");
-                } else {
-                        die_error(undef, "No file name defined.");
-                }
-        }
+		if (defined $file_name) {
+			my $base = $hash_base || git_read_head($project);
+			$hash = git_get_hash_by_path($base, $file_name, "blob") 
+				or die_error(undef, "Error lookup file.");
+		} else {
+			die_error(undef, "No file name defined.");
+		}
+	}
 	my $type = shift;
 	open my $fd, "-|", "$GIT cat-file blob $hash" or die_error("Couldn't cat $file_name, $hash");
 
@@ -1644,13 +1645,14 @@ sub git_blob_plain {
 
 sub git_blob {
 	if (!defined $hash) {
-                if (defined $file_name) {
-                        my $base = $hash_base || git_read_head($project);
-                        $hash = git_get_hash_by_path($base, $file_name, "blob") || die_error(undef, "Error lookup file.");
-                } else {
-                        die_error(undef, "No file name defined.");
-                }
-        }
+		if (defined $file_name) {
+			my $base = $hash_base || git_read_head($project);
+			$hash = git_get_hash_by_path($base, $file_name, "blob") 
+				or die_error(undef, "Error lookup file.");
+		} else {
+			die_error(undef, "No file name defined.");
+		}
+	}
 	my $have_blame = git_get_project_config_bool ('blame');
 	open my $fd, "-|", "$GIT cat-file blob $hash" or die_error(undef, "Open failed.");
 	my $mimetype = git_blob_plain_mimetype($fd, $file_name);
@@ -1677,7 +1679,7 @@ sub git_blob {
 			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain") . "<br/>\n";
 		}
 		print "</div>\n".
-		       "<div>" .
+		      "<div>" .
 		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
 		      "</div>\n";
 	} else {
@@ -2305,7 +2307,7 @@ sub git_commitdiff {
 		my $status = $5;
 		my $file = validate_input(unquote($6));
 		if ($status eq "A") {
-			print "<div class=\"diff_info\">" .  file_type($to_mode) . ":" .
+			print "<div class=\"diff_info\">" . file_type($to_mode) . ":" .
 			      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$to_id;hb=$hash;f=$file")}, $to_id) . "(new)" .
 			      "</div>\n";
 			git_diff_print(undef, "/dev/null", $to_id, "b/$file");
@@ -2359,7 +2361,7 @@ sub git_commitdiff_plain {
 	      "Date: $ad{'rfc2822'} ($ad{'tz_local'})\n".
 	      "Subject: $co{'title'}\n";
 	if (defined $tagname) {
-	      print "X-Git-Tag: $tagname\n";
+		print "X-Git-Tag: $tagname\n";
 	}
 	print "X-Git-Url: $my_url?p=$project;a=commitdiff;h=$hash\n" .
 	      "\n";
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
  2006-07-29 20:43 ` [PATCH 1] gitweb: whitespace cleanup Jakub Narebski
@ 2006-07-29 20:51 ` Jakub Narebski
  2006-07-30  2:12   ` Jakub Narebski
  2006-07-31 10:53   ` Junio C Hamano
  2006-07-29 20:55 ` [PATCH 3] gitweb: simplify git_get_hash_by_path Jakub Narebski
                   ` (21 subsequent siblings)
  23 siblings, 2 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-29 20:51 UTC (permalink / raw)
  To: git

Use list form of open for running git commands and reading their
output through pipe, for example
  open my $fd, "-|", $GIT, "rev-list", "--header", "--parents", $hash
instead of
  open my $fd, "-|", "$GIT rev-list --header --parents $hash"
Single letter options use ' instead of " as quotes, according to style
used in list form of magic "-|" open.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
The correct solution would be to use safe_pipe_capture or, 
what's better, use Git.pm, when it will be in released version.

Should have no impact on speed. Using ' instead of " could bring
insignificant speedup.

 gitweb/gitweb.cgi |   45 +++++++++++++++++++++++++--------------------
 1 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index f92eeab..9a17f87 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -388,7 +388,7 @@ sub die_error {
 sub git_get_type {
 	my $hash = shift;
 
-	open my $fd, "-|", "$GIT cat-file -t $hash" or return;
+	open my $fd, "-|", $GIT, "cat-file", '-t', $hash or return;
 	my $type = <$fd>;
 	close $fd or return;
 	chomp $type;
@@ -440,7 +440,7 @@ sub git_read_tag {
 	my %tag;
 	my @comment;
 
-	open my $fd, "-|", "$GIT cat-file tag $tag_id" or return;
+	open my $fd, "-|", $GIT, "cat-file", "tag", $tag_id or return;
 	$tag{'id'} = $tag_id;
 	while (my $line = <$fd>) {
 		chomp $line;
@@ -512,7 +512,7 @@ sub git_read_commit {
 		@commit_lines = @$commit_text;
 	} else {
 		$/ = "\0";
-		open my $fd, "-|", "$GIT rev-list --header --parents --max-count=1 $commit_id" or return;
+		open my $fd, "-|", $GIT, "rev-list", "--header", "--parents", "--max-count=1", $commit_id or return;
 		@commit_lines = split '\n', <$fd>;
 		close $fd or return;
 		$/ = "\n";
@@ -610,7 +610,7 @@ sub git_diff_print {
 	if (defined $from) {
 		$from_tmp = "$git_temp/gitweb_" . $$ . "_from";
 		open my $fd2, "> $from_tmp";
-		open my $fd, "-|", "$GIT cat-file blob $from";
+		open my $fd, "-|", $GIT, "cat-file", "blob", $from;
 		my @file = <$fd>;
 		print $fd2 @file;
 		close $fd2;
@@ -621,7 +621,7 @@ sub git_diff_print {
 	if (defined $to) {
 		$to_tmp = "$git_temp/gitweb_" . $$ . "_to";
 		open my $fd2, "> $to_tmp";
-		open my $fd, "-|", "$GIT cat-file blob $to";
+		open my $fd, "-|", $GIT, "cat-file", "blob", $to;
 		my @file = <$fd>;
 		print $fd2 @file;
 		close $fd2;
@@ -1062,7 +1062,8 @@ sub git_summary {
 	      "<tr><td>owner</td><td>$owner</td></tr>\n" .
 	      "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n" .
 	      "</table>\n";
-	open my $fd, "-|", "$GIT rev-list --max-count=17 " . git_read_head($project) or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "rev-list", "--max-count=17", git_read_head($project) 
+		or die_error(undef, "Open failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd;
 	print "<div>\n" .
@@ -1526,7 +1527,7 @@ sub git_get_hash_by_path {
 	my $tree = $base;
 	my @parts = split '/', $path;
 	while (my $part = shift @parts) {
-		open my $fd, "-|", "$GIT ls-tree $tree" or die_error(undef, "Open git-ls-tree failed.");
+		open my $fd, "-|", $GIT, "ls-tree", $tree or die_error(undef, "Open git-ls-tree failed.");
 		my (@entries) = map { chomp; $_ } <$fd>;
 		close $fd or return undef;
 		foreach my $line (@entries) {
@@ -1622,7 +1623,7 @@ sub git_blob_plain {
 		}
 	}
 	my $type = shift;
-	open my $fd, "-|", "$GIT cat-file blob $hash" or die_error("Couldn't cat $file_name, $hash");
+	open my $fd, "-|", $GIT, "cat-file", "blob", $hash or die_error("Couldn't cat $file_name, $hash");
 
 	$type ||= git_blob_plain_mimetype($fd, $file_name);
 
@@ -1654,7 +1655,7 @@ sub git_blob {
 		}
 	}
 	my $have_blame = git_get_project_config_bool ('blame');
-	open my $fd, "-|", "$GIT cat-file blob $hash" or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "cat-file", "blob", $hash or die_error(undef, "Open failed.");
 	my $mimetype = git_blob_plain_mimetype($fd, $file_name);
 	if ($mimetype !~ m/^text\//) {
 		close $fd;
@@ -1718,7 +1719,7 @@ sub git_tree {
 		}
 	}
 	$/ = "\0";
-	open my $fd, "-|", "$GIT ls-tree -z $hash" or die_error(undef, "Open git-ls-tree failed.");
+	open my $fd, "-|", $GIT, "ls-tree", '-z', $hash or die_error(undef, "Open git-ls-tree failed.");
 	chomp (my (@entries) = <$fd>);
 	close $fd or die_error(undef, "Reading tree failed.");
 	$/ = "\n";
@@ -1799,7 +1800,8 @@ #			      " | " . $cgi->a({-href => "$my
 
 sub git_rss {
 	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
-	open my $fd, "-|", "$GIT rev-list --max-count=150 " . git_read_head($project) or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project) 
+		or die_error(undef, "Open failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading rev-list failed.");
 	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
@@ -1819,7 +1821,7 @@ sub git_rss {
 			last;
 		}
 		my %cd = date_str($co{'committer_epoch'});
-		open $fd, "-|", "$GIT diff-tree -r $co{'parent'} $co{'id'}" or next;
+		open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next;
 		my @difftree = map { chomp; $_ } <$fd>;
 		close $fd or next;
 		print "<item>\n" .
@@ -1907,7 +1909,7 @@ sub git_log {
 	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n";
 
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
-	open my $fd, "-|", "$GIT rev-list $limit $hash" or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "rev-list", $limit, $hash or die_error(undef, "Open failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd;
 
@@ -1998,7 +2000,8 @@ sub git_commit {
 		$root = " --root";
 		$parent = "";
 	}
-	open my $fd, "-|", "$GIT diff-tree -r -M $root $parent $hash" or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "diff-tree", '-r', '-M', $root, $parent, $hash 
+		or die_error(undef, "Open failed.");
 	@difftree = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
@@ -2244,7 +2247,8 @@ sub git_commitdiff {
 	if (!defined $hash_parent) {
 		$hash_parent = $co{'parent'};
 	}
-	open my $fd, "-|", "$GIT diff-tree -r $hash_parent $hash" or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash
+		or die_error(undef, "Open failed.");
 	my (@difftree) = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
@@ -2334,14 +2338,15 @@ sub git_commitdiff {
 
 sub git_commitdiff_plain {
 	mkdir($git_temp, 0700);
-	open my $fd, "-|", "$GIT diff-tree -r $hash_parent $hash" or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash 
+		or die_error(undef, "Open failed.");
 	my (@difftree) = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
 	# try to figure out the next tag after this commit
 	my $tagname;
 	my $refs = read_info_ref("tags");
-	open $fd, "-|", "$GIT rev-list HEAD";
+	open $fd, "-|", $GIT, "rev-list", "HEAD";
 	chomp (my (@commits) = <$fd>);
 	close $fd;
 	foreach my $commit (@commits) {
@@ -2419,7 +2424,7 @@ sub git_history {
 	git_print_page_path($file_name, $ftype);
 
 	open my $fd, "-|",
-		"$GIT rev-list --full-history $hash_base -- \'$file_name\'";
+		$GIT, "rev-list", "--full-history", $hash_base, "--", "\'$file_name\'";
 	print "<table cellspacing=\"0\">\n";
 	my $alternate = 0;
 	while (my $line = <$fd>) {
@@ -2506,7 +2511,7 @@ sub git_search {
 	my $alternate = 0;
 	if ($commit_search) {
 		$/ = "\0";
-		open my $fd, "-|", "$GIT rev-list --header --parents $hash" or next;
+		open my $fd, "-|", $GIT, "rev-list", "--header", "--parents", $hash or next;
 		while (my $commit_text = <$fd>) {
 			if (!grep m/$searchtext/i, $commit_text) {
 				next;
@@ -2627,7 +2632,7 @@ sub git_shortlog {
 	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n";
 
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
-	open my $fd, "-|", "$GIT rev-list $limit $hash" or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "rev-list", $limit, $hash or die_error(undef, "Open failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd;
 
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 3] gitweb: simplify git_get_hash_by_path
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
  2006-07-29 20:43 ` [PATCH 1] gitweb: whitespace cleanup Jakub Narebski
  2006-07-29 20:51 ` [PATCH 2] gitweb: Use list for of open for running git commands, thorougly Jakub Narebski
@ 2006-07-29 20:55 ` Jakub Narebski
  2006-07-29 21:01 ` [PATCH 4] gitweb: More explicit error messages for open "-|" Jakub Narebski
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-29 20:55 UTC (permalink / raw)
  To: git

Simplify git_get_hash_by_path by using git-ls-tree to do path
limiting, instead of finding correct ttree and parsing unconstrained
git-ls-tree output.

_Should_ be slightly faster.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Testing speed before and after this patch using ApacheBench 
on git.git repository has shown speedup withing error. Perhaps
sample size was too small...

Speedup should be larger for deeper nested projects with larger number
of files in a directory.

Not extensively tested!

 gitweb/gitweb.cgi |   32 +++++++++-----------------------
 1 files changed, 9 insertions(+), 23 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 9a17f87..e1a817b 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1525,29 +1525,15 @@ sub git_get_hash_by_path {
 	my $path = shift || return undef;
 
 	my $tree = $base;
-	my @parts = split '/', $path;
-	while (my $part = shift @parts) {
-		open my $fd, "-|", $GIT, "ls-tree", $tree or die_error(undef, "Open git-ls-tree failed.");
-		my (@entries) = map { chomp; $_ } <$fd>;
-		close $fd or return undef;
-		foreach my $line (@entries) {
-			#'100644	blob	0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
-			$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
-			my $t_mode = $1;
-			my $t_type = $2;
-			my $t_hash = $3;
-			my $t_name = validate_input(unquote($4));
-			if ($t_name eq $part) {
-				if (!(@parts)) {
-					return $t_hash;
-				}
-				if ($t_type eq "tree") {
-					$tree = $t_hash;
-				}
-				last;
-			}
-		}
-	}
+
+	open my $fd, "-|", $GIT, "ls-tree", $base, "--", $path
+		or die_error(undef, "Open git-ls-tree failed.");
+	my $line = <$fd>;
+	close $fd or return undef;
+
+	#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
+	$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+	return $3;
 }
 
 sub mimetype_guess_file {
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 4] gitweb: More explicit error messages for open "-|"
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (2 preceding siblings ...)
  2006-07-29 20:55 ` [PATCH 3] gitweb: simplify git_get_hash_by_path Jakub Narebski
@ 2006-07-29 21:01 ` Jakub Narebski
  2006-07-30  2:08 ` [PATCH 5] gitweb: Cleanup - chomp $line in consistent style Jakub Narebski
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-29 21:01 UTC (permalink / raw)
  To: git

Use more explicit error messages when failing magical "-|" open,
stating at least the name of the git command that failed.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Should not affect web security.

 gitweb/gitweb.cgi |   29 +++++++++++++++++------------
 1 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index e1a817b..2c67df0 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1063,7 +1063,7 @@ sub git_summary {
 	      "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n" .
 	      "</table>\n";
 	open my $fd, "-|", $GIT, "rev-list", "--max-count=17", git_read_head($project) 
-		or die_error(undef, "Open failed.");
+		or die_error(undef, "Open git-rev-list failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd;
 	print "<div>\n" .
@@ -1271,7 +1271,7 @@ sub git_blame2 {
 		die_error("400 Bad Request", "object is not a blob");
 	}
 	open ($fd, "-|", $GIT, "blame", '-l', $file_name, $hash_base)
-		or die_error(undef, "Open failed");
+		or die_error(undef, "Open git-blame failed.");
 	git_header_html();
 	print "<div class=\"page_nav\">\n" .
 		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
@@ -1333,7 +1333,7 @@ sub git_blame {
 			or die_error(undef, "Error lookup file.");
 	}
 	open ($fd, "-|", $GIT, "annotate", '-l', '-t', '-r', $file_name, $hash_base)
-		or die_error(undef, "Open failed.");
+		or die_error(undef, "Open git-annotate failed.");
 	git_header_html();
 	print "<div class=\"page_nav\">\n" .
 		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
@@ -1609,7 +1609,8 @@ sub git_blob_plain {
 		}
 	}
 	my $type = shift;
-	open my $fd, "-|", $GIT, "cat-file", "blob", $hash or die_error("Couldn't cat $file_name, $hash");
+	open my $fd, "-|", $GIT, "cat-file", "blob", $hash 
+		or die_error("Couldn't cat $file_name, $hash");
 
 	$type ||= git_blob_plain_mimetype($fd, $file_name);
 
@@ -1641,7 +1642,8 @@ sub git_blob {
 		}
 	}
 	my $have_blame = git_get_project_config_bool ('blame');
-	open my $fd, "-|", $GIT, "cat-file", "blob", $hash or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "cat-file", "blob", $hash 
+		or die_error(undef, "Couldn't cat $file_name, $hash.");
 	my $mimetype = git_blob_plain_mimetype($fd, $file_name);
 	if ($mimetype !~ m/^text\//) {
 		close $fd;
@@ -1705,7 +1707,8 @@ sub git_tree {
 		}
 	}
 	$/ = "\0";
-	open my $fd, "-|", $GIT, "ls-tree", '-z', $hash or die_error(undef, "Open git-ls-tree failed.");
+	open my $fd, "-|", $GIT, "ls-tree", '-z', $hash 
+		or die_error(undef, "Open git-ls-tree failed.");
 	chomp (my (@entries) = <$fd>);
 	close $fd or die_error(undef, "Reading tree failed.");
 	$/ = "\n";
@@ -1787,7 +1790,7 @@ #			      " | " . $cgi->a({-href => "$my
 sub git_rss {
 	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
 	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project) 
-		or die_error(undef, "Open failed.");
+		or die_error(undef, "Open git-rev-list failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading rev-list failed.");
 	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
@@ -1895,7 +1898,8 @@ sub git_log {
 	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n";
 
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
-	open my $fd, "-|", $GIT, "rev-list", $limit, $hash or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "rev-list", $limit, $hash 
+		or die_error(undef, "Open git-rev-list failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd;
 
@@ -1987,7 +1991,7 @@ sub git_commit {
 		$parent = "";
 	}
 	open my $fd, "-|", $GIT, "diff-tree", '-r', '-M', $root, $parent, $hash 
-		or die_error(undef, "Open failed.");
+		or die_error(undef, "Open git-diff-tree failed.");
 	@difftree = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
@@ -2234,7 +2238,7 @@ sub git_commitdiff {
 		$hash_parent = $co{'parent'};
 	}
 	open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash
-		or die_error(undef, "Open failed.");
+		or die_error(undef, "Open git-diff-tree failed.");
 	my (@difftree) = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
@@ -2325,7 +2329,7 @@ sub git_commitdiff {
 sub git_commitdiff_plain {
 	mkdir($git_temp, 0700);
 	open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash 
-		or die_error(undef, "Open failed.");
+		or die_error(undef, "Open git-diff-tree failed.");
 	my (@difftree) = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
@@ -2618,7 +2622,8 @@ sub git_shortlog {
 	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n";
 
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
-	open my $fd, "-|", $GIT, "rev-list", $limit, $hash or die_error(undef, "Open failed.");
+	open my $fd, "-|", $GIT, "rev-list", $limit, $hash 
+		or die_error(undef, "Open git-rev-list failed.");
 	my (@revlist) = map { chomp; $_ } <$fd>;
 	close $fd;
 
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 5] gitweb: Cleanup - chomp $line in consistent style
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (3 preceding siblings ...)
  2006-07-29 21:01 ` [PATCH 4] gitweb: More explicit error messages for open "-|" Jakub Narebski
@ 2006-07-30  2:08 ` Jakub Narebski
  2006-07-30  2:11 ` [PATCH 6] gitweb: Correct error from changing "-|" open to list form in git_commit Jakub Narebski
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30  2:08 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 2c67df0..e1f0e26 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -635,7 +635,7 @@ sub git_diff_print {
 		$/ = "\n";
 	} else {
 		while (my $line = <$fd>) {
-			chomp($line);
+			chomp $line;
 			my $char = substr($line, 0, 1);
 			my $diff_class = "";
 			if ($char eq '+') {
@@ -944,7 +944,7 @@ sub read_info_ref {
 	# c39ae07f393806ccf406ef966e9a15afc43cc36a	refs/tags/v2.6.11^{}
 	open my $fd, "$projectroot/$project/info/refs" or return;
 	while (my $line = <$fd>) {
-		chomp($line);
+		chomp $line;
 		if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
 			if (defined $refs{$1}) {
 				$refs{$1} .= " / $2";
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 6] gitweb: Correct error from changing "-|" open to list form in git_commit
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (4 preceding siblings ...)
  2006-07-30  2:08 ` [PATCH 5] gitweb: Cleanup - chomp $line in consistent style Jakub Narebski
@ 2006-07-30  2:11 ` Jakub Narebski
  2006-07-30 12:58 ` [PATCH 7] gitweb: Cleanup - chomp @lines in consistent style Jakub Narebski
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30  2:11 UTC (permalink / raw)
  To: git

Correct error in moving to list form of open for running git commands
and reading their output through pipe (PATCH 2 in series) in
git_commit subroutine.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
It also simplifies git_commit a tiny bit.

 gitweb/gitweb.cgi |    8 +++-----
 1 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index e1f0e26..86b9547 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1984,16 +1984,14 @@ sub git_commit {
 	my %cd = date_str($co{'committer_epoch'}, $co{'committer_tz'});
 
 	my @difftree;
-	my $root = "";
 	my $parent = $co{'parent'};
 	if (!defined $parent) {
-		$root = " --root";
-		$parent = "";
+		$parent = "--root";
 	}
-	open my $fd, "-|", $GIT, "diff-tree", '-r', '-M', $root, $parent, $hash 
+	open my $fd, "-|", $GIT, "diff-tree", '-r', '-M', $parent, $hash 
 		or die_error(undef, "Open git-diff-tree failed.");
 	@difftree = map { chomp; $_ } <$fd>;
-	close $fd or die_error(undef, "Reading diff-tree failed.");
+	close $fd or die_error(undef, "Reading git-diff-tree failed.");
 
 	# non-textual hash id's can be cached
 	my $expires;
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-29 20:51 ` [PATCH 2] gitweb: Use list for of open for running git commands, thorougly Jakub Narebski
@ 2006-07-30  2:12   ` Jakub Narebski
  2006-07-31 10:53   ` Junio C Hamano
  1 sibling, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30  2:12 UTC (permalink / raw)
  To: git

This patch introduces error in git_commit, corrected in [PATCH 6].
-- 
Jakub Narebski

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 7] gitweb: Cleanup - chomp @lines in consistent style
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (5 preceding siblings ...)
  2006-07-30  2:11 ` [PATCH 6] gitweb: Correct error from changing "-|" open to list form in git_commit Jakub Narebski
@ 2006-07-30 12:58 ` Jakub Narebski
  2006-07-30 12:59 ` [PATCH 8] gitweb: Add git_page_nav for later use Jakub Narebski
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 12:58 UTC (permalink / raw)
  To: git

Use 'my @lines = map { chomp; $_ } <$fd>;' form to read all lines of
git command output into array without trailing newlines.

It has advantage over 'chomp (my (@lines) = <$fd>);' in that it does
not modify array.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |   19 +++++++++----------
 1 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 86b9547..d5248fe 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1064,7 +1064,7 @@ sub git_summary {
 	      "</table>\n";
 	open my $fd, "-|", $GIT, "rev-list", "--max-count=17", git_read_head($project) 
 		or die_error(undef, "Open git-rev-list failed.");
-	my (@revlist) = map { chomp; $_ } <$fd>;
+	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog"), -class => "title"}, "shortlog") .
@@ -1709,7 +1709,7 @@ sub git_tree {
 	$/ = "\0";
 	open my $fd, "-|", $GIT, "ls-tree", '-z', $hash 
 		or die_error(undef, "Open git-ls-tree failed.");
-	chomp (my (@entries) = <$fd>);
+	my @entries = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading tree failed.");
 	$/ = "\n";
 
@@ -1791,7 +1791,7 @@ sub git_rss {
 	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
 	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project) 
 		or die_error(undef, "Open git-rev-list failed.");
-	my (@revlist) = map { chomp; $_ } <$fd>;
+	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading rev-list failed.");
 	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
 	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
@@ -1900,7 +1900,7 @@ sub git_log {
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 	open my $fd, "-|", $GIT, "rev-list", $limit, $hash 
 		or die_error(undef, "Open git-rev-list failed.");
-	my (@revlist) = map { chomp; $_ } <$fd>;
+	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
 	if ($hash ne $head || $page) {
@@ -1983,14 +1983,13 @@ sub git_commit {
 	my %ad = date_str($co{'author_epoch'}, $co{'author_tz'});
 	my %cd = date_str($co{'committer_epoch'}, $co{'committer_tz'});
 
-	my @difftree;
 	my $parent = $co{'parent'};
 	if (!defined $parent) {
 		$parent = "--root";
 	}
 	open my $fd, "-|", $GIT, "diff-tree", '-r', '-M', $parent, $hash 
 		or die_error(undef, "Open git-diff-tree failed.");
-	@difftree = map { chomp; $_ } <$fd>;
+	my @difftree = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading git-diff-tree failed.");
 
 	# non-textual hash id's can be cached
@@ -2237,7 +2236,7 @@ sub git_commitdiff {
 	}
 	open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash
 		or die_error(undef, "Open git-diff-tree failed.");
-	my (@difftree) = map { chomp; $_ } <$fd>;
+	my @difftree = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
 	# non-textual hash id's can be cached
@@ -2328,14 +2327,14 @@ sub git_commitdiff_plain {
 	mkdir($git_temp, 0700);
 	open my $fd, "-|", $GIT, "diff-tree", '-r', $hash_parent, $hash 
 		or die_error(undef, "Open git-diff-tree failed.");
-	my (@difftree) = map { chomp; $_ } <$fd>;
+	my @difftree = map { chomp; $_ } <$fd>;
 	close $fd or die_error(undef, "Reading diff-tree failed.");
 
 	# try to figure out the next tag after this commit
 	my $tagname;
 	my $refs = read_info_ref("tags");
 	open $fd, "-|", $GIT, "rev-list", "HEAD";
-	chomp (my (@commits) = <$fd>);
+	my @commits = map { chomp; $_ } <$fd>;
 	close $fd;
 	foreach my $commit (@commits) {
 		if (defined $refs->{$commit}) {
@@ -2622,7 +2621,7 @@ sub git_shortlog {
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 	open my $fd, "-|", $GIT, "rev-list", $limit, $hash 
 		or die_error(undef, "Open git-rev-list failed.");
-	my (@revlist) = map { chomp; $_ } <$fd>;
+	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
 	if ($hash ne $head || $page) {
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 8] gitweb: Add git_page_nav for later use
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (6 preceding siblings ...)
  2006-07-30 12:58 ` [PATCH 7] gitweb: Cleanup - chomp @lines in consistent style Jakub Narebski
@ 2006-07-30 12:59 ` Jakub Narebski
  2006-07-30 13:01 ` [PATCH 9] gitweb: Navbar refactoring - use git_page_nav to generate navigation bar Jakub Narebski
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 12:59 UTC (permalink / raw)
  To: git

Adds git_page_nav subroutine to factors out the generation of the
navigation bar.  Based on Sven Verdoolaege code
  Message-Id: <20050618113121.GA13122@pc117b.liacs.nl>
  http://marc.theaimsgroup.com/?l=git&m=111909432415478&w=2

I tried for the refactored navbar generate the same result.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |   34 ++++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index d5248fe..2bc3445 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -385,6 +385,40 @@ sub die_error {
 	exit;
 }
 
+sub git_page_nav {
+	my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
+	$extra = '' if !defined $extra; # pager or formats
+
+	my @navs = qw(summary shortlog log commit commitdiff tree);
+	if ($suppress) {
+		@navs = grep { $_ ne $suppress } @navs;
+	}
+
+	my %arg = map { $_, ''} @navs;
+	if (defined $head) {
+		for (qw(commit commitdiff)) {
+			$arg{$_} = ";h=$head";
+		}
+		if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) {
+			for (qw(shortlog log)) {
+				$arg{$_} = ";h=$head";
+			}
+		}
+	}
+	$arg{tree} .= ";h=$treehead" if defined $treehead;
+	$arg{tree} .= ";hb=$treebase" if defined $treebase;
+
+	print "<div class=\"page_nav\">\n" .
+		(join " | ",
+		 map { $_ eq $current
+					 ? $_
+					 : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
+				 }
+		 @navs);
+	print "<br/>$extra<br/>\n" .
+	      "</div>\n";
+}
+
 sub git_get_type {
 	my $hash = shift;
 
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 9] gitweb: Navbar refactoring - use git_page_nav to generate navigation bar
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (7 preceding siblings ...)
  2006-07-30 12:59 ` [PATCH 8] gitweb: Add git_page_nav for later use Jakub Narebski
@ 2006-07-30 13:01 ` Jakub Narebski
  2006-07-30 13:02 ` [PATCH 10] gitweb: Replace form-feed character by ^L Jakub Narebski
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 13:01 UTC (permalink / raw)
  To: git

Use git_page_nav subroutine to generate navigation bar.  Additional
navigation (either formats or pager/pagination) is put into variables.

Corrects error in git_search where hash parameter was added to
"summary" link instead of to "log" link.  Might differ from previous
version by additional "<br/>" in navigation bar.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |  235 +++++++++++++++--------------------------------------
 1 files changed, 66 insertions(+), 169 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 2bc3445..6c72d33 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1081,15 +1081,7 @@ sub git_summary {
 
 	my $refs = read_info_ref();
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      "summary".
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$head")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$head")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree")}, "tree") .
-	      "<br/><br/>\n" .
-	      "</div>\n";
+	git_page_nav('summary','', $head);
 	print "<div class=\"title\">&nbsp;</div>\n";
 	print "<table cellspacing=\"0\">\n" .
 	      "<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
@@ -1251,15 +1243,7 @@ sub git_print_page_path {
 sub git_tag {
 	my $head = git_read_head($project);
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$head")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$head")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;hb=$head")}, "tree") . "<br/>\n" .
-	      "<br/>\n" .
-	      "</div>\n";
+	git_page_nav('','', $head,undef,$head);
 	my %tag = git_read_tag($hash);
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($tag{'name'})) . "\n" .
@@ -1307,19 +1291,13 @@ sub git_blame2 {
 	open ($fd, "-|", $GIT, "blame", '-l', $file_name, $hash_base)
 		or die_error(undef, "Open git-blame failed.");
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
-	print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head") . "<br/>\n";
-	print "</div>\n".
-		"<div>" .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
-		"</div>\n";
+	my $formats_nav = 
+		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
+		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
+	git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+	print "<div>" .
+	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
+	      "</div>\n";
 	git_print_page_path($file_name, $ftype);
 	my @rev_color = (qw(light dark));
 	my $num_colors = scalar(@rev_color);
@@ -1369,19 +1347,13 @@ sub git_blame {
 	open ($fd, "-|", $GIT, "annotate", '-l', '-t', '-r', $file_name, $hash_base)
 		or die_error(undef, "Open git-annotate failed.");
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
-	print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
-		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head") . "<br/>\n";
-	print "</div>\n".
-		"<div>" .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
-		"</div>\n";
+	my $formats_nav = 
+		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
+		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
+	git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+	print "<div>" .
+	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
+	      "</div>\n";
 	git_print_page_path($file_name);
 	print "<div class=\"page_body\">\n";
 	print <<HTML;
@@ -1456,15 +1428,7 @@ HTML
 sub git_tags {
 	my $head = git_read_head($project);
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$head")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$head")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;hb=$head")}, "tree") . "<br/>\n" .
-	      "<br/>\n" .
-	      "</div>\n";
+	git_page_nav('','', $head,undef,$head);
 	my $taglist = git_read_refs("refs/tags");
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
@@ -1515,15 +1479,7 @@ sub git_tags {
 sub git_heads {
 	my $head = git_read_head($project);
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$head")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$head")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;hb=$head")}, "tree") . "<br/>\n" .
-	      "<br/>\n" .
-	      "</div>\n";
+	git_page_nav('','', $head,undef,$head);
 	my $taglist = git_read_refs("refs/heads");
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
@@ -1684,25 +1640,20 @@ sub git_blob {
 		return git_blob_plain($mimetype);
 	}
 	git_header_html();
+	my $formats_nav = '';
 	if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
-		print "<div class=\"page_nav\">\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
 		if (defined $file_name) {
 			if ($have_blame) {
-				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$hash;hb=$hash_base;f=$file_name")}, "blame") .  " | ";
+				$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$hash;hb=$hash_base;f=$file_name")}, "blame") . " | ";
 			}
-			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
-			" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head") . "<br/>\n";
+			$formats_nav .=
+				$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
+				" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head");
 		} else {
-			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain") . "<br/>\n";
+			$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain");
 		}
-		print "</div>\n".
-		      "<div>" .
+		git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
+		print "<div>" .
 		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
 		      "</div>\n";
 	} else {
@@ -1757,15 +1708,7 @@ sub git_tree {
 	my $base = "";
 	if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
 		$base_key = ";hb=$hash_base";
-		print "<div class=\"page_nav\">\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash_base")}, "shortlog") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash_base")}, "log") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
-		      " | tree" .
-		      "<br/><br/>\n" .
-		      "</div>\n";
+		git_page_nav('tree','', $hash_base);
 		print "<div>\n" .
 		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
 		      "</div>\n";
@@ -1922,14 +1865,6 @@ sub git_log {
 		$page = 0;
 	}
 	my $refs = read_info_ref();
-	git_header_html();
-	print "<div class=\"page_nav\">\n";
-	print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash")}, "shortlog") .
-	      " | log" .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n";
 
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 	open my $fd, "-|", $GIT, "rev-list", $limit, $hash 
@@ -1937,25 +1872,28 @@ sub git_log {
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
+	my $paging_nav = '';
 	if ($hash ne $head || $page) {
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "HEAD");
+		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "HEAD");
 	} else {
-		print "HEAD";
+		$paging_nav .= "HEAD";
 	}
 	if ($page > 0) {
-		print " &sdot; " .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash;pg=" . ($page-1)), -accesskey => "p", -title => "Alt-p"}, "prev");
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash;pg=" . ($page-1)), -accesskey => "p", -title => "Alt-p"}, "prev");
 	} else {
-		print " &sdot; prev";
+		$paging_nav .= " &sdot; prev";
 	}
 	if ($#revlist >= (100 * ($page+1)-1)) {
-		print " &sdot; " .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash;pg=" . ($page+1)), -accesskey => "n", -title => "Alt-n"}, "next");
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash;pg=" . ($page+1)), -accesskey => "n", -title => "Alt-n"}, "next");
 	} else {
-		print " &sdot; next";
+		$paging_nav .= " &sdot; next";
 	}
-	print "<br/>\n" .
-	      "</div>\n";
+
+	git_header_html();
+	git_page_nav('log','', $hash,undef,undef, $paging_nav);
+
 	if (!@revlist) {
 		print "<div>\n" .
 		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
@@ -2037,21 +1975,14 @@ sub git_commit {
 		$ref = " <span class=\"tag\">" . esc_html($refs->{$co{'id'}}) . "</span>";
 	}
 	git_header_html(undef, $expires);
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash")}, "log") .
-	      " | commit";
-	if (defined $co{'parent'}) {
-		print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash")}, "commitdiff");
-	}
-	print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash")}, "tree") . "\n" .
-		"<br/>\n";
+	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;hb=$parent;f=$file_name")}, "blame") . "\n";
+		$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;hb=$parent;f=$file_name")}, "blame");
 	}
-	print "<br/></div>\n";
+	git_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff', 
+							 $hash, $co{'tree'}, $hash,
+							 $formats_nav);
 
 	if (defined $co{'parent'}) {
 		print "<div>\n" .
@@ -2223,16 +2154,9 @@ sub git_blobdiff {
 	mkdir($git_temp, 0700);
 	git_header_html();
 	if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
-		print "<div class=\"page_nav\">\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") .
-		      "<br/>\n";
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff_plain;h=$hash;hp=$hash_parent")}, "plain") .
-		      "</div>\n";
+		my $formats_nav = 
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
+		git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
 		print "<div>\n" .
 		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . "\n" .
 		      "</div>\n";
@@ -2284,15 +2208,9 @@ sub git_commitdiff {
 		$ref = " <span class=\"tag\">" . esc_html($refs->{$co{'id'}}) . "</span>";
 	}
 	git_header_html(undef, $expires);
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash")}, "commit") .
-	      " | commitdiff" .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash")}, "tree") . "<br/>\n";
-	print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain") . "\n" .
-	      "</div>\n";
+	my $formats_nav =
+		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
+	git_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
 	      "</div>\n";
@@ -2424,15 +2342,7 @@ sub git_history {
 	}
 	my $refs = read_info_ref();
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") .
-	      "<br/><br/>\n" .
-	      "</div>\n";
+	git_page_nav('','', $hash_base,$co{'tree'},$hash_base);
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . "\n" .
 	      "</div>\n";
@@ -2515,15 +2425,7 @@ sub git_search {
 		$pickaxe_search = 1;
 	}
 	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary;h=$hash")}, "summary") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash")}, "tree") .
-	      "<br/><br/>\n" .
-	      "</div>\n";
+	git_page_nav('','', $hash,$co{'tree'},$hash);
 
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($co{'title'})) . "\n" .
@@ -2643,14 +2545,6 @@ sub git_shortlog {
 		$page = 0;
 	}
 	my $refs = read_info_ref();
-	git_header_html();
-	print "<div class=\"page_nav\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
-	      " | shortlog" .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash")}, "log") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash")}, "commit") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash")}, "commitdiff") .
-	      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$hash;hb=$hash")}, "tree") . "<br/>\n";
 
 	my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 	open my $fd, "-|", $GIT, "rev-list", $limit, $hash 
@@ -2658,25 +2552,28 @@ sub git_shortlog {
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
+	my $paging_nav = '';
 	if ($hash ne $head || $page) {
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "HEAD");
+		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "HEAD");
 	} else {
-		print "HEAD";
+		$paging_nav .= "HEAD";
 	}
 	if ($page > 0) {
-		print " &sdot; " .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page-1)), -accesskey => "p", -title => "Alt-p"}, "prev");
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page-1)), -accesskey => "p", -title => "Alt-p"}, "prev");
 	} else {
-		print " &sdot; prev";
+		$paging_nav .= " &sdot; prev";
 	}
 	if ($#revlist >= (100 * ($page+1)-1)) {
-		print " &sdot; " .
-		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page+1)), -accesskey => "n", -title => "Alt-n"}, "next");
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page+1)), -accesskey => "n", -title => "Alt-n"}, "next");
 	} else {
-		print " &sdot; next";
+		$paging_nav .= " &sdot; next";
 	}
-	print "<br/>\n" .
-	      "</div>\n";
+
+	git_header_html();
+	git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
+
 	print "<div>\n" .
 	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
 	      "</div>\n";
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 10] gitweb: Replace form-feed character by ^L
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (8 preceding siblings ...)
  2006-07-30 13:01 ` [PATCH 9] gitweb: Navbar refactoring - use git_page_nav to generate navigation bar Jakub Narebski
@ 2006-07-30 13:02 ` Jakub Narebski
  2006-07-30 14:13 ` [PATCH 11] gitweb: Read project description using utf-8 encoding Jakub Narebski
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 13:02 UTC (permalink / raw)
  To: git

>From 2be5cab10486cba804ccae063e93b146288054fe Mon Sep 17 00:00:00 2001
From: Jakub Narebski <jnareb@gmail.com>
Date: Sun, 30 Jul 2006 13:11:56 +0200
Subject: [PATCH] 

Replace FORM FEED (FF) character (014, 12, 0xc) by it's textual
representation '^L'.  This character is used for example in GNU GPL
'COPYING' file.  With this patch "blob" output for COPYING passes
XHTML validation.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 6c72d33..d39af82 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -250,6 +250,7 @@ sub esc_html {
 	my $str = shift;
 	$str = decode("utf8", $str, Encode::FB_DEFAULT);
 	$str = escapeHTML($str);
+	$str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file)
 	return $str;
 }
 
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 11] gitweb: Read project description using utf-8 encoding
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (9 preceding siblings ...)
  2006-07-30 13:02 ` [PATCH 10] gitweb: Replace form-feed character by ^L Jakub Narebski
@ 2006-07-30 14:13 ` Jakub Narebski
  2006-07-30 15:20   ` Jakub Narebski
  2006-07-30 15:47   ` [PATCH 11] gitweb: Show project descriptions with utf-8 characters in project list correctly Jakub Narebski
  2006-07-30 14:14 ` [PATCH 12] gitweb: Add "\n" after <br/> in git_page_nav Jakub Narebski
                   ` (12 subsequent siblings)
  23 siblings, 2 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 14:13 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index d39af82..7d52a2c 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -463,7 +463,7 @@ sub git_read_hash {
 sub git_read_description {
 	my $path = shift;
 
-	open my $fd, "$projectroot/$path/description" or return undef;
+	open (my $fd, "<:utf8", "$projectroot/$path/description") or return undef;
 	my $descr = <$fd>;
 	close $fd;
 	chomp $descr;
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 12] gitweb: Add "\n" after <br/> in git_page_nav
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (10 preceding siblings ...)
  2006-07-30 14:13 ` [PATCH 11] gitweb: Read project description using utf-8 encoding Jakub Narebski
@ 2006-07-30 14:14 ` Jakub Narebski
  2006-07-30 15:49 ` [PATCH 13] gitweb: Pager refactoring - use git_get_paging_nav for pagination Jakub Narebski
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 14:14 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 7d52a2c..df152c3 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -416,7 +416,7 @@ sub git_page_nav {
 					 : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
 				 }
 		 @navs);
-	print "<br/>$extra<br/>\n" .
+	print "<br/>\n$extra<br/>\n" .
 	      "</div>\n";
 }
 
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 11] gitweb: Read project description using utf-8 encoding
  2006-07-30 14:13 ` [PATCH 11] gitweb: Read project description using utf-8 encoding Jakub Narebski
@ 2006-07-30 15:20   ` Jakub Narebski
  2006-07-30 15:47   ` [PATCH 11] gitweb: Show project descriptions with utf-8 characters in project list correctly Jakub Narebski
  1 sibling, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 15:20 UTC (permalink / raw)
  To: git

Disregard this patch for now. It corrects error in project_list page, but
introduces errors on other pages:

  Software error: Cannot decode string with wide characters 
  at Encode.pm line 166.

Corrected patch to follow.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 11] gitweb: Show project descriptions with utf-8 characters in project list correctly
  2006-07-30 14:13 ` [PATCH 11] gitweb: Read project description using utf-8 encoding Jakub Narebski
  2006-07-30 15:20   ` Jakub Narebski
@ 2006-07-30 15:47   ` Jakub Narebski
  1 sibling, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 15:47 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This supersedes previous patch.

 gitweb/gitweb.cgi |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 3884ffd..1befa7d 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -988,7 +988,7 @@ sub git_project_list {
 		}
 		$alternate ^= 1;
 		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
-		      "<td>$pr->{'descr'}</td>\n" .
+		      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
 		      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
 		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "</td>\n" .
 		      "<td class=\"link\">" .
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 13] gitweb: Pager refactoring - use git_get_paging_nav for pagination
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (11 preceding siblings ...)
  2006-07-30 14:14 ` [PATCH 12] gitweb: Add "\n" after <br/> in git_page_nav Jakub Narebski
@ 2006-07-30 15:49 ` Jakub Narebski
  2006-07-30 18:31 ` [PATCH 14] gitweb: Remove $project from git_get_paging_nav arguments Jakub Narebski
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 15:49 UTC (permalink / raw)
  To: git

Add git_get_paging_nav subroutine which returns string with pager
(paging nav) for shortlog and log actions.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
It would make no sense to split this patch into two, I think.

 gitweb/gitweb.cgi |   68 +++++++++++++++++++++++++----------------------------
 1 files changed, 32 insertions(+), 36 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index df152c3..0ed3ad2 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -420,6 +420,36 @@ sub git_page_nav {
 	      "</div>\n";
 }
 
+sub git_get_paging_nav {
+	my ($project, $action, $hash, $head, $page, $nrevs) = @_;
+	my $paging_nav;
+
+
+	if ($hash ne $head || $page) {
+		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action")}, "HEAD");
+	} else {
+		$paging_nav .= "HEAD";
+	}
+
+	if ($page > 0) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page-1)),
+							 -accesskey => "p", -title => "Alt-p"}, "prev");
+	} else {
+		$paging_nav .= " &sdot; prev";
+	}
+
+	if ($nrevs >= (100 * ($page+1)-1)) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page+1)),
+							 -accesskey => "n", -title => "Alt-n"}, "next");
+	} else {
+		$paging_nav .= " &sdot; next";
+	}
+
+	return $paging_nav;
+}
+
 sub git_get_type {
 	my $hash = shift;
 
@@ -1873,24 +1903,7 @@ sub git_log {
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
-	my $paging_nav = '';
-	if ($hash ne $head || $page) {
-		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "HEAD");
-	} else {
-		$paging_nav .= "HEAD";
-	}
-	if ($page > 0) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash;pg=" . ($page-1)), -accesskey => "p", -title => "Alt-p"}, "prev");
-	} else {
-		$paging_nav .= " &sdot; prev";
-	}
-	if ($#revlist >= (100 * ($page+1)-1)) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$hash;pg=" . ($page+1)), -accesskey => "n", -title => "Alt-n"}, "next");
-	} else {
-		$paging_nav .= " &sdot; next";
-	}
+	my $paging_nav = git_get_paging_nav($project, 'log', $hash, $head, $page, $#revlist);
 
 	git_header_html();
 	git_page_nav('log','', $hash,undef,undef, $paging_nav);
@@ -2553,24 +2566,7 @@ sub git_shortlog {
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
-	my $paging_nav = '';
-	if ($hash ne $head || $page) {
-		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "HEAD");
-	} else {
-		$paging_nav .= "HEAD";
-	}
-	if ($page > 0) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page-1)), -accesskey => "p", -title => "Alt-p"}, "prev");
-	} else {
-		$paging_nav .= " &sdot; prev";
-	}
-	if ($#revlist >= (100 * ($page+1)-1)) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page+1)), -accesskey => "n", -title => "Alt-n"}, "next");
-	} else {
-		$paging_nav .= " &sdot; next";
-	}
+	my $paging_nav = git_get_paging_nav($project, 'shortlog', $hash, $head, $page, $#revlist);
 
 	git_header_html();
 	git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 14] gitweb: Remove $project from git_get_paging_nav arguments
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (12 preceding siblings ...)
  2006-07-30 15:49 ` [PATCH 13] gitweb: Pager refactoring - use git_get_paging_nav for pagination Jakub Narebski
@ 2006-07-30 18:31 ` Jakub Narebski
  2006-07-30 18:32 ` [PATCH 15] gitweb: Headers refactoring - use git_header_div for header divs Jakub Narebski
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 18:31 UTC (permalink / raw)
  To: git

Remove $project from arguments passed to git_get_paging_nav
subroutine: it did not depend only on arguments, using $my_uri global
variable (and now $project global variable).

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 1befa7d..bfb01de 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -421,7 +421,7 @@ sub git_page_nav {
 }
 
 sub git_get_paging_nav {
-	my ($project, $action, $hash, $head, $page, $nrevs) = @_;
+	my ($action, $hash, $head, $page, $nrevs) = @_;
 	my $paging_nav;
 
 
@@ -1903,7 +1903,7 @@ sub git_log {
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
-	my $paging_nav = git_get_paging_nav($project, 'log', $hash, $head, $page, $#revlist);
+	my $paging_nav = git_get_paging_nav('log', $hash, $head, $page, $#revlist);
 
 	git_header_html();
 	git_page_nav('log','', $hash,undef,undef, $paging_nav);
@@ -2566,7 +2566,7 @@ sub git_shortlog {
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 
-	my $paging_nav = git_get_paging_nav($project, 'shortlog', $hash, $head, $page, $#revlist);
+	my $paging_nav = git_get_paging_nav('shortlog', $hash, $head, $page, $#revlist);
 
 	git_header_html();
 	git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 15] gitweb: Headers refactoring - use git_header_div for header divs
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (13 preceding siblings ...)
  2006-07-30 18:31 ` [PATCH 14] gitweb: Remove $project from git_get_paging_nav arguments Jakub Narebski
@ 2006-07-30 18:32 ` Jakub Narebski
  2006-07-30 20:36 ` [PATCH 16] gitweb: Remove characters entities entirely when shortening string Jakub Narebski
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 18:32 UTC (permalink / raw)
  To: git

Add git_header_div subroutine which prints "header" divs, now with
class "header" (class "title" is taken, and has set CSS style,
changing appereance and maing layout wrong), and use it thorough
gitweb.cgi.  Change header linking to project summary from empty
(&nbsp; as a contents of link) to having $project as contents/name
of link.  Sometimes a little reordering.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |  100 +++++++++++++++++++++--------------------------------
 1 files changed, 40 insertions(+), 60 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index bfb01de..06a6930 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -420,6 +420,19 @@ sub git_page_nav {
 	      "</div>\n";
 }
 
+sub git_header_div {
+	my ($action, $title, $hash, $hash_base) = @_;
+	my $rest = '';
+
+	$rest .= ";h=$hash" if $hash;
+	$rest .= ";hb=$hash_base" if $hash_base;
+
+	print "<div class=\"header\">\n" .
+	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
+	               -class => "title"}, $title ? $title : $action) . "\n" .
+	      "</div>\n";
+}
+
 sub git_get_paging_nav {
 	my ($action, $hash, $head, $page, $nrevs) = @_;
 	my $paging_nav;
@@ -1123,9 +1136,7 @@ sub git_summary {
 		or die_error(undef, "Open git-rev-list failed.");
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog"), -class => "title"}, "shortlog") .
-	      "</div>\n";
+	git_header_div('shortlog');
 	my $i = 16;
 	print "<table cellspacing=\"0\">\n";
 	my $alternate = 0;
@@ -1169,9 +1180,7 @@ sub git_summary {
 
 	my $taglist = git_read_refs("refs/tags");
 	if (defined @$taglist) {
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tags"), -class => "title"}, "tags") .
-		      "</div>\n";
+		git_header_div('tags');
 		my $i = 16;
 		print "<table cellspacing=\"0\">\n";
 		my $alternate = 0;
@@ -1221,9 +1230,7 @@ sub git_summary {
 
 	my $headlist = git_read_refs("refs/heads");
 	if (defined @$headlist) {
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads"), -class => "title"}, "heads") .
-		      "</div>\n";
+		git_header_div('heads');
 		my $i = 16;
 		print "<table cellspacing=\"0\">\n";
 		my $alternate = 0;
@@ -1276,9 +1283,7 @@ sub git_tag {
 	git_header_html();
 	git_page_nav('','', $head,undef,$head);
 	my %tag = git_read_tag($hash);
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($tag{'name'})) . "\n" .
-	      "</div>\n";
+	git_header_div('commit', esc_html($tag{'name'}), $hash);
 	print "<div class=\"title_text\">\n" .
 	      "<table cellspacing=\"0\">\n" .
 	      "<tr>\n" .
@@ -1326,9 +1331,7 @@ sub git_blame2 {
 		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
 		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
 	git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
-	print "<div>" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
-	      "</div>\n";
+	git_header_div('commit', esc_html($co{'title'}), $hash_base);
 	git_print_page_path($file_name, $ftype);
 	my @rev_color = (qw(light dark));
 	my $num_colors = scalar(@rev_color);
@@ -1382,9 +1385,7 @@ sub git_blame {
 		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
 		" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head");
 	git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
-	print "<div>" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
-	      "</div>\n";
+	git_header_div('commit', esc_html($co{'title'}), $hash_base);
 	git_print_page_path($file_name);
 	print "<div class=\"page_body\">\n";
 	print <<HTML;
@@ -1460,11 +1461,10 @@ sub git_tags {
 	my $head = git_read_head($project);
 	git_header_html();
 	git_page_nav('','', $head,undef,$head);
-	my $taglist = git_read_refs("refs/tags");
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
-	      "</div>\n";
+	git_header_div('summary', $project);
 	print "<table cellspacing=\"0\">\n";
+
+	my $taglist = git_read_refs("refs/tags");
 	my $alternate = 0;
 	if (defined @$taglist) {
 		foreach my $entry (@$taglist) {
@@ -1511,11 +1511,10 @@ sub git_heads {
 	my $head = git_read_head($project);
 	git_header_html();
 	git_page_nav('','', $head,undef,$head);
-	my $taglist = git_read_refs("refs/heads");
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
-	      "</div>\n";
+	hit_header_div('summary', $project);
 	print "<table cellspacing=\"0\">\n";
+
+	my $taglist = git_read_refs("refs/heads");
 	my $alternate = 0;
 	if (defined @$taglist) {
 		foreach my $entry (@$taglist) {
@@ -1684,9 +1683,7 @@ sub git_blob {
 			$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain");
 		}
 		git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
-		print "<div>" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
-		      "</div>\n";
+		git_header_div('commit', esc_html($co{'title'}), $hash_base);
 	} else {
 		print "<div class=\"page_nav\">\n" .
 		      "<br/><br/></div>\n" .
@@ -1740,9 +1737,7 @@ sub git_tree {
 	if (defined $hash_base && (my %co = git_read_commit($hash_base))) {
 		$base_key = ";hb=$hash_base";
 		git_page_nav('tree','', $hash_base);
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
-		      "</div>\n";
+		git_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
 	} else {
 		print "<div class=\"page_nav\">\n";
 		print "<br/><br/></div>\n";
@@ -1909,10 +1904,9 @@ sub git_log {
 	git_page_nav('log','', $hash,undef,undef, $paging_nav);
 
 	if (!@revlist) {
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
-		      "</div>\n";
 		my %co = git_read_commit($hash);
+
+		git_header_div('summary', $project);
 		print "<div class=\"page_body\"> Last change $co{'age_string'}.<br/><br/></div>\n";
 	}
 	for (my $i = ($page * 100); $i <= $#revlist; $i++) {
@@ -1924,10 +1918,10 @@ sub git_log {
 		my %co = git_read_commit($commit);
 		next if !%co;
 		my %ad = date_str($co{'author_epoch'});
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "title"},
-		      "<span class=\"age\">$co{'age_string'}</span>" . esc_html($co{'title'}) . $ref) . "\n";
-		print "</div>\n";
+		git_header_div('commit',
+									 "<span class=\"age\">$co{'age_string'}</span>" .
+									 esc_html($co{'title'}) . $ref,
+									 $commit);
 		print "<div class=\"title_text\">\n" .
 		      "<div class=\"log_link\">\n" .
 		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") .
@@ -1999,13 +1993,9 @@ sub git_commit {
 							 $formats_nav);
 
 	if (defined $co{'parent'}) {
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
-		      "</div>\n";
+		git_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
 	} else {
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash"), -class => "title"}, esc_html($co{'title'})) . "\n" .
-		      "</div>\n";
+		git_header_div('tree', esc_html($co{'title'}), $co{'tree'}, $hash);
 	}
 	print "<div class=\"title_text\">\n" .
 	      "<table cellspacing=\"0\">\n";
@@ -2171,9 +2161,7 @@ sub git_blobdiff {
 		my $formats_nav = 
 			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blobdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
 		git_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
-		print "<div>\n" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . "\n" .
-		      "</div>\n";
+		git_header_div('commit', esc_html($co{'title'}), $hash_base);
 	} else {
 		print "<div class=\"page_nav\">\n" .
 		      "<br/><br/></div>\n" .
@@ -2225,9 +2213,7 @@ sub git_commitdiff {
 	my $formats_nav =
 		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
 	git_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($co{'title'}) . $ref) . "\n" .
-	      "</div>\n";
+	git_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
 	print "<div class=\"page_body\">\n";
 	my $comment = $co{'comment'};
 	my $empty = 0;
@@ -2357,9 +2343,7 @@ sub git_history {
 	my $refs = read_info_ref();
 	git_header_html();
 	git_page_nav('','', $hash_base,$co{'tree'},$hash_base);
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) . "\n" .
-	      "</div>\n";
+	git_header_div('commit', esc_html($co{'title'}), $hash_base);
 	if (!defined $hash && defined $file_name) {
 		$hash = git_get_hash_by_path($hash_base, $file_name);
 	}
@@ -2440,10 +2424,8 @@ sub git_search {
 	}
 	git_header_html();
 	git_page_nav('','', $hash,$co{'tree'},$hash);
+	git_header_div('commit', esc_html($co{'title'}), $hash);
 
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash"), -class => "title"}, esc_html($co{'title'})) . "\n" .
-	      "</div>\n";
 	print "<table cellspacing=\"0\">\n";
 	my $alternate = 0;
 	if ($commit_search) {
@@ -2570,10 +2552,8 @@ sub git_shortlog {
 
 	git_header_html();
 	git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
+	git_header_div('summary', $project);
 
-	print "<div>\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary"), -class => "title"}, "&nbsp;") .
-	      "</div>\n";
 	print "<table cellspacing=\"0\">\n";
 	my $alternate = 0;
 	for (my $i = ($page * 100); $i <= $#revlist; $i++) {
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 16] gitweb: Remove characters entities entirely when shortening string
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (14 preceding siblings ...)
  2006-07-30 18:32 ` [PATCH 15] gitweb: Headers refactoring - use git_header_div for header divs Jakub Narebski
@ 2006-07-30 20:36 ` Jakub Narebski
  2006-07-31 16:59   ` Jakub Narebski
  2006-07-31 18:58   ` [PATCH 16b] gitweb: Remove characters entities entirely when shortening string -- correction Jakub Narebski
  2006-07-31  0:21 ` [PATCH 17] gitweb: Ref refactoring - use git_get_referencing for marking tagged/head commits Jakub Narebski
                   ` (7 subsequent siblings)
  23 siblings, 2 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-30 20:36 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Yet another error noticed due to strict validation 
of application/xhtml+xml by Mozilla.

 gitweb/gitweb.cgi |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 06a6930..83ea97a 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -776,6 +776,7 @@ sub chop_str {
 	my $tail = $2;
 	if (length($tail) > 4) {
 		$tail = " ...";
+		$body =~ s/&[^;]$//; # remove chopped character entities
 	}
 	return "$body$tail";
 }
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 17] gitweb: Ref refactoring - use git_get_referencing for marking tagged/head commits
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (15 preceding siblings ...)
  2006-07-30 20:36 ` [PATCH 16] gitweb: Remove characters entities entirely when shortening string Jakub Narebski
@ 2006-07-31  0:21 ` Jakub Narebski
  2006-07-31  9:22 ` [PATCH 18] gitweb: Refactor generation of shortlog, tags and heads body Jakub Narebski
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31  0:21 UTC (permalink / raw)
  To: git

Use git_get_referencing to get HTML code for markers showing which
refs (tags and heads) point to current commit.  It would be much
easier to change format of markers in one or two places than thorough
the gitweb.cgi file.

Added comment about read_info_ref subroutine: for $type == "" (empty
argument) it saves only last path part of ref name e.g. from
'refs/heads/jn/gitweb' it would leave only 'gitweb'.

Some reordering.  Added $ref in one place.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |   53 ++++++++++++++++++++++-------------------------------
 1 files changed, 22 insertions(+), 31 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 83ea97a..dab6068 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1024,6 +1024,8 @@ sub read_info_ref {
 	open my $fd, "$projectroot/$project/info/refs" or return;
 	while (my $line = <$fd>) {
 		chomp $line;
+		# attention: for $type == "" it saves only last path part of ref name
+		# e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
 		if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
 			if (defined $refs{$1}) {
 				$refs{$1} .= " / $2";
@@ -1036,6 +1038,16 @@ sub read_info_ref {
 	return \%refs;
 }
 
+sub git_get_referencing {
+	my ($refs, $id) = @_;
+
+	if (defined $refs->{$id}) {
+		return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
+	} else {
+		return "";
+	}
+}
+
 sub git_read_refs {
 	my $ref_dir = shift;
 	my @reflist;
@@ -1151,10 +1163,7 @@ sub git_summary {
 		}
 		$alternate ^= 1;
 		if ($i-- > 0) {
-			my $ref = "";
-			if (defined $refs->{$commit}) {
-				$ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
-			}
+			my $ref = git_get_referencing($refs, $commit);
 			print "<td><i>$co{'age_string'}</i></td>\n" .
 			      "<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
 			      "<td>";
@@ -1728,10 +1737,7 @@ sub git_tree {
 	$/ = "\n";
 
 	my $refs = read_info_ref();
-	my $ref = "";
-	if (defined $refs->{$hash_base}) {
-		$ref = " <span class=\"tag\">" . esc_html($refs->{$hash_base}) . "</span>";
-	}
+	my $ref = git_get_referencing($refs, $hash_base);
 	git_header_html();
 	my $base_key = "";
 	my $base = "";
@@ -1912,10 +1918,7 @@ sub git_log {
 	}
 	for (my $i = ($page * 100); $i <= $#revlist; $i++) {
 		my $commit = $revlist[$i];
-		my $ref = "";
-		if (defined $refs->{$commit}) {
-			$ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
-		}
+		my $ref = git_get_referencing($refs, $commit);
 		my %co = git_read_commit($commit);
 		next if !%co;
 		my %ad = date_str($co{'author_epoch'});
@@ -1979,16 +1982,13 @@ sub git_commit {
 		$expires = "+1d";
 	}
 	my $refs = read_info_ref();
-	my $ref = "";
-	if (defined $refs->{$co{'id'}}) {
-		$ref = " <span class=\"tag\">" . esc_html($refs->{$co{'id'}}) . "</span>";
-	}
-	git_header_html(undef, $expires);
+	my $ref = git_get_referencing($refs, $co{'id'});
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
 		$formats_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;hb=$parent;f=$file_name")}, "blame");
 	}
+	git_header_html(undef, $expires);
 	git_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff', 
 							 $hash, $co{'tree'}, $hash,
 							 $formats_nav);
@@ -1996,7 +1996,7 @@ sub git_commit {
 	if (defined $co{'parent'}) {
 		git_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
 	} else {
-		git_header_div('tree', esc_html($co{'title'}), $co{'tree'}, $hash);
+		git_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash);
 	}
 	print "<div class=\"title_text\">\n" .
 	      "<table cellspacing=\"0\">\n";
@@ -2206,13 +2206,10 @@ sub git_commitdiff {
 		$expires = "+1d";
 	}
 	my $refs = read_info_ref();
-	my $ref = "";
-	if (defined $refs->{$co{'id'}}) {
-		$ref = " <span class=\"tag\">" . esc_html($refs->{$co{'id'}}) . "</span>";
-	}
-	git_header_html(undef, $expires);
+	my $ref = git_get_referencing($refs, $co{'id'});
 	my $formats_nav =
 		$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff_plain;h=$hash;hp=$hash_parent")}, "plain");
+	git_header_html(undef, $expires);
 	git_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav);
 	git_header_div('commit', esc_html($co{'title'}) . $ref, $hash);
 	print "<div class=\"page_body\">\n";
@@ -2364,10 +2361,7 @@ sub git_history {
 			if (!%co) {
 				next;
 			}
-			my $ref = "";
-			if (defined $refs->{$commit}) {
-				$ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
-			}
+			my $ref = git_get_referencing($refs, $commit);
 			if ($alternate) {
 				print "<tr class=\"dark\">\n";
 			} else {
@@ -2559,10 +2553,7 @@ sub git_shortlog {
 	my $alternate = 0;
 	for (my $i = ($page * 100); $i <= $#revlist; $i++) {
 		my $commit = $revlist[$i];
-		my $ref = "";
-		if (defined $refs->{$commit}) {
-			$ref = " <span class=\"tag\">" . esc_html($refs->{$commit}) . "</span>";
-		}
+		my $ref = git_get_referencing($refs, $commit);
 		my %co = git_read_commit($commit);
 		my %ad = date_str($co{'author_epoch'});
 		if ($alternate) {
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 18] gitweb: Refactor generation of shortlog, tags and heads body
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (16 preceding siblings ...)
  2006-07-31  0:21 ` [PATCH 17] gitweb: Ref refactoring - use git_get_referencing for marking tagged/head commits Jakub Narebski
@ 2006-07-31  9:22 ` Jakub Narebski
  2006-07-31 16:33 ` [PATCH 19] gitweb: No need to quote path for list version of open "-|" Jakub Narebski
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31  9:22 UTC (permalink / raw)
  To: git

Add git_shortlog_body, git_tags_body and git_heads_body to generate
table with shortlog, tags and heads respectively in git_summary and
git_shortlog, git_tags, git_heads respectively.

Better support for lightweight tags in git_read_refs; currently only
lightweight tag pointing to tag object is not resolved fully.

Shortlog, tags and heads body tables have proper class now (we could
use id instead of class).

Add support for showing full comment on mouseover to tags list when
comment is shortened, similar to how full title of commit was/is
shown on mouseover when title was shortened.  Changed layout of tags
table to better show lightweight tags.

Add showing which branch (head) is current branch (current head),
using "current_head" class (we could use id instead).

Corrected "</table\n>" and hit_header_div instead of git_header_div.


Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Largest patch in the series. Refactoring and unification.
New features (table classes, current head) are fairly unintrusive.

 gitweb/gitweb.cgi |  383 ++++++++++++++++++++++++-----------------------------
 gitweb/gitweb.css |   10 +
 2 files changed, 184 insertions(+), 209 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index dab6068..d209af0 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1102,6 +1102,10 @@ sub git_read_refs {
 			$ref_item{'refid'} = $ref_id;
 			$ref_item{'epoch'} = $co{'committer_epoch'};
 			$ref_item{'age'} = $co{'age_string'};
+		} else {
+			$ref_item{'reftype'} = $type;
+			$ref_item{'name'} = $ref_file;
+			$ref_item{'refid'} = $ref_id;
 		}
 
 		push @reflist, \%ref_item;
@@ -1111,6 +1115,156 @@ sub git_read_refs {
 	return \@reflist;
 }
 
+sub git_shortlog_body {
+	# uses global variable $project
+	my ($revlist, $from, $to, $refs, $extra) = @_;
+	$from = 0 unless defined $from;
+	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
+
+	print "<table class=\"shortlog\" cellspacing=\"0\">\n";
+	my $alternate = 0;
+	for (my $i = $from; $i <= $to; $i++) {
+		my $commit = $revlist->[$i];
+		#my $ref = defined $refs ? git_get_referencing($refs, $commit) : '';
+		my $ref = git_get_referencing($refs, $commit);
+		my %co = git_read_commit($commit);
+		my %ad = date_str($co{'author_epoch'});
+		if ($alternate) {
+			print "<tr class=\"dark\">\n";
+		} else {
+			print "<tr class=\"light\">\n";
+		}
+		$alternate ^= 1;
+		# git_summary() used print "<td><i>$co{'age_string'}</i></td>\n" .
+		print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
+		      "<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
+		      "<td>";
+		if (length($co{'title_short'}) < length($co{'title'})) {
+			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"),
+			               -class => "list", -title => "$co{'title'}"},
+			      "<b>" . esc_html($co{'title_short'}) . "$ref</b>");
+		} else {
+			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"),
+			               -class => "list"},
+			      "<b>" . esc_html($co{'title'}) . "$ref</b>");
+		}
+		print "</td>\n" .
+		      "<td class=\"link\">" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") . " | " .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$commit")}, "commitdiff") .
+		      "</td>\n" .
+		      "</tr>\n";
+	}
+	if (defined $extra) {
+		print "<tr>\n" .
+		      "<td colspan=\"4\">$extra</td>\n" .
+		      "</tr>\n";
+	}
+	print "</table>\n";
+}
+
+sub git_tags_body {
+	# uses global variable $project
+	my ($taglist, $from, $to, $extra) = @_;
+	$from = 0 unless defined $from;
+	$to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
+
+	print "<table class=\"tags\" cellspacing=\"0\">\n";
+	my $alternate = 0;
+	for (my $i = $from; $i <= $to; $i++) {
+		my $entry = $taglist->[$i];
+		my %tag = %$entry;
+		my $comment_lines = $tag{'comment'};
+		my $comment = shift @$comment_lines;
+		my $comment_short;
+		if (defined $comment) {
+			$comment_short = chop_str($comment, 30, 5);
+		}
+		if ($alternate) {
+			print "<tr class=\"dark\">\n";
+		} else {
+			print "<tr class=\"light\">\n";
+		}
+		$alternate ^= 1;
+		print "<td><i>$tag{'age'}</i></td>\n" .
+		      "<td>" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}"),
+		               -class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
+		      "</td>\n" .
+		      "<td>";
+		if (defined $comment) {
+			if (length($comment_short) < length($comment)) {
+				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}"),
+				               -class => "list", -title => $comment}, $comment_short);
+			} else {
+				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}"),
+				               -class => "list"}, $comment);
+			}
+		}
+		print "</td>\n" .
+		      "<td class=\"selflink\">";
+		if ($tag{'type'} eq "tag") {
+			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag");
+		} else {
+			print "&nbsp;";
+		}
+		print "</td>\n" .
+		      "<td class=\"link\">" . " | " .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
+		if ($tag{'reftype'} eq "commit") {
+			print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
+			      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
+		} elsif ($tag{'reftype'} eq "blob") {
+			print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$tag{'refid'}")}, "raw");
+		}
+		print "</td>\n" .
+		      "</tr>";
+	}
+	if (defined $extra) {
+		print "<tr>\n" .
+		      "<td colspan=\"5\">$extra</td>\n" .
+		      "</tr>\n";
+	}
+	print "</table>\n";
+}
+
+sub git_heads_body {
+	# uses global variable $project
+	my ($taglist, $head, $from, $to, $extra) = @_;
+	$from = 0 unless defined $from;
+	$to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
+
+	print "<table class=\"heads\" cellspacing=\"0\">\n";
+	my $alternate = 0;
+	for (my $i = $from; $i <= $to; $i++) {
+		my $entry = $taglist->[$i];
+		my %tag = %$entry;
+		my $curr = $tag{'id'} eq $head;
+		if ($alternate) {
+			print "<tr class=\"dark\">\n";
+		} else {
+			print "<tr class=\"light\">\n";
+		}
+		$alternate ^= 1;
+		print "<td><i>$tag{'age'}</i></td>\n" .
+		      ($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}"),
+		               -class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
+		      "</td>\n" .
+		      "<td class=\"link\">" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") . " | " .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'name'}")}, "log") .
+		      "</td>\n" .
+		      "</tr>";
+	}
+	if (defined $extra) {
+		print "<tr>\n" .
+		      "<td colspan=\"3\">$extra</td>\n" .
+		      "</tr>\n";
+	}
+	print "</table>\n";
+}
+
 sub git_summary {
 	my $descr = git_read_description($project) || "none";
 	my $head = git_read_head($project);
@@ -1139,138 +1293,36 @@ sub git_summary {
 	my $refs = read_info_ref();
 	git_header_html();
 	git_page_nav('summary','', $head);
+
 	print "<div class=\"title\">&nbsp;</div>\n";
 	print "<table cellspacing=\"0\">\n" .
 	      "<tr><td>description</td><td>" . esc_html($descr) . "</td></tr>\n" .
 	      "<tr><td>owner</td><td>$owner</td></tr>\n" .
 	      "<tr><td>last change</td><td>$cd{'rfc2822'}</td></tr>\n" .
 	      "</table>\n";
+
 	open my $fd, "-|", $GIT, "rev-list", "--max-count=17", git_read_head($project) 
 		or die_error(undef, "Open git-rev-list failed.");
 	my @revlist = map { chomp; $_ } <$fd>;
 	close $fd;
 	git_header_div('shortlog');
-	my $i = 16;
-	print "<table cellspacing=\"0\">\n";
-	my $alternate = 0;
-	foreach my $commit (@revlist) {
-		my %co = git_read_commit($commit);
-		my %ad = date_str($co{'author_epoch'});
-		if ($alternate) {
-			print "<tr class=\"dark\">\n";
-		} else {
-			print "<tr class=\"light\">\n";
-		}
-		$alternate ^= 1;
-		if ($i-- > 0) {
-			my $ref = git_get_referencing($refs, $commit);
-			print "<td><i>$co{'age_string'}</i></td>\n" .
-			      "<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
-			      "<td>";
-			if (length($co{'title_short'}) < length($co{'title'})) {
-				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "list", -title => "$co{'title'}"},
-				      "<b>" . esc_html($co{'title_short'}) . "$ref</b>");
-			} else {
-				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "list"},
-				      "<b>" . esc_html($co{'title'}) . "$ref</b>");
-			}
-			print "</td>\n" .
-			      "<td class=\"link\">" .
-			      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") .
-			      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$commit")}, "commitdiff") .
-			      "</td>\n" .
-			      "</tr>";
-		} else {
-			print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "...") . "</td>\n" .
-			"</tr>";
-			last;
-		}
-	}
-	print "</table\n>";
+	git_shortlog_body(\@revlist, 0, 15, $refs,
+	                  $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "..."));
 
 	my $taglist = git_read_refs("refs/tags");
 	if (defined @$taglist) {
 		git_header_div('tags');
-		my $i = 16;
-		print "<table cellspacing=\"0\">\n";
-		my $alternate = 0;
-		foreach my $entry (@$taglist) {
-			my %tag = %$entry;
-			my $comment_lines = $tag{'comment'};
-			my $comment = shift @$comment_lines;
-			if (defined($comment)) {
-				$comment = chop_str($comment, 30, 5);
-			}
-			if ($alternate) {
-				print "<tr class=\"dark\">\n";
-			} else {
-				print "<tr class=\"light\">\n";
-			}
-			$alternate ^= 1;
-			if ($i-- > 0) {
-				print "<td><i>$tag{'age'}</i></td>\n" .
-				      "<td>" .
-				      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}"), -class => "list"},
-				      "<b>" . esc_html($tag{'name'}) . "</b>") .
-				      "</td>\n" .
-				      "<td>";
-				if (defined($comment)) {
-					print $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, esc_html($comment));
-				}
-				print "</td>\n" .
-				      "<td class=\"link\">";
-				if ($tag{'type'} eq "tag") {
-					print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag") . " | ";
-				}
-				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
-				if ($tag{'reftype'} eq "commit") {
-					print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
-					      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
-				}
-				print "</td>\n" .
-				      "</tr>";
-			} else {
-				print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tags")}, "...") . "</td>\n" .
-				"</tr>";
-				last;
-			}
-		}
-		print "</table\n>";
+		git_tags_body($taglist, 0, 15,
+		              $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tags")}, "..."));
 	}
 
 	my $headlist = git_read_refs("refs/heads");
 	if (defined @$headlist) {
 		git_header_div('heads');
-		my $i = 16;
-		print "<table cellspacing=\"0\">\n";
-		my $alternate = 0;
-		foreach my $entry (@$headlist) {
-			my %tag = %$entry;
-			if ($alternate) {
-				print "<tr class=\"dark\">\n";
-			} else {
-				print "<tr class=\"light\">\n";
-			}
-			$alternate ^= 1;
-			if ($i-- > 0) {
-				print "<td><i>$tag{'age'}</i></td>\n" .
-				      "<td>" .
-				      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}"), -class => "list"},
-				      "<b>" . esc_html($tag{'name'}) . "</b>") .
-				      "</td>\n" .
-				      "<td class=\"link\">" .
-				      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
-				      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'name'}")}, "log") .
-				      "</td>\n" .
-				      "</tr>";
-			} else {
-				print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads")}, "...") . "</td>\n" .
-				"</tr>";
-				last;
-			}
-		}
-		print "</table\n>";
+		git_heads_body($taglist, $head, 0, 15,
+		               $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads")}, "..."));
 	}
+
 	git_footer_html();
 }
 
@@ -1472,48 +1524,11 @@ sub git_tags {
 	git_header_html();
 	git_page_nav('','', $head,undef,$head);
 	git_header_div('summary', $project);
-	print "<table cellspacing=\"0\">\n";
 
 	my $taglist = git_read_refs("refs/tags");
-	my $alternate = 0;
 	if (defined @$taglist) {
-		foreach my $entry (@$taglist) {
-			my %tag = %$entry;
-			my $comment_lines = $tag{'comment'};
-			my $comment = shift @$comment_lines;
-			if (defined($comment)) {
-				$comment = chop_str($comment, 30, 5);
-			}
-			if ($alternate) {
-				print "<tr class=\"dark\">\n";
-			} else {
-				print "<tr class=\"light\">\n";
-			}
-			$alternate ^= 1;
-			print "<td><i>$tag{'age'}</i></td>\n" .
-			      "<td>" .
-			      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}"), -class => "list"},
-			      "<b>" . esc_html($tag{'name'}) . "</b>") .
-			      "</td>\n" .
-			      "<td>";
-			if (defined($comment)) {
-				print $cgi->a({-class => "list", -href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, $comment);
-			}
-			print "</td>\n" .
-			      "<td class=\"link\">";
-			if ($tag{'type'} eq "tag") {
-				print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag") . " | ";
-			}
-			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
-			if ($tag{'reftype'} eq "commit") {
-				print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
-				      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
-			}
-			print "</td>\n" .
-			      "</tr>";
-		}
+		git_tags_body($taglist);
 	}
-	print "</table\n>";
 	git_footer_html();
 }
 
@@ -1521,32 +1536,13 @@ sub git_heads {
 	my $head = git_read_head($project);
 	git_header_html();
 	git_page_nav('','', $head,undef,$head);
-	hit_header_div('summary', $project);
-	print "<table cellspacing=\"0\">\n";
+	git_header_div('summary', $project);
 
 	my $taglist = git_read_refs("refs/heads");
 	my $alternate = 0;
 	if (defined @$taglist) {
-		foreach my $entry (@$taglist) {
-			my %tag = %$entry;
-			if ($alternate) {
-				print "<tr class=\"dark\">\n";
-			} else {
-				print "<tr class=\"light\">\n";
-			}
-			$alternate ^= 1;
-			print "<td><i>$tag{'age'}</i></td>\n" .
-			      "<td>" .
-			      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}"), -class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
-			      "</td>\n" .
-			      "<td class=\"link\">" .
-			      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
-			      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'name'}")}, "log") .
-			      "</td>\n" .
-			      "</tr>";
-		}
+		git_heads_body($taglist, $head);
 	}
-	print "</table\n>";
 	git_footer_html();
 }
 
@@ -2544,48 +2540,19 @@ sub git_shortlog {
 	close $fd;
 
 	my $paging_nav = git_get_paging_nav('shortlog', $hash, $head, $page, $#revlist);
+	my $next_link = '';
+	if ($#revlist >= (100 * ($page+1)-1)) {
+		$next_link =
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page+1)),
+			         -title => "Alt-n"}, "next");
+	}
+
 
 	git_header_html();
 	git_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
 	git_header_div('summary', $project);
 
-	print "<table cellspacing=\"0\">\n";
-	my $alternate = 0;
-	for (my $i = ($page * 100); $i <= $#revlist; $i++) {
-		my $commit = $revlist[$i];
-		my $ref = git_get_referencing($refs, $commit);
-		my %co = git_read_commit($commit);
-		my %ad = date_str($co{'author_epoch'});
-		if ($alternate) {
-			print "<tr class=\"dark\">\n";
-		} else {
-			print "<tr class=\"light\">\n";
-		}
-		$alternate ^= 1;
-		print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
-		      "<td><i>" . esc_html(chop_str($co{'author_name'}, 10)) . "</i></td>\n" .
-		      "<td>";
-		if (length($co{'title_short'}) < length($co{'title'})) {
-			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "list", -title => "$co{'title'}"},
-			      "<b>" . esc_html($co{'title_short'}) . "$ref</b>");
-		} else {
-			print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit"), -class => "list"},
-			      "<b>" . esc_html($co{'title_short'}) . "$ref</b>");
-		}
-		print "</td>\n" .
-		      "<td class=\"link\">" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$commit")}, "commit") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$commit")}, "commitdiff") .
-		      "</td>\n" .
-		      "</tr>";
-	}
-	if ($#revlist >= (100 * ($page+1)-1)) {
-		print "<tr>\n" .
-		      "<td>" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$hash;pg=" . ($page+1)), -title => "Alt-n"}, "next") .
-		      "</td>\n" .
-		      "</tr>\n";
-	}
-	print "</table\n>";
+	git_shortlog_body(\@revlist, ($page * 100), $#revlist, $refs, $next_link);
+
 	git_footer_html();
 }
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index fffdb13..460e728 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -181,12 +181,16 @@ td {
 	vertical-align: top;
 }
 
-td.link {
+td.link, td.selflink {
 	padding: 2px 5px;
 	font-family: sans-serif;
 	font-size: 10px;
 }
 
+td.selflink {
+	padding-right: 0px;
+}
+
 td.sha1 {
 	font-family: monospace;
 }
@@ -196,6 +200,10 @@ td.error {
 	background-color: yellow;
 }
 
+td.current_head {
+	text-decoration: underline;
+}
+
 table.diff_tree span.file_status.new {
 	color: #008000;
 }
-- 
1.4.0

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-29 20:51 ` [PATCH 2] gitweb: Use list for of open for running git commands, thorougly Jakub Narebski
  2006-07-30  2:12   ` Jakub Narebski
@ 2006-07-31 10:53   ` Junio C Hamano
  2006-07-31 11:42     ` Jakub Narebski
  2006-07-31 12:59     ` Jakub Narebski
  1 sibling, 2 replies; 54+ messages in thread
From: Junio C Hamano @ 2006-07-31 10:53 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

This, together with PATCH 6, seems to break "history" link.
Visit a repository (summary page), click on "tree" on the second
line, and click on "history" (on any blob or tree).

I might have made a merge mistake while squashing PATCH 2 and
PATCH 6 into a single commit.

BTW, please be careful on trailing whitespaces.

I've wasted quite a lot of time yesterday just fixing up
trailing whitespaces from your patches (although the first in
your series was "whitespace cleanup" X-<).

I usually apply patches with whitespace=strip, unless there is a
compelling reason not to (e.g. when the patch is to add a
testcase of diff output which would inevitably have trailing
whitespaces when a context contains an empty line), which means
if you have a series of patches whose later patch updates lines
with trailing whitespaces an earlier patch introduced the patch
would not apply.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-31 10:53   ` Junio C Hamano
@ 2006-07-31 11:42     ` Jakub Narebski
  2006-07-31 12:10       ` Jakub Narebski
  2006-07-31 12:59     ` Jakub Narebski
  1 sibling, 1 reply; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 11:42 UTC (permalink / raw)
  To: git

Junio C Hamano wrote:

> This, together with PATCH 6, seems to break "history" link.
> Visit a repository (summary page), click on "tree" on the second
> line, and click on "history" (on any blob or tree).

Strange... returning this part of git_history to previous version, i.e.

  open my $fd, "-|",
    "$GIT rev-list --full-history $hash_base -- \'$file_name\'";

still gives no history. Curious. Will examine that...

> BTW, please be careful on trailing whitespaces.

I'm sorry for that. I have forgot to turn-on default git pre-commit it clone
of git repository I'm not working on...

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-31 11:42     ` Jakub Narebski
@ 2006-07-31 12:10       ` Jakub Narebski
  2006-07-31 12:38         ` Jakub Narebski
  0 siblings, 1 reply; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 12:10 UTC (permalink / raw)
  To: git

Jakub Narebski wrote:

> Junio C Hamano wrote:
> 
>> This, together with PATCH 6, seems to break "history" link.
>> Visit a repository (summary page), click on "tree" on the second
>> line, and click on "history" (on any blob or tree).
> 
> Strange... returning this part of git_history to previous version, i.e.
> 
>   open my $fd, "-|",
>     "$GIT rev-list --full-history $hash_base -- \'$file_name\'";
> 
> still gives no history. Curious. Will examine that...

Curiouser and curiouser. It seems that somehow --full-history option 
(which was never documented by the way) got lost somewhere.

  ~/git> git merge-base --all next HEAD
  688a75071490101dbc660e3304aafb7a13e28807

  ~/git> git log --full-history HEAD -- gitweb/test/file+plus+sign
  fatal: unrecognized argument: --full-history

(same with 'git rev-list --full-history HEAD -- gitweb/test/file+plus+sign',
but it shows help instead of simply croaking like git-log).

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-31 12:10       ` Jakub Narebski
@ 2006-07-31 12:38         ` Jakub Narebski
  0 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 12:38 UTC (permalink / raw)
  To: git

Jakub Narebski wrote:

> Jakub Narebski wrote:
> 
>> Junio C Hamano wrote:
>> 
>>> This, together with PATCH 6, seems to break "history" link.
>>> Visit a repository (summary page), click on "tree" on the second
>>> line, and click on "history" (on any blob or tree).
>> 
>> Strange... returning this part of git_history to previous version, i.e.
>> 
>>   open my $fd, "-|",
>>     "$GIT rev-list --full-history $hash_base -- \'$file_name\'";
>> 
>> still gives no history. Curious. Will examine that...
> 
> Curiouser and curiouser. It seems that somehow --full-history option 
> (which was never documented by the way) got lost somewhere.

Ooops. I've forgot that '--full-history' option was introduced after v1.4.0
(which I use).

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 2] gitweb: Use list for of open for running git commands, thorougly.
  2006-07-31 10:53   ` Junio C Hamano
  2006-07-31 11:42     ` Jakub Narebski
@ 2006-07-31 12:59     ` Jakub Narebski
  1 sibling, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 12:59 UTC (permalink / raw)
  To: git

Junio C Hamano wrote:

> This, together with PATCH 6, seems to break "history" link.
> Visit a repository (summary page), click on "tree" on the second
> line, and click on "history" (on any blob or tree).

It works for me (both --full-history and gitweb) for git 1.4.1.1, although
--full-history doesn't seem to add anything for this version of git:

  ~/git> time git rev-list HEAD -- gitweb/test/file+plus+sign
  0a8f4f0020cb35095005852c0797f0b90e9ebb74

  real    0m2.562s
  user    0m2.412s
  sys     0m0.024s


  ~/git> time git rev-list --full-history HEAD -- gitweb/test/file+plus+sign
  0a8f4f0020cb35095005852c0797f0b90e9ebb74

  real    0m8.564s
  user    0m7.212s
  sys     0m0.068s

while correct result should be

  ~/git> time git rev-list HEAD -- gitweb/test/file+plus+sign \
                                   test/file+plus+sign
  0a8f4f0020cb35095005852c0797f0b90e9ebb74
  85852d44e48c1d1c6d815cc5fccf1b580f2f2cad
  cc3245b6512a01d74c0fd460d762ba8a1e8b968a

  real    0m2.565s
  user    0m2.452s
  sys     0m0.008s

git version 1.4.1.1
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 19] gitweb: No need to quote path for list version of open "-|"
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (17 preceding siblings ...)
  2006-07-31  9:22 ` [PATCH 18] gitweb: Refactor generation of shortlog, tags and heads body Jakub Narebski
@ 2006-07-31 16:33 ` Jakub Narebski
  2006-07-31 18:55   ` Junio C Hamano
  2006-07-31 18:48 ` [PATCH 20] gitweb: Reordering code and dividing it into categories Jakub Narebski
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 16:33 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index d209af0..f7fe28a 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -2347,7 +2347,7 @@ sub git_history {
 	git_print_page_path($file_name, $ftype);
 
 	open my $fd, "-|",
-		$GIT, "rev-list", "--full-history", $hash_base, "--", "\'$file_name\'";
+		$GIT, "rev-list", "--full-history", $hash_base, "--", $file_name;
 	print "<table cellspacing=\"0\">\n";
 	my $alternate = 0;
 	while (my $line = <$fd>) {
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 16] gitweb: Remove characters entities entirely when shortening string
  2006-07-30 20:36 ` [PATCH 16] gitweb: Remove characters entities entirely when shortening string Jakub Narebski
@ 2006-07-31 16:59   ` Jakub Narebski
  2006-07-31 18:58   ` [PATCH 16b] gitweb: Remove characters entities entirely when shortening string -- correction Jakub Narebski
  1 sibling, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 16:59 UTC (permalink / raw)
  To: git

Jakub Narebski wrote:

> --- a/gitweb/gitweb.cgi
> +++ b/gitweb/gitweb.cgi
> @@ -776,6 +776,7 @@ sub chop_str {
>       my $tail = $2;
>       if (length($tail) > 4) {
>               $tail = " ...";
> +             $body =~ s/&[^;]$//; # remove chopped character entities
>       }
>       return "$body$tail";
>  }

Of course it should be

+               $body =~ s/&[^;]*$//; # remove chopped character entities

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 20] gitweb: Reordering code and dividing it into categories
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (18 preceding siblings ...)
  2006-07-31 16:33 ` [PATCH 19] gitweb: No need to quote path for list version of open "-|" Jakub Narebski
@ 2006-07-31 18:48 ` Jakub Narebski
  2006-07-31 19:22   ` [PATCH 20 (amend)] " Jakub Narebski
  2006-07-31 21:46 ` [PATCH] gitweb: use a hash to lookup the sub for an action Matthias Lederhofer
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 18:48 UTC (permalink / raw)
  To: git

Reorder gitweb code around, divide it into sections (categories) and
add some comments.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This patch is superficially large, as it only moves code around,
and add only a little.

 gitweb/gitweb.cgi | 1672 ++++++++++++++++++++++++++++-------------------------
 1 files changed, 898 insertions(+), 774 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index cb6af39..2d710ae 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -160,19 +160,65 @@ if (defined $searchtext) {
 	$searchtext = quotemeta $searchtext;
 }
 
-sub validate_input {
-	my $input = shift;
-
-	if ($input =~ m/^[0-9a-fA-F]{40}$/) {
-		return $input;
-	}
-	if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) {
-		return undef;
-	}
-	if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) {
-		return undef;
-	}
-	return $input;
+# dispatch
+if (!defined $action || $action eq "summary") {
+	git_summary();
+	exit;
+} elsif ($action eq "heads") {
+	git_heads();
+	exit;
+} elsif ($action eq "tags") {
+	git_tags();
+	exit;
+} elsif ($action eq "blob") {
+	git_blob();
+	exit;
+} elsif ($action eq "blob_plain") {
+	git_blob_plain();
+	exit;
+} elsif ($action eq "tree") {
+	git_tree();
+	exit;
+} elsif ($action eq "rss") {
+	git_rss();
+	exit;
+} elsif ($action eq "commit") {
+	git_commit();
+	exit;
+} elsif ($action eq "log") {
+	git_log();
+	exit;
+} elsif ($action eq "blobdiff") {
+	git_blobdiff();
+	exit;
+} elsif ($action eq "blobdiff_plain") {
+	git_blobdiff_plain();
+	exit;
+} elsif ($action eq "commitdiff") {
+	git_commitdiff();
+	exit;
+} elsif ($action eq "commitdiff_plain") {
+	git_commitdiff_plain();
+	exit;
+} elsif ($action eq "history") {
+	git_history();
+	exit;
+} elsif ($action eq "search") {
+	git_search();
+	exit;
+} elsif ($action eq "shortlog") {
+	git_shortlog();
+	exit;
+} elsif ($action eq "tag") {
+	git_tag();
+	exit;
+} elsif ($action eq "blame") {
+	git_blame2();
+	exit;
+} else {
+	undef $action;
+	die_error(undef, "Unknown action.");
+	exit;
 }
 
 if (!defined $action || $action eq "summary") {
@@ -235,6 +281,24 @@ if (!defined $action || $action eq "summ
 	exit;
 }
 
+## ======================================================================
+## validation, quoting/unquoting and escaping
+
+sub validate_input {
+	my $input = shift;
+
+	if ($input =~ m/^[0-9a-fA-F]{40}$/) {
+		return $input;
+	}
+	if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) {
+		return undef;
+	}
+	if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) {
+		return undef;
+	}
+	return $input;
+}
+
 # quote unsafe chars, but keep the slash, even when it's not
 # correct, but quoted slashes look too horrible in bookmarks
 sub esc_param {
@@ -264,6 +328,29 @@ sub unquote {
 	return $str;
 }
 
+## ----------------------------------------------------------------------
+## HTML aware string manipulation
+
+sub chop_str {
+	my $str = shift;
+	my $len = shift;
+	my $add_len = shift || 10;
+
+	# allow only $len chars, but don't cut a word if it would fit in $add_len
+	# if it doesn't fit, cut it if it's still longer than the dots we would add
+	$str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/;
+	my $body = $1;
+	my $tail = $2;
+	if (length($tail) > 4) {
+		$tail = " ...";
+		$body =~ s/&[^;]*$//; # remove chopped character entities
+	}
+	return "$body$tail";
+}
+
+## ----------------------------------------------------------------------
+## functions returning short strings
+
 # CSS class for given age value (in seconds)
 sub age_class {
 	my $age = shift;
@@ -277,202 +364,108 @@ sub age_class {
 	}
 }
 
-sub git_header_html {
-	my $status = shift || "200 OK";
-	my $expires = shift;
+# convert age in seconds to "nn units ago" string
+sub age_string {
+	my $age = shift;
+	my $age_str;
 
-	my $title = "$site_name git";
-	if (defined $project) {
-		$title .= " - $project";
-		if (defined $action) {
-			$title .= "/$action";
-			if (defined $file_name) {
-				$title .= " - $file_name";
-				if ($action eq "tree" && $file_name !~ m|/$|) {
-					$title .= "/";
-				}
-			}
-		}
-	}
-	my $content_type;
-	# require explicit support from the UA if we are to send the page as
-	# 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
-	# we have to do this because MSIE sometimes globs '*/*', pretending to
-	# support xhtml+xml but choking when it gets what it asked for.
-	if ($cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && $cgi->Accept('application/xhtml+xml') != 0) {
-		$content_type = 'application/xhtml+xml';
+	if ($age > 60*60*24*365*2) {
+		$age_str = (int $age/60/60/24/365);
+		$age_str .= " years ago";
+	} elsif ($age > 60*60*24*(365/12)*2) {
+		$age_str = int $age/60/60/24/(365/12);
+		$age_str .= " months ago";
+	} elsif ($age > 60*60*24*7*2) {
+		$age_str = int $age/60/60/24/7;
+		$age_str .= " weeks ago";
+	} elsif ($age > 60*60*24*2) {
+		$age_str = int $age/60/60/24;
+		$age_str .= " days ago";
+	} elsif ($age > 60*60*2) {
+		$age_str = int $age/60/60;
+		$age_str .= " hours ago";
+	} elsif ($age > 60*2) {
+		$age_str = int $age/60;
+		$age_str .= " min ago";
+	} elsif ($age > 2) {
+		$age_str = int $age;
+		$age_str .= " sec ago";
 	} else {
-		$content_type = 'text/html';
-	}
-	print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires);
-	print <<EOF;
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<!-- git web interface v$version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
-<!-- git core binaries version $git_version -->
-<head>
-<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
-<meta name="robots" content="index, nofollow"/>
-<title>$title</title>
-<link rel="stylesheet" type="text/css" href="$stylesheet"/>
-$rss_link
-</head>
-<body>
-EOF
-	print "<div class=\"page_header\">\n" .
-	      "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
-	      "<img src=\"$my_uri?" . esc_param("a=git-logo.png") . "\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
-	      "</a>\n";
-	print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
-	if (defined $project) {
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, esc_html($project));
-		if (defined $action) {
-			print " / $action";
-		}
-		print "\n";
-		if (!defined $searchtext) {
-			$searchtext = "";
-		}
-		my $search_hash;
-		if (defined $hash_base) {
-			$search_hash = $hash_base;
-		} elsif (defined $hash) {
-			$search_hash = $hash;
-		} else {
-			$search_hash = "HEAD";
-		}
-		$cgi->param("a", "search");
-		$cgi->param("h", $search_hash);
-		print $cgi->startform(-method => "get", -action => $my_uri) .
-		      "<div class=\"search\">\n" .
-		      $cgi->hidden(-name => "p") . "\n" .
-		      $cgi->hidden(-name => "a") . "\n" .
-		      $cgi->hidden(-name => "h") . "\n" .
-		      $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
-		      "</div>" .
-		      $cgi->end_form() . "\n";
+		$age_str .= " right now";
 	}
-	print "</div>\n";
+	return $age_str;
 }
 
-sub git_footer_html {
-	print "<div class=\"page_footer\">\n";
-	if (defined $project) {
-		my $descr = git_read_description($project);
-		if (defined $descr) {
-			print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
-		}
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=rss"), -class => "rss_logo"}, "RSS") . "\n";
+# convert file mode in octal to symbolic file mode string
+sub mode_str {
+	my $mode = oct shift;
+
+	if (S_ISDIR($mode & S_IFMT)) {
+		return 'drwxr-xr-x';
+	} elsif (S_ISLNK($mode)) {
+		return 'lrwxrwxrwx';
+	} elsif (S_ISREG($mode)) {
+		# git cares only about the executable bit
+		if ($mode & S_IXUSR) {
+			return '-rwxr-xr-x';
+		} else {
+			return '-rw-r--r--';
+		};
 	} else {
-		print $cgi->a({-href => "$my_uri?" . esc_param("a=opml"), -class => "rss_logo"}, "OPML") . "\n";
+		return '----------';
 	}
-	print "</div>\n" .
-	      "</body>\n" .
-	      "</html>";
 }
 
-sub die_error {
-	my $status = shift || "403 Forbidden";
-	my $error = shift || "Malformed query, file missing or permission denied";
+# convert file mode in octal to file type string
+sub file_type {
+	my $mode = oct shift;
 
-	git_header_html($status);
-	print "<div class=\"page_body\">\n" .
-	      "<br/><br/>\n" .
-	      "$status - $error\n" .
-	      "<br/>\n" .
-	      "</div>\n";
-	git_footer_html();
-	exit;
+	if (S_ISDIR($mode & S_IFMT)) {
+		return "directory";
+	} elsif (S_ISLNK($mode)) {
+		return "symlink";
+	} elsif (S_ISREG($mode)) {
+		return "file";
+	} else {
+		return "unknown";
+	}
 }
 
-sub git_page_nav {
-	my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
-	$extra = '' if !defined $extra; # pager or formats
+## ----------------------------------------------------------------------
+## functions returning short HTML fragments, or transforming HTML fragments
+## which don't beling to other sections
 
-	my @navs = qw(summary shortlog log commit commitdiff tree);
-	if ($suppress) {
-		@navs = grep { $_ ne $suppress } @navs;
-	}
+# format line of commit message or tag comment
+sub format_log_line_html {
+	my $line = shift;
 
-	my %arg = map { $_, ''} @navs;
-	if (defined $head) {
-		for (qw(commit commitdiff)) {
-			$arg{$_} = ";h=$head";
-		}
-		if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) {
-			for (qw(shortlog log)) {
-				$arg{$_} = ";h=$head";
-			}
+	$line = esc_html($line);
+	$line =~ s/ /&nbsp;/g;
+	if ($line =~ m/([0-9a-fA-F]{40})/) {
+		my $hash_text = $1;
+		if (git_get_type($hash_text) eq "commit") {
+			my $link = $cgi->a({-class => "text", -href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_text")}, $hash_text);
+			$line =~ s/$hash_text/$link/;
 		}
 	}
-	$arg{tree} .= ";h=$treehead" if defined $treehead;
-	$arg{tree} .= ";hb=$treebase" if defined $treebase;
-
-	print "<div class=\"page_nav\">\n" .
-		(join " | ",
-		 map { $_ eq $current
-					 ? $_
-					 : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
-				 }
-		 @navs);
-	print "<br/>\n$extra<br/>\n" .
-	      "</div>\n";
-}
-
-sub git_header_div {
-	my ($action, $title, $hash, $hash_base) = @_;
-	my $rest = '';
-
-	$rest .= ";h=$hash" if $hash;
-	$rest .= ";hb=$hash_base" if $hash_base;
-
-	print "<div class=\"header\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
-	               -class => "title"}, $title ? $title : $action) . "\n" .
-	      "</div>\n";
+	return $line;
 }
 
-sub git_get_paging_nav {
-	my ($action, $hash, $head, $page, $nrevs) = @_;
-	my $paging_nav;
-
-
-	if ($hash ne $head || $page) {
-		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action")}, "HEAD");
-	} else {
-		$paging_nav .= "HEAD";
-	}
-
-	if ($page > 0) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page-1)),
-							 -accesskey => "p", -title => "Alt-p"}, "prev");
-	} else {
-		$paging_nav .= " &sdot; prev";
-	}
+# format marker of refs pointing to given object
+sub git_get_referencing {
+	my ($refs, $id) = @_;
 
-	if ($nrevs >= (100 * ($page+1)-1)) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page+1)),
-							 -accesskey => "n", -title => "Alt-n"}, "next");
+	if (defined $refs->{$id}) {
+		return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
 	} else {
-		$paging_nav .= " &sdot; next";
+		return "";
 	}
-
-	return $paging_nav;
 }
 
-sub git_get_type {
-	my $hash = shift;
-
-	open my $fd, "-|", $GIT, "cat-file", '-t', $hash or return;
-	my $type = <$fd>;
-	close $fd or return;
-	chomp $type;
-	return $type;
-}
+## ----------------------------------------------------------------------
+## git utility subroutines, invoking git commands
 
+# get HEAD ref of given project as hash
 sub git_read_head {
 	my $project = shift;
 	my $oENV = $ENV{'GIT_DIR'};
@@ -491,6 +484,57 @@ sub git_read_head {
 	return $retval;
 }
 
+# get type of given object
+sub git_get_type {
+	my $hash = shift;
+
+	open my $fd, "-|", $GIT, "cat-file", '-t', $hash or return;
+	my $type = <$fd>;
+	close $fd or return;
+	chomp $type;
+	return $type;
+}
+
+sub git_get_project_config {
+	my $key = shift;
+
+	return unless ($key);
+	$key =~ s/^gitweb\.//;
+	return if ($key =~ m/\W/);
+
+	my $val = qx($GIT repo-config --get gitweb.$key);
+	return ($val);
+}
+
+sub git_get_project_config_bool {
+	my $val = git_get_project_config (@_);
+	if ($val and $val =~ m/true|yes|on/) {
+		return (1);
+	}
+	return; # implicit false
+}
+
+# get hash of given path at given ref
+sub git_get_hash_by_path {
+	my $base = shift;
+	my $path = shift || return undef;
+
+	my $tree = $base;
+
+	open my $fd, "-|", $GIT, "ls-tree", $base, "--", $path
+		or die_error(undef, "Open git-ls-tree failed.");
+	my $line = <$fd>;
+	close $fd or return undef;
+
+	#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
+	$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+	return $3;
+}
+
+## ......................................................................
+## git utility functions, directly accessing git repository
+
+# assumes that PATH is not symref
 sub git_read_hash {
 	my $path = shift;
 
@@ -513,6 +557,100 @@ sub git_read_description {
 	return $descr;
 }
 
+sub git_read_projects {
+	my @list;
+
+	if (-d $projects_list) {
+		# search in directory
+		my $dir = $projects_list;
+		opendir my ($dh), $dir or return undef;
+		while (my $dir = readdir($dh)) {
+			if (-e "$projectroot/$dir/HEAD") {
+				my $pr = {
+					path => $dir,
+				};
+				push @list, $pr
+			}
+		}
+		closedir($dh);
+	} elsif (-f $projects_list) {
+		# read from file(url-encoded):
+		# 'git%2Fgit.git Linus+Torvalds'
+		# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
+		# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
+		open my ($fd), $projects_list or return undef;
+		while (my $line = <$fd>) {
+			chomp $line;
+			my ($path, $owner) = split ' ', $line;
+			$path = unescape($path);
+			$owner = unescape($owner);
+			if (!defined $path) {
+				next;
+			}
+			if (-e "$projectroot/$path/HEAD") {
+				my $pr = {
+					path => $path,
+					owner => decode("utf8", $owner, Encode::FB_DEFAULT),
+				};
+				push @list, $pr
+			}
+		}
+		close $fd;
+	}
+	@list = sort {$a->{'path'} cmp $b->{'path'}} @list;
+	return @list;
+}
+
+sub read_info_ref {
+	my $type = shift || "";
+	my %refs;
+	# 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c	refs/tags/v2.6.11
+	# c39ae07f393806ccf406ef966e9a15afc43cc36a	refs/tags/v2.6.11^{}
+	open my $fd, "$projectroot/$project/info/refs" or return;
+	while (my $line = <$fd>) {
+		chomp $line;
+		# attention: for $type == "" it saves only last path part of ref name
+		# e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
+		if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
+			if (defined $refs{$1}) {
+				$refs{$1} .= " / $2";
+			} else {
+				$refs{$1} = $2;
+			}
+		}
+	}
+	close $fd or return;
+	return \%refs;
+}
+
+## ----------------------------------------------------------------------
+## parse to hash functions
+
+sub date_str {
+	my $epoch = shift;
+	my $tz = shift || "-0000";
+
+	my %date;
+	my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+	my @days = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
+	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($epoch);
+	$date{'hour'} = $hour;
+	$date{'minute'} = $min;
+	$date{'mday'} = $mday;
+	$date{'day'} = $days[$wday];
+	$date{'month'} = $months[$mon];
+	$date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000", $days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec;
+	$date{'mday-time'} = sprintf "%d %s %02d:%02d", $mday, $months[$mon], $hour ,$min;
+
+	$tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/;
+	my $local = $epoch + ((int $1 + ($2/60)) * 3600);
+	($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($local);
+	$date{'hour_local'} = $hour;
+	$date{'minute_local'} = $min;
+	$date{'tz_local'} = $tz;
+	return %date;
+}
+
 sub git_read_tag {
 	my $tag_id = shift;
 	my %tag;
@@ -548,37 +686,6 @@ sub git_read_tag {
 	return %tag
 }
 
-sub age_string {
-	my $age = shift;
-	my $age_str;
-
-	if ($age > 60*60*24*365*2) {
-		$age_str = (int $age/60/60/24/365);
-		$age_str .= " years ago";
-	} elsif ($age > 60*60*24*(365/12)*2) {
-		$age_str = int $age/60/60/24/(365/12);
-		$age_str .= " months ago";
-	} elsif ($age > 60*60*24*7*2) {
-		$age_str = int $age/60/60/24/7;
-		$age_str .= " weeks ago";
-	} elsif ($age > 60*60*24*2) {
-		$age_str = int $age/60/60/24;
-		$age_str .= " days ago";
-	} elsif ($age > 60*60*2) {
-		$age_str = int $age/60/60;
-		$age_str .= " hours ago";
-	} elsif ($age > 60*2) {
-		$age_str = int $age/60;
-		$age_str .= " min ago";
-	} elsif ($age > 2) {
-		$age_str = int $age;
-		$age_str .= " sec ago";
-	} else {
-		$age_str .= " right now";
-	}
-	return $age_str;
-}
-
 sub git_read_commit {
 	my $commit_id = shift;
 	my $commit_text = shift;
@@ -673,380 +780,8 @@ sub git_read_commit {
 	return %co;
 }
 
-sub git_diff_print {
-	my $from = shift;
-	my $from_name = shift;
-	my $to = shift;
-	my $to_name = shift;
-	my $format = shift || "html";
-
-	my $from_tmp = "/dev/null";
-	my $to_tmp = "/dev/null";
-	my $pid = $$;
-
-	# create tmp from-file
-	if (defined $from) {
-		$from_tmp = "$git_temp/gitweb_" . $$ . "_from";
-		open my $fd2, "> $from_tmp";
-		open my $fd, "-|", $GIT, "cat-file", "blob", $from;
-		my @file = <$fd>;
-		print $fd2 @file;
-		close $fd2;
-		close $fd;
-	}
-
-	# create tmp to-file
-	if (defined $to) {
-		$to_tmp = "$git_temp/gitweb_" . $$ . "_to";
-		open my $fd2, "> $to_tmp";
-		open my $fd, "-|", $GIT, "cat-file", "blob", $to;
-		my @file = <$fd>;
-		print $fd2 @file;
-		close $fd2;
-		close $fd;
-	}
-
-	open my $fd, "-|", "/usr/bin/diff -u -p -L \'$from_name\' -L \'$to_name\' $from_tmp $to_tmp";
-	if ($format eq "plain") {
-		undef $/;
-		print <$fd>;
-		$/ = "\n";
-	} else {
-		while (my $line = <$fd>) {
-			chomp $line;
-			my $char = substr($line, 0, 1);
-			my $diff_class = "";
-			if ($char eq '+') {
-				$diff_class = " add";
-			} elsif ($char eq "-") {
-				$diff_class = " rem";
-			} elsif ($char eq "@") {
-				$diff_class = " chunk_header";
-			} elsif ($char eq "\\") {
-				# skip errors
-				next;
-			}
-			while ((my $pos = index($line, "\t")) != -1) {
-				if (my $count = (8 - (($pos-1) % 8))) {
-					my $spaces = ' ' x $count;
-					$line =~ s/\t/$spaces/;
-				}
-			}
-			print "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
-		}
-	}
-	close $fd;
-
-	if (defined $from) {
-		unlink($from_tmp);
-	}
-	if (defined $to) {
-		unlink($to_tmp);
-	}
-}
-
-sub mode_str {
-	my $mode = oct shift;
-
-	if (S_ISDIR($mode & S_IFMT)) {
-		return 'drwxr-xr-x';
-	} elsif (S_ISLNK($mode)) {
-		return 'lrwxrwxrwx';
-	} elsif (S_ISREG($mode)) {
-		# git cares only about the executable bit
-		if ($mode & S_IXUSR) {
-			return '-rwxr-xr-x';
-		} else {
-			return '-rw-r--r--';
-		};
-	} else {
-		return '----------';
-	}
-}
-
-sub chop_str {
-	my $str = shift;
-	my $len = shift;
-	my $add_len = shift || 10;
-
-	# allow only $len chars, but don't cut a word if it would fit in $add_len
-	# if it doesn't fit, cut it if it's still longer than the dots we would add
-	$str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/;
-	my $body = $1;
-	my $tail = $2;
-	if (length($tail) > 4) {
-		$tail = " ...";
-		$body =~ s/&[^;]*$//; # remove chopped character entities
-	}
-	return "$body$tail";
-}
-
-sub file_type {
-	my $mode = oct shift;
-
-	if (S_ISDIR($mode & S_IFMT)) {
-		return "directory";
-	} elsif (S_ISLNK($mode)) {
-		return "symlink";
-	} elsif (S_ISREG($mode)) {
-		return "file";
-	} else {
-		return "unknown";
-	}
-}
-
-sub format_log_line_html {
-	my $line = shift;
-
-	$line = esc_html($line);
-	$line =~ s/ /&nbsp;/g;
-	if ($line =~ m/([0-9a-fA-F]{40})/) {
-		my $hash_text = $1;
-		if (git_get_type($hash_text) eq "commit") {
-			my $link = $cgi->a({-class => "text", -href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_text")}, $hash_text);
-			$line =~ s/$hash_text/$link/;
-		}
-	}
-	return $line;
-}
-
-sub date_str {
-	my $epoch = shift;
-	my $tz = shift || "-0000";
-
-	my %date;
-	my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
-	my @days = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
-	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($epoch);
-	$date{'hour'} = $hour;
-	$date{'minute'} = $min;
-	$date{'mday'} = $mday;
-	$date{'day'} = $days[$wday];
-	$date{'month'} = $months[$mon];
-	$date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000", $days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec;
-	$date{'mday-time'} = sprintf "%d %s %02d:%02d", $mday, $months[$mon], $hour ,$min;
-
-	$tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/;
-	my $local = $epoch + ((int $1 + ($2/60)) * 3600);
-	($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($local);
-	$date{'hour_local'} = $hour;
-	$date{'minute_local'} = $min;
-	$date{'tz_local'} = $tz;
-	return %date;
-}
-
-# git-logo (cached in browser for one day)
-sub git_logo {
-	binmode STDOUT, ':raw';
-	print $cgi->header(-type => 'image/png', -expires => '+1d');
-	# cat git-logo.png | hexdump -e '16/1 " %02x"  "\n"' | sed 's/ /\\x/g'
-	print	"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
-		"\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
-		"\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
-		"\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
-		"\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
-		"\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
-		"\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
-		"\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
-		"\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
-		"\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
-		"\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
-		"\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
-		"\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
-}
-
-sub get_file_owner {
-	my $path = shift;
-
-	my ($dev, $ino, $mode, $nlink, $st_uid, $st_gid, $rdev, $size) = stat($path);
-	my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid($st_uid);
-	if (!defined $gcos) {
-		return undef;
-	}
-	my $owner = $gcos;
-	$owner =~ s/[,;].*$//;
-	return decode("utf8", $owner, Encode::FB_DEFAULT);
-}
-
-sub git_read_projects {
-	my @list;
-
-	if (-d $projects_list) {
-		# search in directory
-		my $dir = $projects_list;
-		opendir my ($dh), $dir or return undef;
-		while (my $dir = readdir($dh)) {
-			if (-e "$projectroot/$dir/HEAD") {
-				my $pr = {
-					path => $dir,
-				};
-				push @list, $pr
-			}
-		}
-		closedir($dh);
-	} elsif (-f $projects_list) {
-		# read from file(url-encoded):
-		# 'git%2Fgit.git Linus+Torvalds'
-		# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
-		# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
-		open my ($fd), $projects_list or return undef;
-		while (my $line = <$fd>) {
-			chomp $line;
-			my ($path, $owner) = split ' ', $line;
-			$path = unescape($path);
-			$owner = unescape($owner);
-			if (!defined $path) {
-				next;
-			}
-			if (-e "$projectroot/$path/HEAD") {
-				my $pr = {
-					path => $path,
-					owner => decode("utf8", $owner, Encode::FB_DEFAULT),
-				};
-				push @list, $pr
-			}
-		}
-		close $fd;
-	}
-	@list = sort {$a->{'path'} cmp $b->{'path'}} @list;
-	return @list;
-}
-
-sub git_get_project_config {
-	my $key = shift;
-
-	return unless ($key);
-	$key =~ s/^gitweb\.//;
-	return if ($key =~ m/\W/);
-
-	my $val = qx($GIT repo-config --get gitweb.$key);
-	return ($val);
-}
-
-sub git_get_project_config_bool {
-	my $val = git_get_project_config (@_);
-	if ($val and $val =~ m/true|yes|on/) {
-		return (1);
-	}
-	return; # implicit false
-}
-
-sub git_project_list {
-	my @list = git_read_projects();
-	my @projects;
-	if (!@list) {
-		die_error(undef, "No project found.");
-	}
-	foreach my $pr (@list) {
-		my $head = git_read_head($pr->{'path'});
-		if (!defined $head) {
-			next;
-		}
-		$ENV{'GIT_DIR'} = "$projectroot/$pr->{'path'}";
-		my %co = git_read_commit($head);
-		if (!%co) {
-			next;
-		}
-		$pr->{'commit'} = \%co;
-		if (!defined $pr->{'descr'}) {
-			my $descr = git_read_description($pr->{'path'}) || "";
-			$pr->{'descr'} = chop_str($descr, 25, 5);
-		}
-		if (!defined $pr->{'owner'}) {
-			$pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
-		}
-		push @projects, $pr;
-	}
-	git_header_html();
-	if (-f $home_text) {
-		print "<div class=\"index_include\">\n";
-		open (my $fd, $home_text);
-		print <$fd>;
-		close $fd;
-		print "</div>\n";
-	}
-	print "<table class=\"project_list\">\n" .
-	      "<tr>\n";
-	if (!defined($order) || (defined($order) && ($order eq "project"))) {
-		@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
-		print "<th>Project</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=project")}, "Project") . "</th>\n";
-	}
-	if (defined($order) && ($order eq "descr")) {
-		@projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
-		print "<th>Description</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=descr")}, "Description") . "</th>\n";
-	}
-	if (defined($order) && ($order eq "owner")) {
-		@projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
-		print "<th>Owner</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=owner")}, "Owner") . "</th>\n";
-	}
-	if (defined($order) && ($order eq "age")) {
-		@projects = sort {$a->{'commit'}{'age'} <=> $b->{'commit'}{'age'}} @projects;
-		print "<th>Last Change</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=age")}, "Last Change") . "</th>\n";
-	}
-	print "<th></th>\n" .
-	      "</tr>\n";
-	my $alternate = 0;
-	foreach my $pr (@projects) {
-		if ($alternate) {
-			print "<tr class=\"dark\">\n";
-		} else {
-			print "<tr class=\"light\">\n";
-		}
-		$alternate ^= 1;
-		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
-		      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
-		      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
-		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "</td>\n" .
-		      "<td class=\"link\">" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") .
-		      "</td>\n" .
-		      "</tr>\n";
-	}
-	print "</table>\n";
-	git_footer_html();
-}
-
-sub read_info_ref {
-	my $type = shift || "";
-	my %refs;
-	# 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c	refs/tags/v2.6.11
-	# c39ae07f393806ccf406ef966e9a15afc43cc36a	refs/tags/v2.6.11^{}
-	open my $fd, "$projectroot/$project/info/refs" or return;
-	while (my $line = <$fd>) {
-		chomp $line;
-		# attention: for $type == "" it saves only last path part of ref name
-		# e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
-		if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
-			if (defined $refs{$1}) {
-				$refs{$1} .= " / $2";
-			} else {
-				$refs{$1} = $2;
-			}
-		}
-	}
-	close $fd or return;
-	return \%refs;
-}
-
-sub git_get_referencing {
-	my ($refs, $id) = @_;
-
-	if (defined $refs->{$id}) {
-		return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
-	} else {
-		return "";
-	}
-}
+## ......................................................................
+## parse to array of hashes functions
 
 sub git_read_refs {
 	my $ref_dir = shift;
@@ -1115,6 +850,299 @@ sub git_read_refs {
 	return \@reflist;
 }
 
+## ----------------------------------------------------------------------
+## filesystem-related functions
+
+sub get_file_owner {
+	my $path = shift;
+
+	my ($dev, $ino, $mode, $nlink, $st_uid, $st_gid, $rdev, $size) = stat($path);
+	my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid($st_uid);
+	if (!defined $gcos) {
+		return undef;
+	}
+	my $owner = $gcos;
+	$owner =~ s/[,;].*$//;
+	return decode("utf8", $owner, Encode::FB_DEFAULT);
+}
+
+## ......................................................................
+## mimetype related functions
+
+sub mimetype_guess_file {
+	my $filename = shift;
+	my $mimemap = shift;
+	-r $mimemap or return undef;
+
+	my %mimemap;
+	open(MIME, $mimemap) or return undef;
+	while (<MIME>) {
+		my ($mime, $exts) = split(/\t+/);
+		my @exts = split(/\s+/, $exts);
+		foreach my $ext (@exts) {
+			$mimemap{$ext} = $mime;
+		}
+	}
+	close(MIME);
+
+	$filename =~ /\.(.*?)$/;
+	return $mimemap{$1};
+}
+
+sub mimetype_guess {
+	my $filename = shift;
+	my $mime;
+	$filename =~ /\./ or return undef;
+
+	if ($mimetypes_file) {
+		my $file = $mimetypes_file;
+		#$file =~ m#^/# or $file = "$projectroot/$path/$file";
+		$mime = mimetype_guess_file($filename, $file);
+	}
+	$mime ||= mimetype_guess_file($filename, '/etc/mime.types');
+	return $mime;
+}
+
+sub git_blob_plain_mimetype {
+	my $fd = shift;
+	my $filename = shift;
+
+	if ($filename) {
+		my $mime = mimetype_guess($filename);
+		$mime and return $mime;
+	}
+
+	# just in case
+	return $default_blob_plain_mimetype unless $fd;
+
+	if (-T $fd) {
+		return 'text/plain' .
+		       ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
+	} elsif (! $filename) {
+		return 'application/octet-stream';
+	} elsif ($filename =~ m/\.png$/i) {
+		return 'image/png';
+	} elsif ($filename =~ m/\.gif$/i) {
+		return 'image/gif';
+	} elsif ($filename =~ m/\.jpe?g$/i) {
+		return 'image/jpeg';
+	} else {
+		return 'application/octet-stream';
+	}
+}
+
+## ======================================================================
+## functions printing HTML: header, footer, error page
+
+sub git_header_html {
+	my $status = shift || "200 OK";
+	my $expires = shift;
+
+	my $title = "$site_name git";
+	if (defined $project) {
+		$title .= " - $project";
+		if (defined $action) {
+			$title .= "/$action";
+			if (defined $file_name) {
+				$title .= " - $file_name";
+				if ($action eq "tree" && $file_name !~ m|/$|) {
+					$title .= "/";
+				}
+			}
+		}
+	}
+	my $content_type;
+	# require explicit support from the UA if we are to send the page as
+	# 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
+	# we have to do this because MSIE sometimes globs '*/*', pretending to
+	# support xhtml+xml but choking when it gets what it asked for.
+	if ($cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && $cgi->Accept('application/xhtml+xml') != 0) {
+		$content_type = 'application/xhtml+xml';
+	} else {
+		$content_type = 'text/html';
+	}
+	print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires);
+	print <<EOF;
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<!-- git web interface v$version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
+<!-- git core binaries version $git_version -->
+<head>
+<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
+<meta name="robots" content="index, nofollow"/>
+<title>$title</title>
+<link rel="stylesheet" type="text/css" href="$stylesheet"/>
+$rss_link
+</head>
+<body>
+EOF
+	print "<div class=\"page_header\">\n" .
+	      "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
+	      "<img src=\"$my_uri?" . esc_param("a=git-logo.png") . "\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
+	      "</a>\n";
+	print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
+	if (defined $project) {
+		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, esc_html($project));
+		if (defined $action) {
+			print " / $action";
+		}
+		print "\n";
+		if (!defined $searchtext) {
+			$searchtext = "";
+		}
+		my $search_hash;
+		if (defined $hash_base) {
+			$search_hash = $hash_base;
+		} elsif (defined $hash) {
+			$search_hash = $hash;
+		} else {
+			$search_hash = "HEAD";
+		}
+		$cgi->param("a", "search");
+		$cgi->param("h", $search_hash);
+		print $cgi->startform(-method => "get", -action => $my_uri) .
+		      "<div class=\"search\">\n" .
+		      $cgi->hidden(-name => "p") . "\n" .
+		      $cgi->hidden(-name => "a") . "\n" .
+		      $cgi->hidden(-name => "h") . "\n" .
+		      $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+		      "</div>" .
+		      $cgi->end_form() . "\n";
+	}
+	print "</div>\n";
+}
+
+sub git_footer_html {
+	print "<div class=\"page_footer\">\n";
+	if (defined $project) {
+		my $descr = git_read_description($project);
+		if (defined $descr) {
+			print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
+		}
+		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=rss"), -class => "rss_logo"}, "RSS") . "\n";
+	} else {
+		print $cgi->a({-href => "$my_uri?" . esc_param("a=opml"), -class => "rss_logo"}, "OPML") . "\n";
+	}
+	print "</div>\n" .
+	      "</body>\n" .
+	      "</html>";
+}
+
+sub die_error {
+	my $status = shift || "403 Forbidden";
+	my $error = shift || "Malformed query, file missing or permission denied";
+
+	git_header_html($status);
+	print "<div class=\"page_body\">\n" .
+	      "<br/><br/>\n" .
+	      "$status - $error\n" .
+	      "<br/>\n" .
+	      "</div>\n";
+	git_footer_html();
+	exit;
+}
+
+## ----------------------------------------------------------------------
+## functions printing or outputting HTML: navigation
+
+sub git_page_nav {
+	my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
+	$extra = '' if !defined $extra; # pager or formats
+
+	my @navs = qw(summary shortlog log commit commitdiff tree);
+	if ($suppress) {
+		@navs = grep { $_ ne $suppress } @navs;
+	}
+
+	my %arg = map { $_, ''} @navs;
+	if (defined $head) {
+		for (qw(commit commitdiff)) {
+			$arg{$_} = ";h=$head";
+		}
+		if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) {
+			for (qw(shortlog log)) {
+				$arg{$_} = ";h=$head";
+			}
+		}
+	}
+	$arg{tree} .= ";h=$treehead" if defined $treehead;
+	$arg{tree} .= ";hb=$treebase" if defined $treebase;
+
+	print "<div class=\"page_nav\">\n" .
+		(join " | ",
+		 map { $_ eq $current
+					 ? $_
+					 : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
+				 }
+		 @navs);
+	print "<br/>\n$extra<br/>\n" .
+	      "</div>\n";
+}
+
+sub git_get_paging_nav {
+	my ($action, $hash, $head, $page, $nrevs) = @_;
+	my $paging_nav;
+
+
+	if ($hash ne $head || $page) {
+		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action")}, "HEAD");
+	} else {
+		$paging_nav .= "HEAD";
+	}
+
+	if ($page > 0) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page-1)),
+							 -accesskey => "p", -title => "Alt-p"}, "prev");
+	} else {
+		$paging_nav .= " &sdot; prev";
+	}
+
+	if ($nrevs >= (100 * ($page+1)-1)) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page+1)),
+							 -accesskey => "n", -title => "Alt-n"}, "next");
+	} else {
+		$paging_nav .= " &sdot; next";
+	}
+
+	return $paging_nav;
+}
+
+## ......................................................................
+## functions printing or outputting HTML: div
+
+sub git_header_div {
+	my ($action, $title, $hash, $hash_base) = @_;
+	my $rest = '';
+
+	$rest .= ";h=$hash" if $hash;
+	$rest .= ";hb=$hash_base" if $hash_base;
+
+	print "<div class=\"header\">\n" .
+	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
+	               -class => "title"}, $title ? $title : $action) . "\n" .
+	      "</div>\n";
+}
+
+sub git_print_page_path {
+	my $name = shift;
+	my $type = shift;
+
+	if (!defined $name) {
+		print "<div class=\"page_path\"><b>/</b></div>\n";
+	} elsif ($type =~ "blob") {
+		print "<div class=\"page_path\"><b>" .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;f=$file_name")}, esc_html($name)) . "</b><br/></div>\n";
+	} else {
+		print "<div class=\"page_path\"><b>" . esc_html($name) . "</b><br/></div>\n";
+	}
+}
+
+## ......................................................................
+## functions printing large fragments of HTML
+
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
@@ -1265,6 +1293,191 @@ sub git_heads_body {
 	print "</table>\n";
 }
 
+## ----------------------------------------------------------------------
+## functions printing large fragments, format as one of arguments
+
+sub git_diff_print {
+	my $from = shift;
+	my $from_name = shift;
+	my $to = shift;
+	my $to_name = shift;
+	my $format = shift || "html";
+
+	my $from_tmp = "/dev/null";
+	my $to_tmp = "/dev/null";
+	my $pid = $$;
+
+	# create tmp from-file
+	if (defined $from) {
+		$from_tmp = "$git_temp/gitweb_" . $$ . "_from";
+		open my $fd2, "> $from_tmp";
+		open my $fd, "-|", $GIT, "cat-file", "blob", $from;
+		my @file = <$fd>;
+		print $fd2 @file;
+		close $fd2;
+		close $fd;
+	}
+
+	# create tmp to-file
+	if (defined $to) {
+		$to_tmp = "$git_temp/gitweb_" . $$ . "_to";
+		open my $fd2, "> $to_tmp";
+		open my $fd, "-|", $GIT, "cat-file", "blob", $to;
+		my @file = <$fd>;
+		print $fd2 @file;
+		close $fd2;
+		close $fd;
+	}
+
+	open my $fd, "-|", "/usr/bin/diff -u -p -L \'$from_name\' -L \'$to_name\' $from_tmp $to_tmp";
+	if ($format eq "plain") {
+		undef $/;
+		print <$fd>;
+		$/ = "\n";
+	} else {
+		while (my $line = <$fd>) {
+			chomp $line;
+			my $char = substr($line, 0, 1);
+			my $diff_class = "";
+			if ($char eq '+') {
+				$diff_class = " add";
+			} elsif ($char eq "-") {
+				$diff_class = " rem";
+			} elsif ($char eq "@") {
+				$diff_class = " chunk_header";
+			} elsif ($char eq "\\") {
+				# skip errors
+				next;
+			}
+			while ((my $pos = index($line, "\t")) != -1) {
+				if (my $count = (8 - (($pos-1) % 8))) {
+					my $spaces = ' ' x $count;
+					$line =~ s/\t/$spaces/;
+				}
+			}
+			print "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
+		}
+	}
+	close $fd;
+
+	if (defined $from) {
+		unlink($from_tmp);
+	}
+	if (defined $to) {
+		unlink($to_tmp);
+	}
+}
+
+
+## ======================================================================
+## ======================================================================
+## actions
+
+# git-logo (cached in browser for one day)
+sub git_logo {
+	binmode STDOUT, ':raw';
+	print $cgi->header(-type => 'image/png', -expires => '+1d');
+	# cat git-logo.png | hexdump -e '16/1 " %02x"  "\n"' | sed 's/ /\\x/g'
+	print	"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
+		"\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
+		"\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
+		"\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
+		"\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
+		"\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
+		"\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
+		"\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
+		"\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
+		"\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
+		"\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
+		"\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
+		"\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
+}
+
+sub git_project_list {
+	my @list = git_read_projects();
+	my @projects;
+	if (!@list) {
+		die_error(undef, "No project found.");
+	}
+	foreach my $pr (@list) {
+		my $head = git_read_head($pr->{'path'});
+		if (!defined $head) {
+			next;
+		}
+		$ENV{'GIT_DIR'} = "$projectroot/$pr->{'path'}";
+		my %co = git_read_commit($head);
+		if (!%co) {
+			next;
+		}
+		$pr->{'commit'} = \%co;
+		if (!defined $pr->{'descr'}) {
+			my $descr = git_read_description($pr->{'path'}) || "";
+			$pr->{'descr'} = chop_str($descr, 25, 5);
+		}
+		if (!defined $pr->{'owner'}) {
+			$pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
+		}
+		push @projects, $pr;
+	}
+	git_header_html();
+	if (-f $home_text) {
+		print "<div class=\"index_include\">\n";
+		open (my $fd, $home_text);
+		print <$fd>;
+		close $fd;
+		print "</div>\n";
+	}
+	print "<table class=\"project_list\">\n" .
+	      "<tr>\n";
+	if (!defined($order) || (defined($order) && ($order eq "project"))) {
+		@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
+		print "<th>Project</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=project")}, "Project") . "</th>\n";
+	}
+	if (defined($order) && ($order eq "descr")) {
+		@projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
+		print "<th>Description</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=descr")}, "Description") . "</th>\n";
+	}
+	if (defined($order) && ($order eq "owner")) {
+		@projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
+		print "<th>Owner</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=owner")}, "Owner") . "</th>\n";
+	}
+	if (defined($order) && ($order eq "age")) {
+		@projects = sort {$a->{'commit'}{'age'} <=> $b->{'commit'}{'age'}} @projects;
+		print "<th>Last Change</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=age")}, "Last Change") . "</th>\n";
+	}
+	print "<th></th>\n" .
+	      "</tr>\n";
+	my $alternate = 0;
+	foreach my $pr (@projects) {
+		if ($alternate) {
+			print "<tr class=\"dark\">\n";
+		} else {
+			print "<tr class=\"light\">\n";
+		}
+		$alternate ^= 1;
+		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+		      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
+		      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
+		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "</td>\n" .
+		      "<td class=\"link\">" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary") .
+		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") .
+		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") .
+		      "</td>\n" .
+		      "</tr>\n";
+	}
+	print "</table>\n";
+	git_footer_html();
+}
+
 sub git_summary {
 	my $descr = git_read_description($project) || "none";
 	my $head = git_read_head($project);
@@ -1326,20 +1539,6 @@ sub git_summary {
 	git_footer_html();
 }
 
-sub git_print_page_path {
-	my $name = shift;
-	my $type = shift;
-
-	if (!defined $name) {
-		print "<div class=\"page_path\"><b>/</b></div>\n";
-	} elsif ($type =~ "blob") {
-		print "<div class=\"page_path\"><b>" .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;f=$file_name")}, esc_html($name)) . "</b><br/></div>\n";
-	} else {
-		print "<div class=\"page_path\"><b>" . esc_html($name) . "</b><br/></div>\n";
-	}
-}
-
 sub git_tag {
 	my $head = git_read_head($project);
 	git_header_html();
@@ -1546,84 +1745,6 @@ sub git_heads {
 	git_footer_html();
 }
 
-sub git_get_hash_by_path {
-	my $base = shift;
-	my $path = shift || return undef;
-
-	my $tree = $base;
-
-	open my $fd, "-|", $GIT, "ls-tree", $base, "--", $path
-		or die_error(undef, "Open git-ls-tree failed.");
-	my $line = <$fd>;
-	close $fd or return undef;
-
-	#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
-	$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
-	return $3;
-}
-
-sub mimetype_guess_file {
-	my $filename = shift;
-	my $mimemap = shift;
-	-r $mimemap or return undef;
-
-	my %mimemap;
-	open(MIME, $mimemap) or return undef;
-	while (<MIME>) {
-		my ($mime, $exts) = split(/\t+/);
-		my @exts = split(/\s+/, $exts);
-		foreach my $ext (@exts) {
-			$mimemap{$ext} = $mime;
-		}
-	}
-	close(MIME);
-
-	$filename =~ /\.(.*?)$/;
-	return $mimemap{$1};
-}
-
-sub mimetype_guess {
-	my $filename = shift;
-	my $mime;
-	$filename =~ /\./ or return undef;
-
-	if ($mimetypes_file) {
-		my $file = $mimetypes_file;
-		#$file =~ m#^/# or $file = "$projectroot/$path/$file";
-		$mime = mimetype_guess_file($filename, $file);
-	}
-	$mime ||= mimetype_guess_file($filename, '/etc/mime.types');
-	return $mime;
-}
-
-sub git_blob_plain_mimetype {
-	my $fd = shift;
-	my $filename = shift;
-
-	if ($filename) {
-		my $mime = mimetype_guess($filename);
-		$mime and return $mime;
-	}
-
-	# just in case
-	return $default_blob_plain_mimetype unless $fd;
-
-	if (-T $fd) {
-		return 'text/plain' .
-		       ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
-	} elsif (! $filename) {
-		return 'application/octet-stream';
-	} elsif ($filename =~ m/\.png$/i) {
-		return 'image/png';
-	} elsif ($filename =~ m/\.gif$/i) {
-		return 'image/gif';
-	} elsif ($filename =~ m/\.jpe?g$/i) {
-		return 'image/jpeg';
-	} else {
-		return 'application/octet-stream';
-	}
-}
-
 sub git_blob_plain {
 	if (!defined $hash) {
 		if (defined $file_name) {
@@ -1793,98 +1914,6 @@ #			      " | " . $cgi->a({-href => "$my
 	git_footer_html();
 }
 
-sub git_rss {
-	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
-	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project) 
-		or die_error(undef, "Open git-rev-list failed.");
-	my @revlist = map { chomp; $_ } <$fd>;
-	close $fd or die_error(undef, "Reading rev-list failed.");
-	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
-	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
-	      "<rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n";
-	print "<channel>\n";
-	print "<title>$project</title>\n".
-	      "<link>" . esc_html("$my_url?p=$project;a=summary") . "</link>\n".
-	      "<description>$project log</description>\n".
-	      "<language>en</language>\n";
-
-	for (my $i = 0; $i <= $#revlist; $i++) {
-		my $commit = $revlist[$i];
-		my %co = git_read_commit($commit);
-		# we read 150, we always show 30 and the ones more recent than 48 hours
-		if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) {
-			last;
-		}
-		my %cd = date_str($co{'committer_epoch'});
-		open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next;
-		my @difftree = map { chomp; $_ } <$fd>;
-		close $fd or next;
-		print "<item>\n" .
-		      "<title>" .
-		      sprintf("%d %s %02d:%02d", $cd{'mday'}, $cd{'month'}, $cd{'hour'}, $cd{'minute'}) . " - " . esc_html($co{'title'}) .
-		      "</title>\n" .
-		      "<author>" . esc_html($co{'author'}) . "</author>\n" .
-		      "<pubDate>$cd{'rfc2822'}</pubDate>\n" .
-		      "<guid isPermaLink=\"true\">" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</guid>\n" .
-		      "<link>" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</link>\n" .
-		      "<description>" . esc_html($co{'title'}) . "</description>\n" .
-		      "<content:encoded>" .
-		      "<![CDATA[\n";
-		my $comment = $co{'comment'};
-		foreach my $line (@$comment) {
-			$line = decode("utf8", $line, Encode::FB_DEFAULT);
-			print "$line<br/>\n";
-		}
-		print "<br/>\n";
-		foreach my $line (@difftree) {
-			if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) {
-				next;
-			}
-			my $file = validate_input(unquote($7));
-			$file = decode("utf8", $file, Encode::FB_DEFAULT);
-			print "$file<br/>\n";
-		}
-		print "]]>\n" .
-		      "</content:encoded>\n" .
-		      "</item>\n";
-	}
-	print "</channel></rss>";
-}
-
-sub git_opml {
-	my @list = git_read_projects();
-
-	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
-	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
-	      "<opml version=\"1.0\">\n".
-	      "<head>".
-	      "  <title>$site_name Git OPML Export</title>\n".
-	      "</head>\n".
-	      "<body>\n".
-	      "<outline text=\"git RSS feeds\">\n";
-
-	foreach my $pr (@list) {
-		my %proj = %$pr;
-		my $head = git_read_head($proj{'path'});
-		if (!defined $head) {
-			next;
-		}
-		$ENV{'GIT_DIR'} = "$projectroot/$proj{'path'}";
-		my %co = git_read_commit($head);
-		if (!%co) {
-			next;
-		}
-
-		my $path = esc_html(chop_str($proj{'path'}, 25, 5));
-		my $rss  = "$my_url?p=$proj{'path'};a=rss";
-		my $html = "$my_url?p=$proj{'path'};a=summary";
-		print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
-	}
-	print "</outline>\n".
-	      "</body>\n".
-	      "</opml>\n";
-}
-
 sub git_log {
 	my $head = git_read_head($project);
 	if (!defined $hash) {
@@ -2556,3 +2585,98 @@ sub git_shortlog {
 
 	git_footer_html();
 }
+
+## ......................................................................
+## feeds (RSS, OPML)
+
+sub git_rss {
+	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
+	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project)
+		or die_error(undef, "Open git-rev-list failed.");
+	my @revlist = map { chomp; $_ } <$fd>;
+	close $fd or die_error(undef, "Reading rev-list failed.");
+	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
+	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
+	      "<rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n";
+	print "<channel>\n";
+	print "<title>$project</title>\n".
+	      "<link>" . esc_html("$my_url?p=$project;a=summary") . "</link>\n".
+	      "<description>$project log</description>\n".
+	      "<language>en</language>\n";
+
+	for (my $i = 0; $i <= $#revlist; $i++) {
+		my $commit = $revlist[$i];
+		my %co = git_read_commit($commit);
+		# we read 150, we always show 30 and the ones more recent than 48 hours
+		if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) {
+			last;
+		}
+		my %cd = date_str($co{'committer_epoch'});
+		open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next;
+		my @difftree = map { chomp; $_ } <$fd>;
+		close $fd or next;
+		print "<item>\n" .
+		      "<title>" .
+		      sprintf("%d %s %02d:%02d", $cd{'mday'}, $cd{'month'}, $cd{'hour'}, $cd{'minute'}) . " - " . esc_html($co{'title'}) .
+		      "</title>\n" .
+		      "<author>" . esc_html($co{'author'}) . "</author>\n" .
+		      "<pubDate>$cd{'rfc2822'}</pubDate>\n" .
+		      "<guid isPermaLink=\"true\">" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</guid>\n" .
+		      "<link>" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</link>\n" .
+		      "<description>" . esc_html($co{'title'}) . "</description>\n" .
+		      "<content:encoded>" .
+		      "<![CDATA[\n";
+		my $comment = $co{'comment'};
+		foreach my $line (@$comment) {
+			$line = decode("utf8", $line, Encode::FB_DEFAULT);
+			print "$line<br/>\n";
+		}
+		print "<br/>\n";
+		foreach my $line (@difftree) {
+			if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) {
+				next;
+			}
+			my $file = validate_input(unquote($7));
+			$file = decode("utf8", $file, Encode::FB_DEFAULT);
+			print "$file<br/>\n";
+		}
+		print "]]>\n" .
+		      "</content:encoded>\n" .
+		      "</item>\n";
+	}
+	print "</channel></rss>";
+}
+
+sub git_opml {
+	my @list = git_read_projects();
+
+	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
+	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
+	      "<opml version=\"1.0\">\n".
+	      "<head>".
+	      "  <title>$site_name Git OPML Export</title>\n".
+	      "</head>\n".
+	      "<body>\n".
+	      "<outline text=\"git RSS feeds\">\n";
+
+	foreach my $pr (@list) {
+		my %proj = %$pr;
+		my $head = git_read_head($proj{'path'});
+		if (!defined $head) {
+			next;
+		}
+		$ENV{'GIT_DIR'} = "$projectroot/$proj{'path'}";
+		my %co = git_read_commit($head);
+		if (!%co) {
+			next;
+		}
+
+		my $path = esc_html(chop_str($proj{'path'}, 25, 5));
+		my $rss  = "$my_url?p=$proj{'path'};a=rss";
+		my $html = "$my_url?p=$proj{'path'};a=summary";
+		print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
+	}
+	print "</outline>\n".
+	      "</body>\n".
+	      "</opml>\n";
+}
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 19] gitweb: No need to quote path for list version of open "-|"
  2006-07-31 16:33 ` [PATCH 19] gitweb: No need to quote path for list version of open "-|" Jakub Narebski
@ 2006-07-31 18:55   ` Junio C Hamano
  2006-07-31 19:00     ` Jakub Narebski
  0 siblings, 1 reply; 54+ messages in thread
From: Junio C Hamano @ 2006-07-31 18:55 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

I suspect the patch title is wrong -- it is not "no need to" but
"quoting path breaks so do not do it" ;-).

I guess this fixes the problem I saw last night?

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 16b] gitweb: Remove characters entities entirely when shortening string -- correction
  2006-07-30 20:36 ` [PATCH 16] gitweb: Remove characters entities entirely when shortening string Jakub Narebski
  2006-07-31 16:59   ` Jakub Narebski
@ 2006-07-31 18:58   ` Jakub Narebski
  1 sibling, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 18:58 UTC (permalink / raw)
  To: git

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Apply it on top of [PATCH 16] to correct it;
this patch was generated after [PATCH 19].

 gitweb/gitweb.cgi |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index f7fe28a..cb6af39 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -776,7 +776,7 @@ sub chop_str {
 	my $tail = $2;
 	if (length($tail) > 4) {
 		$tail = " ...";
-		$body =~ s/&[^;]$//; # remove chopped character entities
+		$body =~ s/&[^;]*$//; # remove chopped character entities
 	}
 	return "$body$tail";
 }
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 19] gitweb: No need to quote path for list version of open "-|"
  2006-07-31 18:55   ` Junio C Hamano
@ 2006-07-31 19:00     ` Jakub Narebski
  2006-08-01  2:17       ` Junio C Hamano
  2006-08-01  2:18       ` There can be more than two levels of subdirectories Junio C Hamano
  0 siblings, 2 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 19:00 UTC (permalink / raw)
  To: git

<opublikowany i wysłany>

Junio C Hamano wrote:

> I suspect the patch title is wrong -- it is not "no need to" but
> "quoting path breaks so do not do it" ;-).
> 
> I guess this fixes the problem I saw last night?

If I remember correctly it worked without this patch, for git 1.4.1.1 
(i.e. with --full-history option, although not working as advertised: see my
comment earlier in thread).

How to do sane fallback to version without "--full-history", if git binaries
used do not support "--full-history"?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 20 (amend)] gitweb: Reordering code and dividing it into categories
  2006-07-31 18:48 ` [PATCH 20] gitweb: Reordering code and dividing it into categories Jakub Narebski
@ 2006-07-31 19:22   ` Jakub Narebski
  0 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 19:22 UTC (permalink / raw)
  To: git

Reorder gitweb code around, divide it into sections (categories) and
add some comments.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.cgi | 1616 ++++++++++++++++++++++++++++-------------------------
 1 files changed, 840 insertions(+), 776 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index cb6af39..c1ee79e 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -160,21 +160,7 @@ if (defined $searchtext) {
 	$searchtext = quotemeta $searchtext;
 }
 
-sub validate_input {
-	my $input = shift;
-
-	if ($input =~ m/^[0-9a-fA-F]{40}$/) {
-		return $input;
-	}
-	if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) {
-		return undef;
-	}
-	if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) {
-		return undef;
-	}
-	return $input;
-}
-
+# dispatch
 if (!defined $action || $action eq "summary") {
 	git_summary();
 	exit;
@@ -235,6 +221,24 @@ if (!defined $action || $action eq "summ
 	exit;
 }
 
+## ======================================================================
+## validation, quoting/unquoting and escaping
+
+sub validate_input {
+	my $input = shift;
+
+	if ($input =~ m/^[0-9a-fA-F]{40}$/) {
+		return $input;
+	}
+	if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) {
+		return undef;
+	}
+	if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) {
+		return undef;
+	}
+	return $input;
+}
+
 # quote unsafe chars, but keep the slash, even when it's not
 # correct, but quoted slashes look too horrible in bookmarks
 sub esc_param {
@@ -264,6 +268,29 @@ sub unquote {
 	return $str;
 }
 
+## ----------------------------------------------------------------------
+## HTML aware string manipulation
+
+sub chop_str {
+	my $str = shift;
+	my $len = shift;
+	my $add_len = shift || 10;
+
+	# allow only $len chars, but don't cut a word if it would fit in $add_len
+	# if it doesn't fit, cut it if it's still longer than the dots we would add
+	$str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/;
+	my $body = $1;
+	my $tail = $2;
+	if (length($tail) > 4) {
+		$tail = " ...";
+		$body =~ s/&[^;]*$//; # remove chopped character entities
+	}
+	return "$body$tail";
+}
+
+## ----------------------------------------------------------------------
+## functions returning short strings
+
 # CSS class for given age value (in seconds)
 sub age_class {
 	my $age = shift;
@@ -277,202 +304,108 @@ sub age_class {
 	}
 }
 
-sub git_header_html {
-	my $status = shift || "200 OK";
-	my $expires = shift;
+# convert age in seconds to "nn units ago" string
+sub age_string {
+	my $age = shift;
+	my $age_str;
 
-	my $title = "$site_name git";
-	if (defined $project) {
-		$title .= " - $project";
-		if (defined $action) {
-			$title .= "/$action";
-			if (defined $file_name) {
-				$title .= " - $file_name";
-				if ($action eq "tree" && $file_name !~ m|/$|) {
-					$title .= "/";
-				}
-			}
-		}
-	}
-	my $content_type;
-	# require explicit support from the UA if we are to send the page as
-	# 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
-	# we have to do this because MSIE sometimes globs '*/*', pretending to
-	# support xhtml+xml but choking when it gets what it asked for.
-	if ($cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && $cgi->Accept('application/xhtml+xml') != 0) {
-		$content_type = 'application/xhtml+xml';
+	if ($age > 60*60*24*365*2) {
+		$age_str = (int $age/60/60/24/365);
+		$age_str .= " years ago";
+	} elsif ($age > 60*60*24*(365/12)*2) {
+		$age_str = int $age/60/60/24/(365/12);
+		$age_str .= " months ago";
+	} elsif ($age > 60*60*24*7*2) {
+		$age_str = int $age/60/60/24/7;
+		$age_str .= " weeks ago";
+	} elsif ($age > 60*60*24*2) {
+		$age_str = int $age/60/60/24;
+		$age_str .= " days ago";
+	} elsif ($age > 60*60*2) {
+		$age_str = int $age/60/60;
+		$age_str .= " hours ago";
+	} elsif ($age > 60*2) {
+		$age_str = int $age/60;
+		$age_str .= " min ago";
+	} elsif ($age > 2) {
+		$age_str = int $age;
+		$age_str .= " sec ago";
 	} else {
-		$content_type = 'text/html';
-	}
-	print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires);
-	print <<EOF;
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<!-- git web interface v$version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
-<!-- git core binaries version $git_version -->
-<head>
-<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
-<meta name="robots" content="index, nofollow"/>
-<title>$title</title>
-<link rel="stylesheet" type="text/css" href="$stylesheet"/>
-$rss_link
-</head>
-<body>
-EOF
-	print "<div class=\"page_header\">\n" .
-	      "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
-	      "<img src=\"$my_uri?" . esc_param("a=git-logo.png") . "\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
-	      "</a>\n";
-	print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
-	if (defined $project) {
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, esc_html($project));
-		if (defined $action) {
-			print " / $action";
-		}
-		print "\n";
-		if (!defined $searchtext) {
-			$searchtext = "";
-		}
-		my $search_hash;
-		if (defined $hash_base) {
-			$search_hash = $hash_base;
-		} elsif (defined $hash) {
-			$search_hash = $hash;
-		} else {
-			$search_hash = "HEAD";
-		}
-		$cgi->param("a", "search");
-		$cgi->param("h", $search_hash);
-		print $cgi->startform(-method => "get", -action => $my_uri) .
-		      "<div class=\"search\">\n" .
-		      $cgi->hidden(-name => "p") . "\n" .
-		      $cgi->hidden(-name => "a") . "\n" .
-		      $cgi->hidden(-name => "h") . "\n" .
-		      $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
-		      "</div>" .
-		      $cgi->end_form() . "\n";
+		$age_str .= " right now";
 	}
-	print "</div>\n";
+	return $age_str;
 }
 
-sub git_footer_html {
-	print "<div class=\"page_footer\">\n";
-	if (defined $project) {
-		my $descr = git_read_description($project);
-		if (defined $descr) {
-			print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
-		}
-		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=rss"), -class => "rss_logo"}, "RSS") . "\n";
+# convert file mode in octal to symbolic file mode string
+sub mode_str {
+	my $mode = oct shift;
+
+	if (S_ISDIR($mode & S_IFMT)) {
+		return 'drwxr-xr-x';
+	} elsif (S_ISLNK($mode)) {
+		return 'lrwxrwxrwx';
+	} elsif (S_ISREG($mode)) {
+		# git cares only about the executable bit
+		if ($mode & S_IXUSR) {
+			return '-rwxr-xr-x';
+		} else {
+			return '-rw-r--r--';
+		};
 	} else {
-		print $cgi->a({-href => "$my_uri?" . esc_param("a=opml"), -class => "rss_logo"}, "OPML") . "\n";
+		return '----------';
 	}
-	print "</div>\n" .
-	      "</body>\n" .
-	      "</html>";
 }
 
-sub die_error {
-	my $status = shift || "403 Forbidden";
-	my $error = shift || "Malformed query, file missing or permission denied";
+# convert file mode in octal to file type string
+sub file_type {
+	my $mode = oct shift;
 
-	git_header_html($status);
-	print "<div class=\"page_body\">\n" .
-	      "<br/><br/>\n" .
-	      "$status - $error\n" .
-	      "<br/>\n" .
-	      "</div>\n";
-	git_footer_html();
-	exit;
+	if (S_ISDIR($mode & S_IFMT)) {
+		return "directory";
+	} elsif (S_ISLNK($mode)) {
+		return "symlink";
+	} elsif (S_ISREG($mode)) {
+		return "file";
+	} else {
+		return "unknown";
+	}
 }
 
-sub git_page_nav {
-	my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
-	$extra = '' if !defined $extra; # pager or formats
+## ----------------------------------------------------------------------
+## functions returning short HTML fragments, or transforming HTML fragments
+## which don't beling to other sections
 
-	my @navs = qw(summary shortlog log commit commitdiff tree);
-	if ($suppress) {
-		@navs = grep { $_ ne $suppress } @navs;
-	}
+# format line of commit message or tag comment
+sub format_log_line_html {
+	my $line = shift;
 
-	my %arg = map { $_, ''} @navs;
-	if (defined $head) {
-		for (qw(commit commitdiff)) {
-			$arg{$_} = ";h=$head";
-		}
-		if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) {
-			for (qw(shortlog log)) {
-				$arg{$_} = ";h=$head";
-			}
+	$line = esc_html($line);
+	$line =~ s/ /&nbsp;/g;
+	if ($line =~ m/([0-9a-fA-F]{40})/) {
+		my $hash_text = $1;
+		if (git_get_type($hash_text) eq "commit") {
+			my $link = $cgi->a({-class => "text", -href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_text")}, $hash_text);
+			$line =~ s/$hash_text/$link/;
 		}
 	}
-	$arg{tree} .= ";h=$treehead" if defined $treehead;
-	$arg{tree} .= ";hb=$treebase" if defined $treebase;
-
-	print "<div class=\"page_nav\">\n" .
-		(join " | ",
-		 map { $_ eq $current
-					 ? $_
-					 : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
-				 }
-		 @navs);
-	print "<br/>\n$extra<br/>\n" .
-	      "</div>\n";
-}
-
-sub git_header_div {
-	my ($action, $title, $hash, $hash_base) = @_;
-	my $rest = '';
-
-	$rest .= ";h=$hash" if $hash;
-	$rest .= ";hb=$hash_base" if $hash_base;
-
-	print "<div class=\"header\">\n" .
-	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
-	               -class => "title"}, $title ? $title : $action) . "\n" .
-	      "</div>\n";
+	return $line;
 }
 
-sub git_get_paging_nav {
-	my ($action, $hash, $head, $page, $nrevs) = @_;
-	my $paging_nav;
-
-
-	if ($hash ne $head || $page) {
-		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action")}, "HEAD");
-	} else {
-		$paging_nav .= "HEAD";
-	}
-
-	if ($page > 0) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page-1)),
-							 -accesskey => "p", -title => "Alt-p"}, "prev");
-	} else {
-		$paging_nav .= " &sdot; prev";
-	}
+# format marker of refs pointing to given object
+sub git_get_referencing {
+	my ($refs, $id) = @_;
 
-	if ($nrevs >= (100 * ($page+1)-1)) {
-		$paging_nav .= " &sdot; " .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page+1)),
-							 -accesskey => "n", -title => "Alt-n"}, "next");
+	if (defined $refs->{$id}) {
+		return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
 	} else {
-		$paging_nav .= " &sdot; next";
+		return "";
 	}
-
-	return $paging_nav;
 }
 
-sub git_get_type {
-	my $hash = shift;
-
-	open my $fd, "-|", $GIT, "cat-file", '-t', $hash or return;
-	my $type = <$fd>;
-	close $fd or return;
-	chomp $type;
-	return $type;
-}
+## ----------------------------------------------------------------------
+## git utility subroutines, invoking git commands
 
+# get HEAD ref of given project as hash
 sub git_read_head {
 	my $project = shift;
 	my $oENV = $ENV{'GIT_DIR'};
@@ -491,6 +424,57 @@ sub git_read_head {
 	return $retval;
 }
 
+# get type of given object
+sub git_get_type {
+	my $hash = shift;
+
+	open my $fd, "-|", $GIT, "cat-file", '-t', $hash or return;
+	my $type = <$fd>;
+	close $fd or return;
+	chomp $type;
+	return $type;
+}
+
+sub git_get_project_config {
+	my $key = shift;
+
+	return unless ($key);
+	$key =~ s/^gitweb\.//;
+	return if ($key =~ m/\W/);
+
+	my $val = qx($GIT repo-config --get gitweb.$key);
+	return ($val);
+}
+
+sub git_get_project_config_bool {
+	my $val = git_get_project_config (@_);
+	if ($val and $val =~ m/true|yes|on/) {
+		return (1);
+	}
+	return; # implicit false
+}
+
+# get hash of given path at given ref
+sub git_get_hash_by_path {
+	my $base = shift;
+	my $path = shift || return undef;
+
+	my $tree = $base;
+
+	open my $fd, "-|", $GIT, "ls-tree", $base, "--", $path
+		or die_error(undef, "Open git-ls-tree failed.");
+	my $line = <$fd>;
+	close $fd or return undef;
+
+	#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
+	$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+	return $3;
+}
+
+## ......................................................................
+## git utility functions, directly accessing git repository
+
+# assumes that PATH is not symref
 sub git_read_hash {
 	my $path = shift;
 
@@ -513,6 +497,100 @@ sub git_read_description {
 	return $descr;
 }
 
+sub git_read_projects {
+	my @list;
+
+	if (-d $projects_list) {
+		# search in directory
+		my $dir = $projects_list;
+		opendir my ($dh), $dir or return undef;
+		while (my $dir = readdir($dh)) {
+			if (-e "$projectroot/$dir/HEAD") {
+				my $pr = {
+					path => $dir,
+				};
+				push @list, $pr
+			}
+		}
+		closedir($dh);
+	} elsif (-f $projects_list) {
+		# read from file(url-encoded):
+		# 'git%2Fgit.git Linus+Torvalds'
+		# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
+		# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
+		open my ($fd), $projects_list or return undef;
+		while (my $line = <$fd>) {
+			chomp $line;
+			my ($path, $owner) = split ' ', $line;
+			$path = unescape($path);
+			$owner = unescape($owner);
+			if (!defined $path) {
+				next;
+			}
+			if (-e "$projectroot/$path/HEAD") {
+				my $pr = {
+					path => $path,
+					owner => decode("utf8", $owner, Encode::FB_DEFAULT),
+				};
+				push @list, $pr
+			}
+		}
+		close $fd;
+	}
+	@list = sort {$a->{'path'} cmp $b->{'path'}} @list;
+	return @list;
+}
+
+sub read_info_ref {
+	my $type = shift || "";
+	my %refs;
+	# 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c	refs/tags/v2.6.11
+	# c39ae07f393806ccf406ef966e9a15afc43cc36a	refs/tags/v2.6.11^{}
+	open my $fd, "$projectroot/$project/info/refs" or return;
+	while (my $line = <$fd>) {
+		chomp $line;
+		# attention: for $type == "" it saves only last path part of ref name
+		# e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
+		if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
+			if (defined $refs{$1}) {
+				$refs{$1} .= " / $2";
+			} else {
+				$refs{$1} = $2;
+			}
+		}
+	}
+	close $fd or return;
+	return \%refs;
+}
+
+## ----------------------------------------------------------------------
+## parse to hash functions
+
+sub date_str {
+	my $epoch = shift;
+	my $tz = shift || "-0000";
+
+	my %date;
+	my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+	my @days = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
+	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($epoch);
+	$date{'hour'} = $hour;
+	$date{'minute'} = $min;
+	$date{'mday'} = $mday;
+	$date{'day'} = $days[$wday];
+	$date{'month'} = $months[$mon];
+	$date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000", $days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec;
+	$date{'mday-time'} = sprintf "%d %s %02d:%02d", $mday, $months[$mon], $hour ,$min;
+
+	$tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/;
+	my $local = $epoch + ((int $1 + ($2/60)) * 3600);
+	($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($local);
+	$date{'hour_local'} = $hour;
+	$date{'minute_local'} = $min;
+	$date{'tz_local'} = $tz;
+	return %date;
+}
+
 sub git_read_tag {
 	my $tag_id = shift;
 	my %tag;
@@ -548,37 +626,6 @@ sub git_read_tag {
 	return %tag
 }
 
-sub age_string {
-	my $age = shift;
-	my $age_str;
-
-	if ($age > 60*60*24*365*2) {
-		$age_str = (int $age/60/60/24/365);
-		$age_str .= " years ago";
-	} elsif ($age > 60*60*24*(365/12)*2) {
-		$age_str = int $age/60/60/24/(365/12);
-		$age_str .= " months ago";
-	} elsif ($age > 60*60*24*7*2) {
-		$age_str = int $age/60/60/24/7;
-		$age_str .= " weeks ago";
-	} elsif ($age > 60*60*24*2) {
-		$age_str = int $age/60/60/24;
-		$age_str .= " days ago";
-	} elsif ($age > 60*60*2) {
-		$age_str = int $age/60/60;
-		$age_str .= " hours ago";
-	} elsif ($age > 60*2) {
-		$age_str = int $age/60;
-		$age_str .= " min ago";
-	} elsif ($age > 2) {
-		$age_str = int $age;
-		$age_str .= " sec ago";
-	} else {
-		$age_str .= " right now";
-	}
-	return $age_str;
-}
-
 sub git_read_commit {
 	my $commit_id = shift;
 	my $commit_text = shift;
@@ -673,380 +720,8 @@ sub git_read_commit {
 	return %co;
 }
 
-sub git_diff_print {
-	my $from = shift;
-	my $from_name = shift;
-	my $to = shift;
-	my $to_name = shift;
-	my $format = shift || "html";
-
-	my $from_tmp = "/dev/null";
-	my $to_tmp = "/dev/null";
-	my $pid = $$;
-
-	# create tmp from-file
-	if (defined $from) {
-		$from_tmp = "$git_temp/gitweb_" . $$ . "_from";
-		open my $fd2, "> $from_tmp";
-		open my $fd, "-|", $GIT, "cat-file", "blob", $from;
-		my @file = <$fd>;
-		print $fd2 @file;
-		close $fd2;
-		close $fd;
-	}
-
-	# create tmp to-file
-	if (defined $to) {
-		$to_tmp = "$git_temp/gitweb_" . $$ . "_to";
-		open my $fd2, "> $to_tmp";
-		open my $fd, "-|", $GIT, "cat-file", "blob", $to;
-		my @file = <$fd>;
-		print $fd2 @file;
-		close $fd2;
-		close $fd;
-	}
-
-	open my $fd, "-|", "/usr/bin/diff -u -p -L \'$from_name\' -L \'$to_name\' $from_tmp $to_tmp";
-	if ($format eq "plain") {
-		undef $/;
-		print <$fd>;
-		$/ = "\n";
-	} else {
-		while (my $line = <$fd>) {
-			chomp $line;
-			my $char = substr($line, 0, 1);
-			my $diff_class = "";
-			if ($char eq '+') {
-				$diff_class = " add";
-			} elsif ($char eq "-") {
-				$diff_class = " rem";
-			} elsif ($char eq "@") {
-				$diff_class = " chunk_header";
-			} elsif ($char eq "\\") {
-				# skip errors
-				next;
-			}
-			while ((my $pos = index($line, "\t")) != -1) {
-				if (my $count = (8 - (($pos-1) % 8))) {
-					my $spaces = ' ' x $count;
-					$line =~ s/\t/$spaces/;
-				}
-			}
-			print "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
-		}
-	}
-	close $fd;
-
-	if (defined $from) {
-		unlink($from_tmp);
-	}
-	if (defined $to) {
-		unlink($to_tmp);
-	}
-}
-
-sub mode_str {
-	my $mode = oct shift;
-
-	if (S_ISDIR($mode & S_IFMT)) {
-		return 'drwxr-xr-x';
-	} elsif (S_ISLNK($mode)) {
-		return 'lrwxrwxrwx';
-	} elsif (S_ISREG($mode)) {
-		# git cares only about the executable bit
-		if ($mode & S_IXUSR) {
-			return '-rwxr-xr-x';
-		} else {
-			return '-rw-r--r--';
-		};
-	} else {
-		return '----------';
-	}
-}
-
-sub chop_str {
-	my $str = shift;
-	my $len = shift;
-	my $add_len = shift || 10;
-
-	# allow only $len chars, but don't cut a word if it would fit in $add_len
-	# if it doesn't fit, cut it if it's still longer than the dots we would add
-	$str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/;
-	my $body = $1;
-	my $tail = $2;
-	if (length($tail) > 4) {
-		$tail = " ...";
-		$body =~ s/&[^;]*$//; # remove chopped character entities
-	}
-	return "$body$tail";
-}
-
-sub file_type {
-	my $mode = oct shift;
-
-	if (S_ISDIR($mode & S_IFMT)) {
-		return "directory";
-	} elsif (S_ISLNK($mode)) {
-		return "symlink";
-	} elsif (S_ISREG($mode)) {
-		return "file";
-	} else {
-		return "unknown";
-	}
-}
-
-sub format_log_line_html {
-	my $line = shift;
-
-	$line = esc_html($line);
-	$line =~ s/ /&nbsp;/g;
-	if ($line =~ m/([0-9a-fA-F]{40})/) {
-		my $hash_text = $1;
-		if (git_get_type($hash_text) eq "commit") {
-			my $link = $cgi->a({-class => "text", -href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_text")}, $hash_text);
-			$line =~ s/$hash_text/$link/;
-		}
-	}
-	return $line;
-}
-
-sub date_str {
-	my $epoch = shift;
-	my $tz = shift || "-0000";
-
-	my %date;
-	my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
-	my @days = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
-	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($epoch);
-	$date{'hour'} = $hour;
-	$date{'minute'} = $min;
-	$date{'mday'} = $mday;
-	$date{'day'} = $days[$wday];
-	$date{'month'} = $months[$mon];
-	$date{'rfc2822'} = sprintf "%s, %d %s %4d %02d:%02d:%02d +0000", $days[$wday], $mday, $months[$mon], 1900+$year, $hour ,$min, $sec;
-	$date{'mday-time'} = sprintf "%d %s %02d:%02d", $mday, $months[$mon], $hour ,$min;
-
-	$tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/;
-	my $local = $epoch + ((int $1 + ($2/60)) * 3600);
-	($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($local);
-	$date{'hour_local'} = $hour;
-	$date{'minute_local'} = $min;
-	$date{'tz_local'} = $tz;
-	return %date;
-}
-
-# git-logo (cached in browser for one day)
-sub git_logo {
-	binmode STDOUT, ':raw';
-	print $cgi->header(-type => 'image/png', -expires => '+1d');
-	# cat git-logo.png | hexdump -e '16/1 " %02x"  "\n"' | sed 's/ /\\x/g'
-	print	"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
-		"\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
-		"\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
-		"\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
-		"\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
-		"\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
-		"\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
-		"\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
-		"\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
-		"\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
-		"\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
-		"\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
-		"\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
-}
-
-sub get_file_owner {
-	my $path = shift;
-
-	my ($dev, $ino, $mode, $nlink, $st_uid, $st_gid, $rdev, $size) = stat($path);
-	my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid($st_uid);
-	if (!defined $gcos) {
-		return undef;
-	}
-	my $owner = $gcos;
-	$owner =~ s/[,;].*$//;
-	return decode("utf8", $owner, Encode::FB_DEFAULT);
-}
-
-sub git_read_projects {
-	my @list;
-
-	if (-d $projects_list) {
-		# search in directory
-		my $dir = $projects_list;
-		opendir my ($dh), $dir or return undef;
-		while (my $dir = readdir($dh)) {
-			if (-e "$projectroot/$dir/HEAD") {
-				my $pr = {
-					path => $dir,
-				};
-				push @list, $pr
-			}
-		}
-		closedir($dh);
-	} elsif (-f $projects_list) {
-		# read from file(url-encoded):
-		# 'git%2Fgit.git Linus+Torvalds'
-		# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
-		# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
-		open my ($fd), $projects_list or return undef;
-		while (my $line = <$fd>) {
-			chomp $line;
-			my ($path, $owner) = split ' ', $line;
-			$path = unescape($path);
-			$owner = unescape($owner);
-			if (!defined $path) {
-				next;
-			}
-			if (-e "$projectroot/$path/HEAD") {
-				my $pr = {
-					path => $path,
-					owner => decode("utf8", $owner, Encode::FB_DEFAULT),
-				};
-				push @list, $pr
-			}
-		}
-		close $fd;
-	}
-	@list = sort {$a->{'path'} cmp $b->{'path'}} @list;
-	return @list;
-}
-
-sub git_get_project_config {
-	my $key = shift;
-
-	return unless ($key);
-	$key =~ s/^gitweb\.//;
-	return if ($key =~ m/\W/);
-
-	my $val = qx($GIT repo-config --get gitweb.$key);
-	return ($val);
-}
-
-sub git_get_project_config_bool {
-	my $val = git_get_project_config (@_);
-	if ($val and $val =~ m/true|yes|on/) {
-		return (1);
-	}
-	return; # implicit false
-}
-
-sub git_project_list {
-	my @list = git_read_projects();
-	my @projects;
-	if (!@list) {
-		die_error(undef, "No project found.");
-	}
-	foreach my $pr (@list) {
-		my $head = git_read_head($pr->{'path'});
-		if (!defined $head) {
-			next;
-		}
-		$ENV{'GIT_DIR'} = "$projectroot/$pr->{'path'}";
-		my %co = git_read_commit($head);
-		if (!%co) {
-			next;
-		}
-		$pr->{'commit'} = \%co;
-		if (!defined $pr->{'descr'}) {
-			my $descr = git_read_description($pr->{'path'}) || "";
-			$pr->{'descr'} = chop_str($descr, 25, 5);
-		}
-		if (!defined $pr->{'owner'}) {
-			$pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
-		}
-		push @projects, $pr;
-	}
-	git_header_html();
-	if (-f $home_text) {
-		print "<div class=\"index_include\">\n";
-		open (my $fd, $home_text);
-		print <$fd>;
-		close $fd;
-		print "</div>\n";
-	}
-	print "<table class=\"project_list\">\n" .
-	      "<tr>\n";
-	if (!defined($order) || (defined($order) && ($order eq "project"))) {
-		@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
-		print "<th>Project</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=project")}, "Project") . "</th>\n";
-	}
-	if (defined($order) && ($order eq "descr")) {
-		@projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
-		print "<th>Description</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=descr")}, "Description") . "</th>\n";
-	}
-	if (defined($order) && ($order eq "owner")) {
-		@projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
-		print "<th>Owner</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=owner")}, "Owner") . "</th>\n";
-	}
-	if (defined($order) && ($order eq "age")) {
-		@projects = sort {$a->{'commit'}{'age'} <=> $b->{'commit'}{'age'}} @projects;
-		print "<th>Last Change</th>\n";
-	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=age")}, "Last Change") . "</th>\n";
-	}
-	print "<th></th>\n" .
-	      "</tr>\n";
-	my $alternate = 0;
-	foreach my $pr (@projects) {
-		if ($alternate) {
-			print "<tr class=\"dark\">\n";
-		} else {
-			print "<tr class=\"light\">\n";
-		}
-		$alternate ^= 1;
-		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
-		      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
-		      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
-		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "</td>\n" .
-		      "<td class=\"link\">" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") .
-		      "</td>\n" .
-		      "</tr>\n";
-	}
-	print "</table>\n";
-	git_footer_html();
-}
-
-sub read_info_ref {
-	my $type = shift || "";
-	my %refs;
-	# 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c	refs/tags/v2.6.11
-	# c39ae07f393806ccf406ef966e9a15afc43cc36a	refs/tags/v2.6.11^{}
-	open my $fd, "$projectroot/$project/info/refs" or return;
-	while (my $line = <$fd>) {
-		chomp $line;
-		# attention: for $type == "" it saves only last path part of ref name
-		# e.g. from 'refs/heads/jn/gitweb' it would leave only 'gitweb'
-		if ($line =~ m/^([0-9a-fA-F]{40})\t.*$type\/([^\^]+)/) {
-			if (defined $refs{$1}) {
-				$refs{$1} .= " / $2";
-			} else {
-				$refs{$1} = $2;
-			}
-		}
-	}
-	close $fd or return;
-	return \%refs;
-}
-
-sub git_get_referencing {
-	my ($refs, $id) = @_;
-
-	if (defined $refs->{$id}) {
-		return ' <span class="tag">' . esc_html($refs->{$id}) . '</span>';
-	} else {
-		return "";
-	}
-}
+## ......................................................................
+## parse to array of hashes functions
 
 sub git_read_refs {
 	my $ref_dir = shift;
@@ -1115,6 +790,299 @@ sub git_read_refs {
 	return \@reflist;
 }
 
+## ----------------------------------------------------------------------
+## filesystem-related functions
+
+sub get_file_owner {
+	my $path = shift;
+
+	my ($dev, $ino, $mode, $nlink, $st_uid, $st_gid, $rdev, $size) = stat($path);
+	my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid($st_uid);
+	if (!defined $gcos) {
+		return undef;
+	}
+	my $owner = $gcos;
+	$owner =~ s/[,;].*$//;
+	return decode("utf8", $owner, Encode::FB_DEFAULT);
+}
+
+## ......................................................................
+## mimetype related functions
+
+sub mimetype_guess_file {
+	my $filename = shift;
+	my $mimemap = shift;
+	-r $mimemap or return undef;
+
+	my %mimemap;
+	open(MIME, $mimemap) or return undef;
+	while (<MIME>) {
+		my ($mime, $exts) = split(/\t+/);
+		my @exts = split(/\s+/, $exts);
+		foreach my $ext (@exts) {
+			$mimemap{$ext} = $mime;
+		}
+	}
+	close(MIME);
+
+	$filename =~ /\.(.*?)$/;
+	return $mimemap{$1};
+}
+
+sub mimetype_guess {
+	my $filename = shift;
+	my $mime;
+	$filename =~ /\./ or return undef;
+
+	if ($mimetypes_file) {
+		my $file = $mimetypes_file;
+		#$file =~ m#^/# or $file = "$projectroot/$path/$file";
+		$mime = mimetype_guess_file($filename, $file);
+	}
+	$mime ||= mimetype_guess_file($filename, '/etc/mime.types');
+	return $mime;
+}
+
+sub git_blob_plain_mimetype {
+	my $fd = shift;
+	my $filename = shift;
+
+	if ($filename) {
+		my $mime = mimetype_guess($filename);
+		$mime and return $mime;
+	}
+
+	# just in case
+	return $default_blob_plain_mimetype unless $fd;
+
+	if (-T $fd) {
+		return 'text/plain' .
+		       ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
+	} elsif (! $filename) {
+		return 'application/octet-stream';
+	} elsif ($filename =~ m/\.png$/i) {
+		return 'image/png';
+	} elsif ($filename =~ m/\.gif$/i) {
+		return 'image/gif';
+	} elsif ($filename =~ m/\.jpe?g$/i) {
+		return 'image/jpeg';
+	} else {
+		return 'application/octet-stream';
+	}
+}
+
+## ======================================================================
+## functions printing HTML: header, footer, error page
+
+sub git_header_html {
+	my $status = shift || "200 OK";
+	my $expires = shift;
+
+	my $title = "$site_name git";
+	if (defined $project) {
+		$title .= " - $project";
+		if (defined $action) {
+			$title .= "/$action";
+			if (defined $file_name) {
+				$title .= " - $file_name";
+				if ($action eq "tree" && $file_name !~ m|/$|) {
+					$title .= "/";
+				}
+			}
+		}
+	}
+	my $content_type;
+	# require explicit support from the UA if we are to send the page as
+	# 'application/xhtml+xml', otherwise send it as plain old 'text/html'.
+	# we have to do this because MSIE sometimes globs '*/*', pretending to
+	# support xhtml+xml but choking when it gets what it asked for.
+	if ($cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && $cgi->Accept('application/xhtml+xml') != 0) {
+		$content_type = 'application/xhtml+xml';
+	} else {
+		$content_type = 'text/html';
+	}
+	print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires);
+	print <<EOF;
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<!-- git web interface v$version, (C) 2005-2006, Kay Sievers <kay.sievers\@vrfy.org>, Christian Gierke -->
+<!-- git core binaries version $git_version -->
+<head>
+<meta http-equiv="content-type" content="$content_type; charset=utf-8"/>
+<meta name="robots" content="index, nofollow"/>
+<title>$title</title>
+<link rel="stylesheet" type="text/css" href="$stylesheet"/>
+$rss_link
+</head>
+<body>
+EOF
+	print "<div class=\"page_header\">\n" .
+	      "<a href=\"http://www.kernel.org/pub/software/scm/git/docs/\" title=\"git documentation\">" .
+	      "<img src=\"$my_uri?" . esc_param("a=git-logo.png") . "\" width=\"72\" height=\"27\" alt=\"git\" style=\"float:right; border-width:0px;\"/>" .
+	      "</a>\n";
+	print $cgi->a({-href => esc_param($home_link)}, "projects") . " / ";
+	if (defined $project) {
+		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, esc_html($project));
+		if (defined $action) {
+			print " / $action";
+		}
+		print "\n";
+		if (!defined $searchtext) {
+			$searchtext = "";
+		}
+		my $search_hash;
+		if (defined $hash_base) {
+			$search_hash = $hash_base;
+		} elsif (defined $hash) {
+			$search_hash = $hash;
+		} else {
+			$search_hash = "HEAD";
+		}
+		$cgi->param("a", "search");
+		$cgi->param("h", $search_hash);
+		print $cgi->startform(-method => "get", -action => $my_uri) .
+		      "<div class=\"search\">\n" .
+		      $cgi->hidden(-name => "p") . "\n" .
+		      $cgi->hidden(-name => "a") . "\n" .
+		      $cgi->hidden(-name => "h") . "\n" .
+		      $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+		      "</div>" .
+		      $cgi->end_form() . "\n";
+	}
+	print "</div>\n";
+}
+
+sub git_footer_html {
+	print "<div class=\"page_footer\">\n";
+	if (defined $project) {
+		my $descr = git_read_description($project);
+		if (defined $descr) {
+			print "<div class=\"page_footer_text\">" . esc_html($descr) . "</div>\n";
+		}
+		print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=rss"), -class => "rss_logo"}, "RSS") . "\n";
+	} else {
+		print $cgi->a({-href => "$my_uri?" . esc_param("a=opml"), -class => "rss_logo"}, "OPML") . "\n";
+	}
+	print "</div>\n" .
+	      "</body>\n" .
+	      "</html>";
+}
+
+sub die_error {
+	my $status = shift || "403 Forbidden";
+	my $error = shift || "Malformed query, file missing or permission denied";
+
+	git_header_html($status);
+	print "<div class=\"page_body\">\n" .
+	      "<br/><br/>\n" .
+	      "$status - $error\n" .
+	      "<br/>\n" .
+	      "</div>\n";
+	git_footer_html();
+	exit;
+}
+
+## ----------------------------------------------------------------------
+## functions printing or outputting HTML: navigation
+
+sub git_page_nav {
+	my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_;
+	$extra = '' if !defined $extra; # pager or formats
+
+	my @navs = qw(summary shortlog log commit commitdiff tree);
+	if ($suppress) {
+		@navs = grep { $_ ne $suppress } @navs;
+	}
+
+	my %arg = map { $_, ''} @navs;
+	if (defined $head) {
+		for (qw(commit commitdiff)) {
+			$arg{$_} = ";h=$head";
+		}
+		if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) {
+			for (qw(shortlog log)) {
+				$arg{$_} = ";h=$head";
+			}
+		}
+	}
+	$arg{tree} .= ";h=$treehead" if defined $treehead;
+	$arg{tree} .= ";hb=$treebase" if defined $treebase;
+
+	print "<div class=\"page_nav\">\n" .
+		(join " | ",
+		 map { $_ eq $current
+					 ? $_
+					 : $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$_$arg{$_}")}, "$_")
+				 }
+		 @navs);
+	print "<br/>\n$extra<br/>\n" .
+	      "</div>\n";
+}
+
+sub git_get_paging_nav {
+	my ($action, $hash, $head, $page, $nrevs) = @_;
+	my $paging_nav;
+
+
+	if ($hash ne $head || $page) {
+		$paging_nav .= $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action")}, "HEAD");
+	} else {
+		$paging_nav .= "HEAD";
+	}
+
+	if ($page > 0) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page-1)),
+							 -accesskey => "p", -title => "Alt-p"}, "prev");
+	} else {
+		$paging_nav .= " &sdot; prev";
+	}
+
+	if ($nrevs >= (100 * ($page+1)-1)) {
+		$paging_nav .= " &sdot; " .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action;h=$hash;pg=" . ($page+1)),
+							 -accesskey => "n", -title => "Alt-n"}, "next");
+	} else {
+		$paging_nav .= " &sdot; next";
+	}
+
+	return $paging_nav;
+}
+
+## ......................................................................
+## functions printing or outputting HTML: div
+
+sub git_header_div {
+	my ($action, $title, $hash, $hash_base) = @_;
+	my $rest = '';
+
+	$rest .= ";h=$hash" if $hash;
+	$rest .= ";hb=$hash_base" if $hash_base;
+
+	print "<div class=\"header\">\n" .
+	      $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$action$rest"),
+	               -class => "title"}, $title ? $title : $action) . "\n" .
+	      "</div>\n";
+}
+
+sub git_print_page_path {
+	my $name = shift;
+	my $type = shift;
+
+	if (!defined $name) {
+		print "<div class=\"page_path\"><b>/</b></div>\n";
+	} elsif ($type =~ "blob") {
+		print "<div class=\"page_path\"><b>" .
+			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;f=$file_name")}, esc_html($name)) . "</b><br/></div>\n";
+	} else {
+		print "<div class=\"page_path\"><b>" . esc_html($name) . "</b><br/></div>\n";
+	}
+}
+
+## ......................................................................
+## functions printing large fragments of HTML
+
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
@@ -1265,6 +1233,191 @@ sub git_heads_body {
 	print "</table>\n";
 }
 
+## ----------------------------------------------------------------------
+## functions printing large fragments, format as one of arguments
+
+sub git_diff_print {
+	my $from = shift;
+	my $from_name = shift;
+	my $to = shift;
+	my $to_name = shift;
+	my $format = shift || "html";
+
+	my $from_tmp = "/dev/null";
+	my $to_tmp = "/dev/null";
+	my $pid = $$;
+
+	# create tmp from-file
+	if (defined $from) {
+		$from_tmp = "$git_temp/gitweb_" . $$ . "_from";
+		open my $fd2, "> $from_tmp";
+		open my $fd, "-|", $GIT, "cat-file", "blob", $from;
+		my @file = <$fd>;
+		print $fd2 @file;
+		close $fd2;
+		close $fd;
+	}
+
+	# create tmp to-file
+	if (defined $to) {
+		$to_tmp = "$git_temp/gitweb_" . $$ . "_to";
+		open my $fd2, "> $to_tmp";
+		open my $fd, "-|", $GIT, "cat-file", "blob", $to;
+		my @file = <$fd>;
+		print $fd2 @file;
+		close $fd2;
+		close $fd;
+	}
+
+	open my $fd, "-|", "/usr/bin/diff -u -p -L \'$from_name\' -L \'$to_name\' $from_tmp $to_tmp";
+	if ($format eq "plain") {
+		undef $/;
+		print <$fd>;
+		$/ = "\n";
+	} else {
+		while (my $line = <$fd>) {
+			chomp $line;
+			my $char = substr($line, 0, 1);
+			my $diff_class = "";
+			if ($char eq '+') {
+				$diff_class = " add";
+			} elsif ($char eq "-") {
+				$diff_class = " rem";
+			} elsif ($char eq "@") {
+				$diff_class = " chunk_header";
+			} elsif ($char eq "\\") {
+				# skip errors
+				next;
+			}
+			while ((my $pos = index($line, "\t")) != -1) {
+				if (my $count = (8 - (($pos-1) % 8))) {
+					my $spaces = ' ' x $count;
+					$line =~ s/\t/$spaces/;
+				}
+			}
+			print "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
+		}
+	}
+	close $fd;
+
+	if (defined $from) {
+		unlink($from_tmp);
+	}
+	if (defined $to) {
+		unlink($to_tmp);
+	}
+}
+
+
+## ======================================================================
+## ======================================================================
+## actions
+
+# git-logo (cached in browser for one day)
+sub git_logo {
+	binmode STDOUT, ':raw';
+	print $cgi->header(-type => 'image/png', -expires => '+1d');
+	# cat git-logo.png | hexdump -e '16/1 " %02x"  "\n"' | sed 's/ /\\x/g'
+	print	"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
+		"\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
+		"\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
+		"\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
+		"\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
+		"\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
+		"\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
+		"\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
+		"\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
+		"\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
+		"\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
+		"\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
+		"\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
+}
+
+sub git_project_list {
+	my @list = git_read_projects();
+	my @projects;
+	if (!@list) {
+		die_error(undef, "No project found.");
+	}
+	foreach my $pr (@list) {
+		my $head = git_read_head($pr->{'path'});
+		if (!defined $head) {
+			next;
+		}
+		$ENV{'GIT_DIR'} = "$projectroot/$pr->{'path'}";
+		my %co = git_read_commit($head);
+		if (!%co) {
+			next;
+		}
+		$pr->{'commit'} = \%co;
+		if (!defined $pr->{'descr'}) {
+			my $descr = git_read_description($pr->{'path'}) || "";
+			$pr->{'descr'} = chop_str($descr, 25, 5);
+		}
+		if (!defined $pr->{'owner'}) {
+			$pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
+		}
+		push @projects, $pr;
+	}
+	git_header_html();
+	if (-f $home_text) {
+		print "<div class=\"index_include\">\n";
+		open (my $fd, $home_text);
+		print <$fd>;
+		close $fd;
+		print "</div>\n";
+	}
+	print "<table class=\"project_list\">\n" .
+	      "<tr>\n";
+	if (!defined($order) || (defined($order) && ($order eq "project"))) {
+		@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
+		print "<th>Project</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=project")}, "Project") . "</th>\n";
+	}
+	if (defined($order) && ($order eq "descr")) {
+		@projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
+		print "<th>Description</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=descr")}, "Description") . "</th>\n";
+	}
+	if (defined($order) && ($order eq "owner")) {
+		@projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
+		print "<th>Owner</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=owner")}, "Owner") . "</th>\n";
+	}
+	if (defined($order) && ($order eq "age")) {
+		@projects = sort {$a->{'commit'}{'age'} <=> $b->{'commit'}{'age'}} @projects;
+		print "<th>Last Change</th>\n";
+	} else {
+		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=age")}, "Last Change") . "</th>\n";
+	}
+	print "<th></th>\n" .
+	      "</tr>\n";
+	my $alternate = 0;
+	foreach my $pr (@projects) {
+		if ($alternate) {
+			print "<tr class=\"dark\">\n";
+		} else {
+			print "<tr class=\"light\">\n";
+		}
+		$alternate ^= 1;
+		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+		      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
+		      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
+		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "</td>\n" .
+		      "<td class=\"link\">" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary") .
+		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") .
+		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") .
+		      "</td>\n" .
+		      "</tr>\n";
+	}
+	print "</table>\n";
+	git_footer_html();
+}
+
 sub git_summary {
 	my $descr = git_read_description($project) || "none";
 	my $head = git_read_head($project);
@@ -1326,20 +1479,6 @@ sub git_summary {
 	git_footer_html();
 }
 
-sub git_print_page_path {
-	my $name = shift;
-	my $type = shift;
-
-	if (!defined $name) {
-		print "<div class=\"page_path\"><b>/</b></div>\n";
-	} elsif ($type =~ "blob") {
-		print "<div class=\"page_path\"><b>" .
-			$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;f=$file_name")}, esc_html($name)) . "</b><br/></div>\n";
-	} else {
-		print "<div class=\"page_path\"><b>" . esc_html($name) . "</b><br/></div>\n";
-	}
-}
-
 sub git_tag {
 	my $head = git_read_head($project);
 	git_header_html();
@@ -1546,84 +1685,6 @@ sub git_heads {
 	git_footer_html();
 }
 
-sub git_get_hash_by_path {
-	my $base = shift;
-	my $path = shift || return undef;
-
-	my $tree = $base;
-
-	open my $fd, "-|", $GIT, "ls-tree", $base, "--", $path
-		or die_error(undef, "Open git-ls-tree failed.");
-	my $line = <$fd>;
-	close $fd or return undef;
-
-	#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa	panic.c'
-	$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
-	return $3;
-}
-
-sub mimetype_guess_file {
-	my $filename = shift;
-	my $mimemap = shift;
-	-r $mimemap or return undef;
-
-	my %mimemap;
-	open(MIME, $mimemap) or return undef;
-	while (<MIME>) {
-		my ($mime, $exts) = split(/\t+/);
-		my @exts = split(/\s+/, $exts);
-		foreach my $ext (@exts) {
-			$mimemap{$ext} = $mime;
-		}
-	}
-	close(MIME);
-
-	$filename =~ /\.(.*?)$/;
-	return $mimemap{$1};
-}
-
-sub mimetype_guess {
-	my $filename = shift;
-	my $mime;
-	$filename =~ /\./ or return undef;
-
-	if ($mimetypes_file) {
-		my $file = $mimetypes_file;
-		#$file =~ m#^/# or $file = "$projectroot/$path/$file";
-		$mime = mimetype_guess_file($filename, $file);
-	}
-	$mime ||= mimetype_guess_file($filename, '/etc/mime.types');
-	return $mime;
-}
-
-sub git_blob_plain_mimetype {
-	my $fd = shift;
-	my $filename = shift;
-
-	if ($filename) {
-		my $mime = mimetype_guess($filename);
-		$mime and return $mime;
-	}
-
-	# just in case
-	return $default_blob_plain_mimetype unless $fd;
-
-	if (-T $fd) {
-		return 'text/plain' .
-		       ($default_text_plain_charset ? '; charset='.$default_text_plain_charset : '');
-	} elsif (! $filename) {
-		return 'application/octet-stream';
-	} elsif ($filename =~ m/\.png$/i) {
-		return 'image/png';
-	} elsif ($filename =~ m/\.gif$/i) {
-		return 'image/gif';
-	} elsif ($filename =~ m/\.jpe?g$/i) {
-		return 'image/jpeg';
-	} else {
-		return 'application/octet-stream';
-	}
-}
-
 sub git_blob_plain {
 	if (!defined $hash) {
 		if (defined $file_name) {
@@ -1793,98 +1854,6 @@ #			      " | " . $cgi->a({-href => "$my
 	git_footer_html();
 }
 
-sub git_rss {
-	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
-	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project) 
-		or die_error(undef, "Open git-rev-list failed.");
-	my @revlist = map { chomp; $_ } <$fd>;
-	close $fd or die_error(undef, "Reading rev-list failed.");
-	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
-	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
-	      "<rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n";
-	print "<channel>\n";
-	print "<title>$project</title>\n".
-	      "<link>" . esc_html("$my_url?p=$project;a=summary") . "</link>\n".
-	      "<description>$project log</description>\n".
-	      "<language>en</language>\n";
-
-	for (my $i = 0; $i <= $#revlist; $i++) {
-		my $commit = $revlist[$i];
-		my %co = git_read_commit($commit);
-		# we read 150, we always show 30 and the ones more recent than 48 hours
-		if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) {
-			last;
-		}
-		my %cd = date_str($co{'committer_epoch'});
-		open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next;
-		my @difftree = map { chomp; $_ } <$fd>;
-		close $fd or next;
-		print "<item>\n" .
-		      "<title>" .
-		      sprintf("%d %s %02d:%02d", $cd{'mday'}, $cd{'month'}, $cd{'hour'}, $cd{'minute'}) . " - " . esc_html($co{'title'}) .
-		      "</title>\n" .
-		      "<author>" . esc_html($co{'author'}) . "</author>\n" .
-		      "<pubDate>$cd{'rfc2822'}</pubDate>\n" .
-		      "<guid isPermaLink=\"true\">" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</guid>\n" .
-		      "<link>" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</link>\n" .
-		      "<description>" . esc_html($co{'title'}) . "</description>\n" .
-		      "<content:encoded>" .
-		      "<![CDATA[\n";
-		my $comment = $co{'comment'};
-		foreach my $line (@$comment) {
-			$line = decode("utf8", $line, Encode::FB_DEFAULT);
-			print "$line<br/>\n";
-		}
-		print "<br/>\n";
-		foreach my $line (@difftree) {
-			if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) {
-				next;
-			}
-			my $file = validate_input(unquote($7));
-			$file = decode("utf8", $file, Encode::FB_DEFAULT);
-			print "$file<br/>\n";
-		}
-		print "]]>\n" .
-		      "</content:encoded>\n" .
-		      "</item>\n";
-	}
-	print "</channel></rss>";
-}
-
-sub git_opml {
-	my @list = git_read_projects();
-
-	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
-	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
-	      "<opml version=\"1.0\">\n".
-	      "<head>".
-	      "  <title>$site_name Git OPML Export</title>\n".
-	      "</head>\n".
-	      "<body>\n".
-	      "<outline text=\"git RSS feeds\">\n";
-
-	foreach my $pr (@list) {
-		my %proj = %$pr;
-		my $head = git_read_head($proj{'path'});
-		if (!defined $head) {
-			next;
-		}
-		$ENV{'GIT_DIR'} = "$projectroot/$proj{'path'}";
-		my %co = git_read_commit($head);
-		if (!%co) {
-			next;
-		}
-
-		my $path = esc_html(chop_str($proj{'path'}, 25, 5));
-		my $rss  = "$my_url?p=$proj{'path'};a=rss";
-		my $html = "$my_url?p=$proj{'path'};a=summary";
-		print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
-	}
-	print "</outline>\n".
-	      "</body>\n".
-	      "</opml>\n";
-}
-
 sub git_log {
 	my $head = git_read_head($project);
 	if (!defined $hash) {
@@ -2556,3 +2525,98 @@ sub git_shortlog {
 
 	git_footer_html();
 }
+
+## ......................................................................
+## feeds (RSS, OPML)
+
+sub git_rss {
+	# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
+	open my $fd, "-|", $GIT, "rev-list", "--max-count=150", git_read_head($project)
+		or die_error(undef, "Open git-rev-list failed.");
+	my @revlist = map { chomp; $_ } <$fd>;
+	close $fd or die_error(undef, "Reading rev-list failed.");
+	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
+	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
+	      "<rss version=\"2.0\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n";
+	print "<channel>\n";
+	print "<title>$project</title>\n".
+	      "<link>" . esc_html("$my_url?p=$project;a=summary") . "</link>\n".
+	      "<description>$project log</description>\n".
+	      "<language>en</language>\n";
+
+	for (my $i = 0; $i <= $#revlist; $i++) {
+		my $commit = $revlist[$i];
+		my %co = git_read_commit($commit);
+		# we read 150, we always show 30 and the ones more recent than 48 hours
+		if (($i >= 20) && ((time - $co{'committer_epoch'}) > 48*60*60)) {
+			last;
+		}
+		my %cd = date_str($co{'committer_epoch'});
+		open $fd, "-|", $GIT, "diff-tree", '-r', $co{'parent'}, $co{'id'} or next;
+		my @difftree = map { chomp; $_ } <$fd>;
+		close $fd or next;
+		print "<item>\n" .
+		      "<title>" .
+		      sprintf("%d %s %02d:%02d", $cd{'mday'}, $cd{'month'}, $cd{'hour'}, $cd{'minute'}) . " - " . esc_html($co{'title'}) .
+		      "</title>\n" .
+		      "<author>" . esc_html($co{'author'}) . "</author>\n" .
+		      "<pubDate>$cd{'rfc2822'}</pubDate>\n" .
+		      "<guid isPermaLink=\"true\">" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</guid>\n" .
+		      "<link>" . esc_html("$my_url?p=$project;a=commit;h=$commit") . "</link>\n" .
+		      "<description>" . esc_html($co{'title'}) . "</description>\n" .
+		      "<content:encoded>" .
+		      "<![CDATA[\n";
+		my $comment = $co{'comment'};
+		foreach my $line (@$comment) {
+			$line = decode("utf8", $line, Encode::FB_DEFAULT);
+			print "$line<br/>\n";
+		}
+		print "<br/>\n";
+		foreach my $line (@difftree) {
+			if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) {
+				next;
+			}
+			my $file = validate_input(unquote($7));
+			$file = decode("utf8", $file, Encode::FB_DEFAULT);
+			print "$file<br/>\n";
+		}
+		print "]]>\n" .
+		      "</content:encoded>\n" .
+		      "</item>\n";
+	}
+	print "</channel></rss>";
+}
+
+sub git_opml {
+	my @list = git_read_projects();
+
+	print $cgi->header(-type => 'text/xml', -charset => 'utf-8');
+	print "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
+	      "<opml version=\"1.0\">\n".
+	      "<head>".
+	      "  <title>$site_name Git OPML Export</title>\n".
+	      "</head>\n".
+	      "<body>\n".
+	      "<outline text=\"git RSS feeds\">\n";
+
+	foreach my $pr (@list) {
+		my %proj = %$pr;
+		my $head = git_read_head($proj{'path'});
+		if (!defined $head) {
+			next;
+		}
+		$ENV{'GIT_DIR'} = "$projectroot/$proj{'path'}";
+		my %co = git_read_commit($head);
+		if (!%co) {
+			next;
+		}
+
+		my $path = esc_html(chop_str($proj{'path'}, 25, 5));
+		my $rss  = "$my_url?p=$proj{'path'};a=rss";
+		my $html = "$my_url?p=$proj{'path'};a=summary";
+		print "<outline type=\"rss\" text=\"$path\" title=\"$path\" xmlUrl=\"$rss\" htmlUrl=\"$html\"/>\n";
+	}
+	print "</outline>\n".
+	      "</body>\n".
+	      "</opml>\n";
+}
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH] gitweb: use a hash to lookup the sub for an action
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (19 preceding siblings ...)
  2006-07-31 18:48 ` [PATCH 20] gitweb: Reordering code and dividing it into categories Jakub Narebski
@ 2006-07-31 21:46 ` Matthias Lederhofer
  2006-07-31 22:39   ` Junio C Hamano
                     ` (2 more replies)
  2006-08-01  0:59 ` [PATCH 22] Jakub Narebski
                   ` (2 subsequent siblings)
  23 siblings, 3 replies; 54+ messages in thread
From: Matthias Lederhofer @ 2006-07-31 21:46 UTC (permalink / raw)
  To: git

Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
 gitweb/gitweb.cgi |   81 ++++++++++++++++-------------------------------------
 1 files changed, 25 insertions(+), 56 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index c1ee79e..75390c8 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -161,65 +161,34 @@ if (defined $searchtext) {
 }
 
 # dispatch
-if (!defined $action || $action eq "summary") {
-	git_summary();
-	exit;
-} elsif ($action eq "heads") {
-	git_heads();
-	exit;
-} elsif ($action eq "tags") {
-	git_tags();
-	exit;
-} elsif ($action eq "blob") {
-	git_blob();
-	exit;
-} elsif ($action eq "blob_plain") {
-	git_blob_plain();
-	exit;
-} elsif ($action eq "tree") {
-	git_tree();
-	exit;
-} elsif ($action eq "rss") {
-	git_rss();
-	exit;
-} elsif ($action eq "commit") {
-	git_commit();
-	exit;
-} elsif ($action eq "log") {
-	git_log();
-	exit;
-} elsif ($action eq "blobdiff") {
-	git_blobdiff();
-	exit;
-} elsif ($action eq "blobdiff_plain") {
-	git_blobdiff_plain();
-	exit;
-} elsif ($action eq "commitdiff") {
-	git_commitdiff();
-	exit;
-} elsif ($action eq "commitdiff_plain") {
-	git_commitdiff_plain();
-	exit;
-} elsif ($action eq "history") {
-	git_history();
-	exit;
-} elsif ($action eq "search") {
-	git_search();
-	exit;
-} elsif ($action eq "shortlog") {
-	git_shortlog();
-	exit;
-} elsif ($action eq "tag") {
-	git_tag();
-	exit;
-} elsif ($action eq "blame") {
-	git_blame2();
-	exit;
-} else {
+my %actions = (
+	"blame" => \&git_blame2,
+	"blobdiff" => \&git_blobdiff,
+	"blobdiff_plain" => \&git_blobdiff_plain,
+	"blob" => \&git_blob,
+	"blob_plain" => \&git_blob_plain,
+	"commitdiff" => \&git_commitdiff,
+	"commitdiff_plain" => \&git_commitdiff_plain,
+	"commit" => \&git_commit,
+	"heads" => \&git_heads,
+	"history" => \&git_history,
+	"log" => \&git_log,
+	"rss" => \&git_rss,
+	"search" => \&git_search,
+	"shortlog" => \&git_shortlog,
+	"summary" => \&git_summary,
+	"tag" => \&git_tag,
+	"tags" => \&git_tags,
+	"tree" => \&git_tree,
+);
+
+$action = 'summary' if (!defined($action));
+if (!defined($actions{$action})) {
 	undef $action;
 	die_error(undef, "Unknown action.");
-	exit;
 }
+$actions{$action}->();
+exit;
 
 ## ======================================================================
 ## validation, quoting/unquoting and escaping
-- 
1.4.2.rc2.ge0bed

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH] gitweb: use a hash to lookup the sub for an action
  2006-07-31 21:46 ` [PATCH] gitweb: use a hash to lookup the sub for an action Matthias Lederhofer
@ 2006-07-31 22:39   ` Junio C Hamano
  2006-07-31 22:55   ` [PATCH 21] " Jakub Narebski
  2006-08-01  2:50   ` [PATCH] " Luben Tuikov
  2 siblings, 0 replies; 54+ messages in thread
From: Junio C Hamano @ 2006-07-31 22:39 UTC (permalink / raw)
  To: Matthias Lederhofer; +Cc: git

Matthias Lederhofer <matled@gmx.net> writes:

> Signed-off-by: Matthias Lederhofer <matled@gmx.net>

Yeah, finally.  I like this.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 21] gitweb: use a hash to lookup the sub for an action
  2006-07-31 21:46 ` [PATCH] gitweb: use a hash to lookup the sub for an action Matthias Lederhofer
  2006-07-31 22:39   ` Junio C Hamano
@ 2006-07-31 22:55   ` Jakub Narebski
  2006-08-01  2:50   ` [PATCH] " Luben Tuikov
  2 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-07-31 22:55 UTC (permalink / raw)
  To: git

Matthias Lederhofer wrote:

> Signed-off-by: Matthias Lederhofer <matled@gmx.net>

Acked-by: Jakub Narebski <jnareb@gmail.com>

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 22]
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (20 preceding siblings ...)
  2006-07-31 21:46 ` [PATCH] gitweb: use a hash to lookup the sub for an action Matthias Lederhofer
@ 2006-08-01  0:59 ` Jakub Narebski
  2006-08-01  2:12   ` Perhaps an obvious cut and paste error Junio C Hamano
  2006-08-01  4:24   ` A few more fixups to gitweb Junio C Hamano
  2006-08-01 12:48 ` [PATCH] gitweb: clean up user configuration part Matthias Lederhofer
  2006-08-01 13:53 ` [RFC/PATCH] gitweb: include perl files for configuration Matthias Lederhofer
  23 siblings, 2 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-08-01  0:59 UTC (permalink / raw)
  To: git

>From d69d3357f134bb5548f18fafff7664499adc1fcd Mon Sep 17 00:00:00 2001
From: Jakub Narebski <jnareb@gmail.com>
Date: Tue, 1 Aug 2006 02:56:51 +0200
Subject: [PATCH] gitweb: Refactoring git_project_list

Slightly reworking git_project_list, including moving setting $order,
as it is used only in this action. Mostly reindent.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
After Matthias Lederhofer <matled@gmx.net> patch,
"[PATCH] gitweb: use a hash to lookup the sub for an action"

 gitweb/gitweb.cgi |   57 +++++++++++++++++++++++++++++++++--------------------
 1 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 75390c8..27c36ef 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -80,14 +80,6 @@ if (defined $action) {
 	}
 }
 
-our $order = $cgi->param('o');
-if (defined $order) {
-	if ($order =~ m/[^0-9a-zA-Z_]/) {
-		undef $order;
-		die_error(undef, "Invalid order parameter.");
-	}
-}
-
 our $project = ($cgi->param('p') || $ENV{'PATH_INFO'});
 if (defined $project) {
 	$project =~ s|^/||; $project =~ s|/$||;
@@ -1303,10 +1295,15 @@ sub git_logo {
 }
 
 sub git_project_list {
+	my $order = $cgi->param('o');
+	if (defined $order && $order !~ m/project|descr|owner|age/) {
+		die_error(undef, "Invalid order parameter '$order'.");
+	}
+
 	my @list = git_read_projects();
 	my @projects;
 	if (!@list) {
-		die_error(undef, "No project found.");
+		die_error(undef, "No projects found.");
 	}
 	foreach my $pr (@list) {
 		my $head = git_read_head($pr->{'path'});
@@ -1328,6 +1325,7 @@ sub git_project_list {
 		}
 		push @projects, $pr;
 	}
+
 	git_header_html();
 	if (-f $home_text) {
 		print "<div class=\"index_include\">\n";
@@ -1338,29 +1336,42 @@ sub git_project_list {
 	}
 	print "<table class=\"project_list\">\n" .
 	      "<tr>\n";
-	if (!defined($order) || (defined($order) && ($order eq "project"))) {
+	$order ||= "project";
+	if ($order eq "project") {
 		@projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
 		print "<th>Project</th>\n";
 	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=project")}, "Project") . "</th>\n";
+		print "<th>" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("o=project"),
+		               -class => "header"}, "Project") .
+		      "</th>\n";
 	}
-	if (defined($order) && ($order eq "descr")) {
+	if ($order eq "descr") {
 		@projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
 		print "<th>Description</th>\n";
 	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=descr")}, "Description") . "</th>\n";
+		print "<th>" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("o=descr"),
+		               -class => "header"}, "Description") .
+		      "</th>\n";
 	}
-	if (defined($order) && ($order eq "owner")) {
+	if ($order eq "owner") {
 		@projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
 		print "<th>Owner</th>\n";
 	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=owner")}, "Owner") . "</th>\n";
+		print "<th>" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("o=owner"),
+		               -class => "header"}, "Owner") .
+		      "</th>\n";
 	}
-	if (defined($order) && ($order eq "age")) {
+	if ($order eq "age") {
 		@projects = sort {$a->{'commit'}{'age'} <=> $b->{'commit'}{'age'}} @projects;
 		print "<th>Last Change</th>\n";
 	} else {
-		print "<th>" . $cgi->a({-class => "header", -href => "$my_uri?" . esc_param("o=age")}, "Last Change") . "</th>\n";
+		print "<th>" .
+		      $cgi->a({-href => "$my_uri?" . esc_param("o=age"),
+		               -class => "header"}, "Last Change") .
+		      "</th>\n";
 	}
 	print "<th></th>\n" .
 	      "</tr>\n";
@@ -1372,14 +1383,16 @@ sub git_project_list {
 			print "<tr class=\"light\">\n";
 		}
 		$alternate ^= 1;
-		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"), -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
+		print "<td>" . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary"),
+		                        -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" .
 		      "<td>" . esc_html($pr->{'descr'}) . "</td>\n" .
 		      "<td><i>" . chop_str($pr->{'owner'}, 15) . "</i></td>\n";
-		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" . $pr->{'commit'}{'age_string'} . "</td>\n" .
+		print "<td class=\"". age_class($pr->{'commit'}{'age'}) . "\">" .
+		      $pr->{'commit'}{'age_string'} . "</td>\n" .
 		      "<td class=\"link\">" .
-		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") .
-		      " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=summary")}, "summary")   . " | " .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=shortlog")}, "shortlog") . " | " .
+		      $cgi->a({-href => "$my_uri?" . esc_param("p=$pr->{'path'};a=log")}, "log") .
 		      "</td>\n" .
 		      "</tr>\n";
 	}
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Perhaps an obvious cut and paste error.
  2006-08-01  0:59 ` [PATCH 22] Jakub Narebski
@ 2006-08-01  2:12   ` Junio C Hamano
  2006-08-01  7:23     ` Jakub Narebski
  2006-08-01  4:24   ` A few more fixups to gitweb Junio C Hamano
  1 sibling, 1 reply; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  2:12 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 4e79390..a4a46d9 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -1441,7 +1434,7 @@ sub git_summary {
 	my $headlist = git_read_refs("refs/heads");
 	if (defined @$headlist) {
 		git_header_div('heads');
-		git_heads_body($taglist, $head, 0, 15,
+		git_heads_body($headlist, $head, 0, 15,
 		               $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads")}, "..."));
 	}
 

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 19] gitweb: No need to quote path for list version of open "-|"
  2006-07-31 19:00     ` Jakub Narebski
@ 2006-08-01  2:17       ` Junio C Hamano
  2006-08-01  2:18       ` There can be more than two levels of subdirectories Junio C Hamano
  1 sibling, 0 replies; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  2:17 UTC (permalink / raw)
  To: jnareb; +Cc: git

Jakub Narebski <jnareb@gmail.com> writes:

> <opublikowany i wysłany>
>
> Junio C Hamano wrote:
>
>> I suspect the patch title is wrong -- it is not "no need to" but
>> "quoting path breaks so do not do it" ;-).
>> 
>> I guess this fixes the problem I saw last night?
>
> If I remember correctly it worked without this patch, for git 1.4.1.1 
> (i.e. with --full-history option, although not working as advertised: see my
> comment earlier in thread).

Couldn't have worked, or you have found a bug in whatever
command you invoked.  If it is told to look for a path that
starts with a single quote it should have done so and produced
no history since there is no such file.

In any case, the patch #19 seems to fix the problem.  Thanks.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* There can be more than two levels of subdirectories
  2006-07-31 19:00     ` Jakub Narebski
  2006-08-01  2:17       ` Junio C Hamano
@ 2006-08-01  2:18       ` Junio C Hamano
  1 sibling, 0 replies; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  2:18 UTC (permalink / raw)
  To: jnareb; +Cc: git

Earlier code to read .git/refs/{tags,heads} hierarchy had a
hardcoded up-to-two-level assumption.  Lift it by using
File::Find.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---
diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 4e79390..902b96a 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -14,6 +14,7 @@ use CGI::Util qw(unescape);
 use CGI::Carp qw(fatalsToBrowser);
 use Encode;
 use Fcntl ':mode';
+use File::Find qw();
 binmode STDOUT, ':utf8';
 
 our $cgi = new CGI;
@@ -697,23 +698,14 @@ sub git_read_refs {
 	my @reflist;
 
 	my @refs;
-	opendir my $dh, "$projectroot/$project/$ref_dir";
-	while (my $dir = readdir($dh)) {
-		if ($dir =~ m/^\./) {
-			next;
-		}
-		if (-d "$projectroot/$project/$ref_dir/$dir") {
-			opendir my $dh2, "$projectroot/$project/$ref_dir/$dir";
-			my @subdirs = grep !m/^\./, readdir $dh2;
-			closedir($dh2);
-			foreach my $subdir (@subdirs) {
-				push @refs, "$dir/$subdir"
-			}
-			next;
+	my $pfxlen = length("$projectroot/$project/$ref_dir");
+	File::Find::find(sub {
+		return if (/^\./);
+		if (-f $_) {
+			push @refs, substr($File::Find::name, $pfxlen + 1);
 		}
-		push @refs, $dir;
-	}
-	closedir($dh);
+	}, "$projectroot/$project/$ref_dir");
+
 	foreach my $ref_file (@refs) {
 		my $ref_id = git_read_hash("$project/$ref_dir/$ref_file");
 		my $type = git_get_type($ref_id) || next;

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH] gitweb: use a hash to lookup the sub for an action
  2006-07-31 21:46 ` [PATCH] gitweb: use a hash to lookup the sub for an action Matthias Lederhofer
  2006-07-31 22:39   ` Junio C Hamano
  2006-07-31 22:55   ` [PATCH 21] " Jakub Narebski
@ 2006-08-01  2:50   ` Luben Tuikov
  2 siblings, 0 replies; 54+ messages in thread
From: Luben Tuikov @ 2006-08-01  2:50 UTC (permalink / raw)
  To: Matthias Lederhofer, git

--- Matthias Lederhofer <matled@gmx.net> wrote:
> Signed-off-by: Matthias Lederhofer <matled@gmx.net>

That's a great patch.

   Luben

> ---
>  gitweb/gitweb.cgi |   81 ++++++++++++++++-------------------------------------
>  1 files changed, 25 insertions(+), 56 deletions(-)
> 
> diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
> index c1ee79e..75390c8 100755
> --- a/gitweb/gitweb.cgi
> +++ b/gitweb/gitweb.cgi
> @@ -161,65 +161,34 @@ if (defined $searchtext) {
>  }
>  
>  # dispatch
> -if (!defined $action || $action eq "summary") {
> -	git_summary();
> -	exit;
> -} elsif ($action eq "heads") {
> -	git_heads();
> -	exit;
> -} elsif ($action eq "tags") {
> -	git_tags();
> -	exit;
> -} elsif ($action eq "blob") {
> -	git_blob();
> -	exit;
> -} elsif ($action eq "blob_plain") {
> -	git_blob_plain();
> -	exit;
> -} elsif ($action eq "tree") {
> -	git_tree();
> -	exit;
> -} elsif ($action eq "rss") {
> -	git_rss();
> -	exit;
> -} elsif ($action eq "commit") {
> -	git_commit();
> -	exit;
> -} elsif ($action eq "log") {
> -	git_log();
> -	exit;
> -} elsif ($action eq "blobdiff") {
> -	git_blobdiff();
> -	exit;
> -} elsif ($action eq "blobdiff_plain") {
> -	git_blobdiff_plain();
> -	exit;
> -} elsif ($action eq "commitdiff") {
> -	git_commitdiff();
> -	exit;
> -} elsif ($action eq "commitdiff_plain") {
> -	git_commitdiff_plain();
> -	exit;
> -} elsif ($action eq "history") {
> -	git_history();
> -	exit;
> -} elsif ($action eq "search") {
> -	git_search();
> -	exit;
> -} elsif ($action eq "shortlog") {
> -	git_shortlog();
> -	exit;
> -} elsif ($action eq "tag") {
> -	git_tag();
> -	exit;
> -} elsif ($action eq "blame") {
> -	git_blame2();
> -	exit;
> -} else {
> +my %actions = (
> +	"blame" => \&git_blame2,
> +	"blobdiff" => \&git_blobdiff,
> +	"blobdiff_plain" => \&git_blobdiff_plain,
> +	"blob" => \&git_blob,
> +	"blob_plain" => \&git_blob_plain,
> +	"commitdiff" => \&git_commitdiff,
> +	"commitdiff_plain" => \&git_commitdiff_plain,
> +	"commit" => \&git_commit,
> +	"heads" => \&git_heads,
> +	"history" => \&git_history,
> +	"log" => \&git_log,
> +	"rss" => \&git_rss,
> +	"search" => \&git_search,
> +	"shortlog" => \&git_shortlog,
> +	"summary" => \&git_summary,
> +	"tag" => \&git_tag,
> +	"tags" => \&git_tags,
> +	"tree" => \&git_tree,
> +);
> +
> +$action = 'summary' if (!defined($action));
> +if (!defined($actions{$action})) {
>  	undef $action;
>  	die_error(undef, "Unknown action.");
> -	exit;
>  }
> +$actions{$action}->();
> +exit;
>  
>  ## ======================================================================
>  ## validation, quoting/unquoting and escaping
> -- 
> 1.4.2.rc2.ge0bed
> 
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 54+ messages in thread

* A few more fixups to gitweb
  2006-08-01  0:59 ` [PATCH 22] Jakub Narebski
  2006-08-01  2:12   ` Perhaps an obvious cut and paste error Junio C Hamano
@ 2006-08-01  4:24   ` Junio C Hamano
  2006-08-01  7:36     ` Jakub Narebski
  2006-08-01 20:10     ` A few more fixups to gitweb Luben Tuikov
  1 sibling, 2 replies; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  4:24 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git, Martin Langhoff, Luben Tuikov, Matthias Lederhofer

I've applied most of the recent gitweb changes from the list
(except the one that processes gitweb.perl into gitweb.cgi, not
because I am opposed to it, but because merging it early would
make things a bit more inconvenient while many patches are in
flight on the list) and fixed up a few things I noticed.  I'll
be pushing out the results on "next" branch shortly, so if
people want to hack on gitweb further please base your changes
on this version (I am CC'ing this message to people who recently
worked on, or expressed interest in working on gitweb).

One thing to note.  Please make sure that you do not see
anything in Apache error log after you make your changes.  I do
not remember the details but kernel.org folks were very unhappy
earlier when gitweb spewed stuff into the error log, and if I
recall correctly things that output to the error stream were not
friendly to the http-server cache for some reason.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: Perhaps an obvious cut and paste error.
  2006-08-01  2:12   ` Perhaps an obvious cut and paste error Junio C Hamano
@ 2006-08-01  7:23     ` Jakub Narebski
  0 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-08-01  7:23 UTC (permalink / raw)
  To: git

Junio C Hamano wrote:

> diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
> index 4e79390..a4a46d9 100755
> --- a/gitweb/gitweb.cgi
> +++ b/gitweb/gitweb.cgi
> @@ -1441,7 +1434,7 @@ sub git_summary {
>       my $headlist = git_read_refs("refs/heads");
>       if (defined @$headlist) {
>               git_header_div('heads');
> -             git_heads_body($taglist, $head, 0, 15,
> +             git_heads_body($headlist, $head, 0, 15,
>                              $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=heads")}, "..."));
>       }
>  
> 

Yes, of course. ACK.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: A few more fixups to gitweb
  2006-08-01  4:24   ` A few more fixups to gitweb Junio C Hamano
@ 2006-08-01  7:36     ` Jakub Narebski
  2006-08-01  8:04       ` Junio C Hamano
  2006-08-01 20:10     ` A few more fixups to gitweb Luben Tuikov
  1 sibling, 1 reply; 54+ messages in thread
From: Jakub Narebski @ 2006-08-01  7:36 UTC (permalink / raw)
  To: git

Junio C Hamano wrote:

> One thing to note.  Please make sure that you do not see
> anything in Apache error log after you make your changes.  I do
> not remember the details but kernel.org folks were very unhappy
> earlier when gitweb spewed stuff into the error log, and if I
> recall correctly things that output to the error stream were not
> friendly to the http-server cache for some reason.

By the way, I wonder why git when cloning/fetching via http protocol
uses e.g. "git/1.4.2.rc2.ge0bed" as User-Agent: string when fetching objects
and packs, and e.g. "curl/7.15.4 (i486-pc-linux-gnu) libcurl/7.15.4
OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" as User-Agent: when fetching refs
(heads and tags) and info/refs.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: A few more fixups to gitweb
  2006-08-01  7:36     ` Jakub Narebski
@ 2006-08-01  8:04       ` Junio C Hamano
  2006-08-01  9:34         ` [PATCH 1/2] Use tabs for indent in shell scripts Jakub Narebski
  0 siblings, 1 reply; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  8:04 UTC (permalink / raw)
  To: jnareb; +Cc: git

Jakub Narebski <jnareb@gmail.com> writes:

> By the way, I wonder why git when cloning/fetching via http protocol
> uses e.g. "git/1.4.2.rc2.ge0bed" as User-Agent: string when fetching objects
> and packs, and e.g. "curl/7.15.4 (i486-pc-linux-gnu) libcurl/7.15.4
> OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" as User-Agent: when fetching refs
> (heads and tags) and info/refs.

"Why?", meaning if we deliberately do so for some good reason?

There isn't.

git-http-fetch uses its own User-Agent string, but the shell
script wrappers that use curl executable do not bother setting
customized User-Agent string; that is why.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 1/2] Use tabs for indent in shell scripts
  2006-08-01  8:04       ` Junio C Hamano
@ 2006-08-01  9:34         ` Jakub Narebski
  2006-08-01  9:36           ` [PATCH 2/2] Set User-Agent string in shell scripts used for fetching Jakub Narebski
  2006-08-01  9:50           ` [PATCH 1/2] Use tabs for indent in shell scripts Junio C Hamano
  0 siblings, 2 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-08-01  9:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Consistently use tabs for indenting in some shell scripts.  Needs
checking for consistency (command1 && command2 && command3 split into
lines).

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 git-clone.sh     |   94 +++++-----
 git-fetch.sh     |  493 +++++++++++++++++++++++++++---------------------------
 git-ls-remote.sh |   50 +++--
 3 files changed, 319 insertions(+), 318 deletions(-)

diff --git a/git-clone.sh b/git-clone.sh
index a92b22a..adb752d 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -18,7 +18,7 @@ get_repo_base() {
 }
 
 if [ -n "$GIT_SSL_NO_VERIFY" ]; then
-    curl_extra_args="-k"
+	curl_extra_args="-k"
 fi
 
 http_fetch () {
@@ -43,7 +43,7 @@ Perhaps git-update-server-info needs to 
 		*^*)	continue;;
 		esac
 		if test -n "$use_separate_remote" &&
-		   branch_name=`expr "z$name" : 'zheads/\(.*\)'`
+			branch_name=`expr "z$name" : 'zheads/\(.*\)'`
 		then
 			tname="remotes/$origin/$branch_name"
 		else
@@ -119,13 +119,13 @@ while
 	*,--na|*,--nak|*,--nake|*,--naked|\
 	*,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
 	*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
-        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
-          local_shared=yes; use_local=yes ;;
+	*,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
+		local_shared=yes; use_local=yes ;;
 	1,--template) usage ;;
 	*,--template)
 		shift; template="--template=$1" ;;
 	*,--template=*)
-	  template="$1" ;;
+		template="$1" ;;
 	*,-q|*,--quiet) quiet=-q ;;
 	*,--use-separate-remote)
 		use_separate_remote=t ;;
@@ -137,18 +137,18 @@ while
 	*,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin)
 		case "$2" in
 		'')
-		    usage ;;
+			usage ;;
 		*/*)
-		    echo >&2 "'$2' is not suitable for an origin name"
-		    exit 1
+			echo >&2 "'$2' is not suitable for an origin name"
+			exit 1
 		esac
 		git-check-ref-format "heads/$2" || {
-		    echo >&2 "'$2' is not suitable for a branch name"
-		    exit 1
+			echo >&2 "'$2' is not suitable for a branch name"
+			exit 1
 		}
 		test -z "$origin_override" || {
-		    echo >&2 "Do not give more than one --origin options."
-		    exit 1
+			echo >&2 "Do not give more than one --origin options."
+			exit 1
 		}
 		origin_override=yes
 		origin="$2"; shift
@@ -167,8 +167,8 @@ done
 repo="$1"
 if test -z "$repo"
 then
-    echo >&2 'you must specify a repository to clone.'
-    exit 1
+	echo >&2 'you must specify a repository to clone.'
+	exit 1
 fi
 
 # --bare implies --no-checkout
@@ -225,9 +225,9 @@ then
 		echo "$reference/objects" >"$GIT_DIR/objects/info/alternates"
 		(cd "$reference" && tar cf - refs) |
 		(cd "$GIT_DIR/refs" &&
-		 mkdir reference-tmp &&
-		 cd reference-tmp &&
-		 tar xf -)
+			mkdir reference-tmp &&
+			cd reference-tmp &&
+			tar xf -)
 	else
 		echo >&2 "$reference: not a local directory." && usage
 	fi
@@ -245,26 +245,26 @@ yes,yes)
 
 	case "$local_shared" in
 	no)
-	    # See if we can hardlink and drop "l" if not.
-	    sample_file=$(cd "$repo" && \
-			  find objects -type f -print | sed -e 1q)
+		# See if we can hardlink and drop "l" if not.
+		sample_file=$(cd "$repo" && \
+			find objects -type f -print | sed -e 1q)
 
-	    # objects directory should not be empty since we are cloning!
-	    test -f "$repo/$sample_file" || exit
+		# objects directory should not be empty since we are cloning!
+		test -f "$repo/$sample_file" || exit
 
-	    l=
-	    if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
-	    then
-		    l=l
-	    fi &&
-	    rm -f "$GIT_DIR/objects/sample" &&
-	    cd "$repo" &&
-	    find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
-	    ;;
+		l=
+		if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
+		then
+			l=l
+		fi &&
+		rm -f "$GIT_DIR/objects/sample" &&
+		cd "$repo" &&
+		find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
+		;;
 	yes)
-	    mkdir -p "$GIT_DIR/objects/info"
-	    echo "$repo/objects" >> "$GIT_DIR/objects/info/alternates"
-	    ;;
+		mkdir -p "$GIT_DIR/objects/info"
+		echo "$repo/objects" >> "$GIT_DIR/objects/info/alternates"
+		;;
 	esac
 	git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
 	;;
@@ -282,19 +282,19 @@ yes,yes)
 			rm -f "$GIT_DIR/TMP_ALT"
 		if test -f "$GIT_DIR/TMP_ALT"
 		then
-		    ( cd "$D" &&
-		      . git-parse-remote &&
-		      resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) |
-		    while read alt
-		    do
-			case "$alt" in 'bad alternate: '*) die "$alt";; esac
-			case "$quiet" in
-			'')	echo >&2 "Getting alternate: $alt" ;;
-			esac
-			rsync $quiet -av --ignore-existing  \
-			    --exclude info "$alt" "$GIT_DIR/objects" || exit
-		    done
-		    rm -f "$GIT_DIR/TMP_ALT"
+			( cd "$D" &&
+				. git-parse-remote &&
+				resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) |
+			while read alt
+			do
+				case "$alt" in 'bad alternate: '*) die "$alt";; esac
+				case "$quiet" in
+				'')	echo >&2 "Getting alternate: $alt" ;;
+				esac
+				rsync $quiet -av --ignore-existing  \
+					--exclude info "$alt" "$GIT_DIR/objects" || exit
+			done
+			rm -f "$GIT_DIR/TMP_ALT"
 		fi
 		git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
 		;;
diff --git a/git-fetch.sh b/git-fetch.sh
index c2eebee..cea6e0b 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -90,124 +90,124 @@ then
 fi
 
 append_fetch_head () {
-    head_="$1"
-    remote_="$2"
-    remote_name_="$3"
-    remote_nick_="$4"
-    local_name_="$5"
-    case "$6" in
-    t) not_for_merge_='not-for-merge' ;;
-    '') not_for_merge_= ;;
-    esac
+	head_="$1"
+	remote_="$2"
+	remote_name_="$3"
+	remote_nick_="$4"
+	local_name_="$5"
+	case "$6" in
+		t) not_for_merge_='not-for-merge' ;;
+		'') not_for_merge_= ;;
+	esac
 
-    # remote-nick is the URL given on the command line (or a shorthand)
-    # remote-name is the $GIT_DIR relative refs/ path we computed
-    # for this refspec.
+	# remote-nick is the URL given on the command line (or a shorthand)
+	# remote-name is the $GIT_DIR relative refs/ path we computed
+	# for this refspec.
 
-    # the $note_ variable will be fed to git-fmt-merge-msg for further
-    # processing.
-    case "$remote_name_" in
-    HEAD)
-	note_= ;;
-    refs/heads/*)
-	note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
-	note_="branch '$note_' of " ;;
-    refs/tags/*)
-	note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
-	note_="tag '$note_' of " ;;
-    refs/remotes/*)
-	note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
-	note_="remote branch '$note_' of " ;;
-    *)
-	note_="$remote_name of " ;;
-    esac
-    remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
+	# the $note_ variable will be fed to git-fmt-merge-msg for further
+	# processing.
+	case "$remote_name_" in
+	HEAD)
+		note_= ;;
+	refs/heads/*)
+		note_="$(expr "$remote_name_" : 'refs/heads/\(.*\)')"
+		note_="branch '$note_' of " ;;
+	refs/tags/*)
+		note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
+		note_="tag '$note_' of " ;;
+	refs/remotes/*)
+		note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
+		note_="remote branch '$note_' of " ;;
+	*)
+		note_="$remote_name of " ;;
+	esac
+	remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
 	remote_="$remote_1_"
-    note_="$note_$remote_"
+	note_="$note_$remote_"
 
-    # 2.6.11-tree tag would not be happy to be fed to resolve.
-    if git-cat-file commit "$head_" >/dev/null 2>&1
-    then
-	headc_=$(git-rev-parse --verify "$head_^0") || exit
-	echo "$headc_	$not_for_merge_	$note_" >>"$GIT_DIR/FETCH_HEAD"
-	[ "$verbose" ] && echo >&2 "* committish: $head_"
-	[ "$verbose" ] && echo >&2 "  $note_"
-    else
-	echo "$head_	not-for-merge	$note_" >>"$GIT_DIR/FETCH_HEAD"
-	[ "$verbose" ] && echo >&2 "* non-commit: $head_"
-	[ "$verbose" ] && echo >&2 "  $note_"
-    fi
-    if test "$local_name_" != ""
-    then
-	# We are storing the head locally.  Make sure that it is
-	# a fast forward (aka "reverse push").
-	fast_forward_local "$local_name_" "$head_" "$note_"
-    fi
+	# 2.6.11-tree tag would not be happy to be fed to resolve.
+	if git-cat-file commit "$head_" >/dev/null 2>&1
+	then
+		headc_=$(git-rev-parse --verify "$head_^0") || exit
+		echo "$headc_	$not_for_merge_	$note_" >>"$GIT_DIR/FETCH_HEAD"
+		[ "$verbose" ] && echo >&2 "* committish: $head_"
+		[ "$verbose" ] && echo >&2 "  $note_"
+	else
+		echo "$head_	not-for-merge	$note_" >>"$GIT_DIR/FETCH_HEAD"
+		[ "$verbose" ] && echo >&2 "* non-commit: $head_"
+		[ "$verbose" ] && echo >&2 "  $note_"
+	fi
+	if test "$local_name_" != ""
+	then
+		# We are storing the head locally.  Make sure that it is
+		# a fast forward (aka "reverse push").
+		fast_forward_local "$local_name_" "$head_" "$note_"
+	fi
 }
 
 fast_forward_local () {
-    mkdir -p "$(dirname "$GIT_DIR/$1")"
-    case "$1" in
-    refs/tags/*)
-	# Tags need not be pointing at commits so there
-	# is no way to guarantee "fast-forward" anyway.
-	if test -f "$GIT_DIR/$1"
-	then
-		if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
+	mkdir -p "$(dirname "$GIT_DIR/$1")"
+	case "$1" in
+	refs/tags/*)
+		# Tags need not be pointing at commits so there
+		# is no way to guarantee "fast-forward" anyway.
+		if test -f "$GIT_DIR/$1"
 		then
-			[ "$verbose" ] && echo >&2 "* $1: same as $3" ||:
+			if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
+			then
+				[ "$verbose" ] && echo >&2 "* $1: same as $3" ||:
+			else
+				echo >&2 "* $1: updating with $3"
+				git-update-ref -m "$rloga: updating tag" "$1" "$2"
+			fi
 		else
-			echo >&2 "* $1: updating with $3"
-			git-update-ref -m "$rloga: updating tag" "$1" "$2"
+			echo >&2 "* $1: storing $3"
+			git-update-ref -m "$rloga: storing tag" "$1" "$2"
 		fi
-	else
-		echo >&2 "* $1: storing $3"
-		git-update-ref -m "$rloga: storing tag" "$1" "$2"
-	fi
-	;;
+		;;
 
-    refs/heads/* | refs/remotes/*)
-	# $1 is the ref being updated.
-	# $2 is the new value for the ref.
-	local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
-	if test "$local"
-	then
-	    # Require fast-forward.
-	    mb=$(git-merge-base "$local" "$2") &&
-	    case "$2,$mb" in
-	    $local,*)
-	        if test -n "$verbose"
+	refs/heads/* | refs/remotes/*)
+		# $1 is the ref being updated.
+		# $2 is the new value for the ref.
+		local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
+		if test "$local"
 		then
-			echo >&2 "* $1: same as $3"
+			# Require fast-forward.
+			mb=$(git-merge-base "$local" "$2") &&
+			case "$2,$mb" in
+			$local,*)
+				if test -n "$verbose"
+				then
+					echo >&2 "* $1: same as $3"
+				fi
+				;;
+			*,$local)
+				echo >&2 "* $1: fast forward to $3"
+				echo >&2 "  from $local to $2"
+				git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
+				;;
+			*)
+				false
+				;;
+			esac || {
+				echo >&2 "* $1: does not fast forward to $3;"
+				case ",$force,$single_force," in
+				*,t,*)
+					echo >&2 "  forcing update."
+					git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local"
+					;;
+				*)
+					echo >&2 "  not updating."
+					exit 1
+					;;
+				esac
+			}
+		else
+			echo >&2 "* $1: storing $3"
+			git-update-ref -m "$rloga: storing head" "$1" "$2"
 		fi
 		;;
-	    *,$local)
-		echo >&2 "* $1: fast forward to $3"
-		echo >&2 "  from $local to $2"
-		git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
-		;;
-	    *)
-		false
-		;;
-	    esac || {
-		echo >&2 "* $1: does not fast forward to $3;"
-		case ",$force,$single_force," in
-		*,t,*)
-			echo >&2 "  forcing update."
-			git-update-ref -m "$rloga: forced-update" "$1" "$2" "$local"
-			;;
-		*)
-			echo >&2 "  not updating."
-			exit 1
-			;;
-		esac
-	    }
-	else
-	    echo >&2 "* $1: storing $3"
-	    git-update-ref -m "$rloga: storing head" "$1" "$2"
-	fi
-	;;
-    esac
+	esac
 }
 
 case "$update_head_ok" in
@@ -225,26 +225,27 @@ reflist=$(get_remote_refs_for_fetch "$@"
 if test "$tags"
 then
 	taglist=`IFS="	" &&
-		  (
+		(
 			git-ls-remote $upload_pack --tags "$remote" ||
 			echo fail ouch
-		  ) |
-	          while read sha1 name
-		  do
+		) |
+		while read sha1 name
+		do
 			case "$sha1" in
 			fail)
 				exit 1
 			esac
 			case "$name" in
-			*^*) continue ;;
+			*^*)
+				continue ;;
 			esac
-		  	if git-check-ref-format "$name"
+			if git-check-ref-format "$name"
 			then
-			    echo ".${name}:${name}"
+				echo ".${name}:${name}"
 			else
-			    echo >&2 "warning: tag ${name} ignored"
+				echo >&2 "warning: tag ${name} ignored"
 			fi
-		  done` || exit
+		done` || exit
 	if test "$#" -gt 1
 	then
 		# remote URL plus explicit refspecs; we need to merge them.
@@ -256,146 +257,146 @@ then
 fi
 
 fetch_main () {
-  reflist="$1"
-  refs=
+	reflist="$1"
+	refs=
 
-  for ref in $reflist
-  do
-      refs="$refs$LF$ref"
+	for ref in $reflist
+	do
+		refs="$refs$LF$ref"
 
-      # These are relative path from $GIT_DIR, typically starting at refs/
-      # but may be HEAD
-      if expr "z$ref" : 'z\.' >/dev/null
-      then
-	  not_for_merge=t
-	  ref=$(expr "z$ref" : 'z\.\(.*\)')
-      else
-	  not_for_merge=
-      fi
-      if expr "z$ref" : 'z+' >/dev/null
-      then
-	  single_force=t
-	  ref=$(expr "z$ref" : 'z+\(.*\)')
-      else
-	  single_force=
-      fi
-      remote_name=$(expr "z$ref" : 'z\([^:]*\):')
-      local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)')
+		# These are relative path from $GIT_DIR, typically starting at refs/
+		# but may be HEAD
+		if expr "z$ref" : 'z\.' >/dev/null
+		then
+			not_for_merge=t
+			ref=$(expr "z$ref" : 'z\.\(.*\)')
+		else
+			not_for_merge=
+		fi
+		if expr "z$ref" : 'z+' >/dev/null
+		then
+			single_force=t
+			ref=$(expr "z$ref" : 'z+\(.*\)')
+		else
+			single_force=
+		fi
+		remote_name=$(expr "z$ref" : 'z\([^:]*\):')
+		local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 
-      rref="$rref$LF$remote_name"
+		rref="$rref$LF$remote_name"
 
-      # There are transports that can fetch only one head at a time...
-      case "$remote" in
-      http://* | https://*)
-	  if [ -n "$GIT_SSL_NO_VERIFY" ]; then
-	      curl_extra_args="-k"
-	  fi
-	  max_depth=5
-	  depth=0
-	  head="ref: $remote_name"
-	  while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null
-	  do
-	    remote_name_quoted=$(@@PERL@@ -e '
-	      my $u = $ARGV[0];
-              $u =~ s/^ref:\s*//;
-	      $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
-	      print "$u";
-	  ' "$head")
-	    head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted")
-	    depth=$( expr \( $depth + 1 \) )
-	  done
-	  expr "z$head" : "z$_x40\$" >/dev/null ||
-	      die "Failed to fetch $remote_name from $remote"
-	  echo >&2 Fetching "$remote_name from $remote" using http
-	  git-http-fetch -v -a "$head" "$remote/" || exit
-	  ;;
-      rsync://*)
-	  TMP_HEAD="$GIT_DIR/TMP_HEAD"
-	  rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
-	  head=$(git-rev-parse --verify TMP_HEAD)
-	  rm -f "$TMP_HEAD"
-	  test "$rsync_slurped_objects" || {
-	      rsync -av --ignore-existing --exclude info \
-		  "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
+		# There are transports that can fetch only one head at a time...
+		case "$remote" in
+		http://* | https://*)
+			if [ -n "$GIT_SSL_NO_VERIFY" ]; then
+				curl_extra_args="-k"
+			fi
+			max_depth=5
+			depth=0
+			head="ref: $remote_name"
+			while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null
+			do
+				remote_name_quoted=$(@@PERL@@ -e '
+					my $u = $ARGV[0];
+					$u =~ s/^ref:\s*//;
+					$u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
+					print "$u";
+					' "$head")
+				head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted")
+				depth=$( expr \( $depth + 1 \) )
+			done
+			expr "z$head" : "z$_x40\$" >/dev/null ||
+				die "Failed to fetch $remote_name from $remote"
+			echo >&2 Fetching "$remote_name from $remote" using http
+			git-http-fetch -v -a "$head" "$remote/" || exit
+			;;
+		rsync://*)
+			TMP_HEAD="$GIT_DIR/TMP_HEAD"
+			rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
+			head=$(git-rev-parse --verify TMP_HEAD)
+			rm -f "$TMP_HEAD"
+			test "$rsync_slurped_objects" || {
+				rsync -av --ignore-existing --exclude info \
+					"$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
 
-	      # Look at objects/info/alternates for rsync -- http will
-	      # support it natively and git native ones will do it on
-	      # the remote end.  Not having that file is not a crime.
-	      rsync -q "$remote/objects/info/alternates" \
-		  "$GIT_DIR/TMP_ALT" 2>/dev/null ||
-		  rm -f "$GIT_DIR/TMP_ALT"
-	      if test -f "$GIT_DIR/TMP_ALT"
-	      then
-		  resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
-		  while read alt
-		  do
-		      case "$alt" in 'bad alternate: '*) die "$alt";; esac
-		      echo >&2 "Getting alternate: $alt"
-		      rsync -av --ignore-existing --exclude info \
-		      "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
-		  done
-		  rm -f "$GIT_DIR/TMP_ALT"
-	      fi
-	      rsync_slurped_objects=t
-	  }
-	  ;;
-      *)
-	  # We will do git native transport with just one call later.
-	  continue ;;
-      esac
+			# Look at objects/info/alternates for rsync -- http will
+			# support it natively and git native ones will do it on
+			# the remote end.  Not having that file is not a crime.
+			rsync -q "$remote/objects/info/alternates" \
+				"$GIT_DIR/TMP_ALT" 2>/dev/null ||
+				rm -f "$GIT_DIR/TMP_ALT"
+			if test -f "$GIT_DIR/TMP_ALT"
+			then
+				resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
+				while read alt
+				do
+					case "$alt" in 'bad alternate: '*) die "$alt";; esac
+					echo >&2 "Getting alternate: $alt"
+					rsync -av --ignore-existing --exclude info \
+						"$alt" "$GIT_OBJECT_DIRECTORY/" || exit
+				done
+				rm -f "$GIT_DIR/TMP_ALT"
+			fi
+			rsync_slurped_objects=t
+			}
+			;;
+		*)
+			# We will do git native transport with just one call later.
+			continue ;;
+		esac
 
-      append_fetch_head "$head" "$remote" \
-	  "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
+		append_fetch_head "$head" "$remote" \
+			"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
 
-  done
+	done
 
-  case "$remote" in
-  http://* | https://* | rsync://* )
-      ;; # we are already done.
-  *)
-    ( : subshell because we muck with IFS
-      IFS=" 	$LF"
-      (
-	  git-fetch-pack $exec $keep "$remote" $rref || echo failed "$remote"
-      ) |
-      while read sha1 remote_name
-      do
-	  case "$sha1" in
-	  failed)
-		  echo >&2 "Fetch failure: $remote"
-		  exit 1 ;;
-	  esac
-	  found=
-	  single_force=
-	  for ref in $refs
-	  do
-	      case "$ref" in
-	      +$remote_name:*)
-		  single_force=t
-		  not_for_merge=
-		  found="$ref"
-		  break ;;
-	      .+$remote_name:*)
-		  single_force=t
-		  not_for_merge=t
-		  found="$ref"
-		  break ;;
-	      .$remote_name:*)
-		  not_for_merge=t
-		  found="$ref"
-		  break ;;
-	      $remote_name:*)
-		  not_for_merge=
-		  found="$ref"
-		  break ;;
-	      esac
-	  done
-	  local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
-	  append_fetch_head "$sha1" "$remote" \
-		  "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
-      done
-    ) || exit ;;
-  esac
+	case "$remote" in
+	http://* | https://* | rsync://* )
+		;; # we are already done.
+	*)
+		( : subshell because we muck with IFS
+			IFS=" 	$LF"
+			(
+				git-fetch-pack $exec $keep "$remote" $rref || echo failed "$remote"
+			) |
+			while read sha1 remote_name
+			do
+				case "$sha1" in
+				failed)
+					echo >&2 "Fetch failure: $remote"
+					exit 1 ;;
+				esac
+				found=
+				single_force=
+				for ref in $refs
+				do
+					case "$ref" in
+					+$remote_name:*)
+						single_force=t
+						not_for_merge=
+						found="$ref"
+						break ;;
+					.+$remote_name:*)
+						single_force=t
+						not_for_merge=t
+						found="$ref"
+						break ;;
+					.$remote_name:*)
+						not_for_merge=t
+						found="$ref"
+						break ;;
+					$remote_name:*)
+						not_for_merge=
+						found="$ref"
+						break ;;
+					esac
+				done
+				local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
+				append_fetch_head "$sha1" "$remote" \
+					"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
+			done
+		) || exit ;;
+	esac
 
 }
 
@@ -439,7 +440,7 @@ case ",$update_head_ok,$orig_head," in
 	curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 	if test "$curr_head" != "$orig_head"
 	then
-	    git-update-ref \
+		git-update-ref \
 			-m "$rloga: Undoing incorrectly fetched HEAD." \
 			HEAD "$orig_head"
 		die "Cannot fetch into the current branch."
diff --git a/git-ls-remote.sh b/git-ls-remote.sh
index 2fdcaf7..38122ad 100755
--- a/git-ls-remote.sh
+++ b/git-ls-remote.sh
@@ -2,36 +2,36 @@ #!/bin/sh
 #
 
 usage () {
-    echo >&2 "usage: $0 [--heads] [--tags] [-u|--upload-pack <upload-pack>]"
-    echo >&2 "          <repository> <refs>..."
-    exit 1;
+	echo >&2 "usage: $0 [--heads] [--tags] [-u|--upload-pack <upload-pack>]"
+	echo >&2 "          <repository> <refs>..."
+	exit 1;
 }
 
 die () {
-    echo >&2 "$*"
-    exit 1
+	echo >&2 "$*"
+	exit 1
 }
 
 exec=
 while case "$#" in 0) break;; esac
 do
-  case "$1" in
-  -h|--h|--he|--hea|--head|--heads)
-  heads=heads; shift ;;
-  -t|--t|--ta|--tag|--tags)
-  tags=tags; shift ;;
-  -u|--u|--up|--upl|--uploa|--upload|--upload-|--upload-p|--upload-pa|\
-  --upload-pac|--upload-pack)
-	shift
-	exec="--exec=$1"
-	shift;;
-  --)
-  shift; break ;;
-  -*)
-  usage ;;
-  *)
-  break ;;
-  esac
+	case "$1" in
+	-h|--h|--he|--hea|--head|--heads)
+		heads=heads; shift ;;
+	-t|--t|--ta|--tag|--tags)
+		tags=tags; shift ;;
+	-u|--u|--up|--upl|--uploa|--upload|--upload-|--upload-p|--upload-pa|\
+		--upload-pac|--upload-pack)
+		shift
+		exec="--exec=$1"
+		shift;;
+	--)
+		shift; break ;;
+	-*)
+		usage ;;
+	*)
+		break ;;
+	esac
 done
 
 case "$#" in 0) usage ;; esac
@@ -50,9 +50,9 @@ tmpdir=$tmp-d
 
 case "$peek_repo" in
 http://* | https://* )
-        if [ -n "$GIT_SSL_NO_VERIFY" ]; then
-            curl_extra_args="-k"
-        fi
+	if [ -n "$GIT_SSL_NO_VERIFY" ]; then
+		curl_extra_args="-k"
+	fi
 	curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" ||
 		echo "failed	slurping"
 	;;
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 2/2] Set User-Agent string in shell scripts used for fetching
  2006-08-01  9:34         ` [PATCH 1/2] Use tabs for indent in shell scripts Jakub Narebski
@ 2006-08-01  9:36           ` Jakub Narebski
  2006-08-01  9:51             ` Junio C Hamano
  2006-08-01  9:50           ` [PATCH 1/2] Use tabs for indent in shell scripts Junio C Hamano
  1 sibling, 1 reply; 54+ messages in thread
From: Jakub Narebski @ 2006-08-01  9:36 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This needs checking for shell portability.

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Junio C Hamano wrote:

> Jakub Narebski <jnareb@gmail.com> writes:
> 
>> By the way, I wonder why git when cloning/fetching via http protocol
>> uses e.g. "git/1.4.2.rc2.ge0bed" as User-Agent: string when fetching objects
>> and packs, and e.g. "curl/7.15.4 (i486-pc-linux-gnu) libcurl/7.15.4
>> OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" as User-Agent: when fetching refs
>> (heads and tags) and info/refs.
> 
> "Why?", meaning if we deliberately do so for some good reason?
> 
> There isn't.
> 
> git-http-fetch uses its own User-Agent string, but the shell
> script wrappers that use curl executable do not bother setting
> customized User-Agent string; that is why.

So there :-)

 git-clone.sh     |    4 +++-
 git-fetch.sh     |    5 ++++-
 git-ls-remote.sh |    7 +++++--
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/git-clone.sh b/git-clone.sh
index adb752d..a9676d6 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -20,10 +20,12 @@ get_repo_base() {
 if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 	curl_extra_args="-k"
 fi
+curl_user_agent="$(git --version)"
+curl_user_agent="git/${curl_user_agent##git version }"
 
 http_fetch () {
 	# $1 = Remote, $2 = Local
-	curl -nsfL $curl_extra_args "$1" >"$2"
+	curl -nsfL $curl_extra_args $curl_user_agent "$1" >"$2"
 }
 
 clone_dumb_http () {
diff --git a/git-fetch.sh b/git-fetch.sh
index cea6e0b..6635bd5 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -291,6 +291,8 @@ fetch_main () {
 			if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 				curl_extra_args="-k"
 			fi
+			curl_user_agent="$(git --version)"
+			curl_user_agent="git/${curl_user_agent##git version }"
 			max_depth=5
 			depth=0
 			head="ref: $remote_name"
@@ -302,7 +304,8 @@ fetch_main () {
 					$u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
 					print "$u";
 					' "$head")
-				head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted")
+				head=$(curl -nsfL $curl_extra_args $curl_user_agent \
+					"$remote/$remote_name_quoted")
 				depth=$( expr \( $depth + 1 \) )
 			done
 			expr "z$head" : "z$_x40\$" >/dev/null ||
diff --git a/git-ls-remote.sh b/git-ls-remote.sh
index 38122ad..32b93da 100755
--- a/git-ls-remote.sh
+++ b/git-ls-remote.sh
@@ -53,8 +53,11 @@ http://* | https://* )
 	if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 		curl_extra_args="-k"
 	fi
-	curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" ||
-		echo "failed	slurping"
+	curl_user_agent="$(git --version)"
+	curl_user_agent="git/${curl_user_agent##git version }"
+	curl -nsf $curl_extra_args $curl_user_agent --header "Pragma: no-cache" \
+		"$peek_repo/info/refs" ||
+		echo "failed slurping"
 	;;
 
 rsync://* )
-- 
1.4.1.1

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [PATCH 1/2] Use tabs for indent in shell scripts
  2006-08-01  9:34         ` [PATCH 1/2] Use tabs for indent in shell scripts Jakub Narebski
  2006-08-01  9:36           ` [PATCH 2/2] Set User-Agent string in shell scripts used for fetching Jakub Narebski
@ 2006-08-01  9:50           ` Junio C Hamano
  2006-08-01 10:01             ` Jakub Narebski
  1 sibling, 1 reply; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  9:50 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

Jakub Narebski <jnareb@gmail.com> writes:

>  if [ -n "$GIT_SSL_NO_VERIFY" ]; then
> -    curl_extra_args="-k"
> +	curl_extra_args="-k"
>  fi

Things like this makes some sense...

>  		if test -n "$use_separate_remote" &&
> -		   branch_name=`expr "z$name" : 'zheads/\(.*\)'`
> +			branch_name=`expr "z$name" : 'zheads/\(.*\)'`
>  		then

... but not this, which is not just indent but an alignment.

>  		case "$2" in
>  		'')
> -		    usage ;;
> +			usage ;;
>  		*/*)
> -		    echo >&2 "'$2' is not suitable for an origin name"
> -		    exit 1
> +			echo >&2 "'$2' is not suitable for an origin name"
> +			exit 1

Also shell scripts tend to become too deeply indented, and 4-column
indentation helps to keep things within typical screen width.

In short, not very enthused.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 2/2] Set User-Agent string in shell scripts used for fetching
  2006-08-01  9:36           ` [PATCH 2/2] Set User-Agent string in shell scripts used for fetching Jakub Narebski
@ 2006-08-01  9:51             ` Junio C Hamano
  0 siblings, 0 replies; 54+ messages in thread
From: Junio C Hamano @ 2006-08-01  9:51 UTC (permalink / raw)
  To: git

Jakub Narebski <jnareb@gmail.com> writes:

>> "Why?", meaning if we deliberately do so for some good reason?
>> 
>> There isn't.
>> 
>> git-http-fetch uses its own User-Agent string, but the shell
>> script wrappers that use curl executable do not bother setting
>> customized User-Agent string; that is why.
>
> So there :-)

Who said we want to?  Actually I explicitly said we do not
bother ;-).

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [PATCH 1/2] Use tabs for indent in shell scripts
  2006-08-01  9:50           ` [PATCH 1/2] Use tabs for indent in shell scripts Junio C Hamano
@ 2006-08-01 10:01             ` Jakub Narebski
  0 siblings, 0 replies; 54+ messages in thread
From: Jakub Narebski @ 2006-08-01 10:01 UTC (permalink / raw)
  To: git

Junio C Hamano wrote:

> Jakub Narebski <jnareb@gmail.com> writes:
> 
>>  if [ -n "$GIT_SSL_NO_VERIFY" ]; then
>> -    curl_extra_args="-k"
>> +    curl_extra_args="-k"
>>  fi
> 
> Things like this makes some sense...
> 
>>              if test -n "$use_separate_remote" &&
>> -               branch_name=`expr "z$name" : 'zheads/\(.*\)'`
>> +                    branch_name=`expr "z$name" : 'zheads/\(.*\)'`
>>              then
> 
> ... but not this, which is not just indent but an alignment.

Sorry, my mistake. Tabs for indent, spaces for align, of course. So discard
this chunk, please.


I'm not sure how to indent sequences like the following:

  command arg \
    arg arg arg \
    arg arg arg

The above I think everybody would agree on.

  command &&
    command &&
    command

  command ||
    command ||
    command

Not so sure about above

[...]
> Also shell scripts tend to become too deeply indented, and 4-column
> indentation helps to keep things within typical screen width.
> 
> In short, not very enthused.

I use tab-width 2 and script didn't get too indented. All changed scripts
except git-clone.sh fit in 80 column window for tab width 2, and the lines
in git-clone.sh which do not fit in 80 columns are not indented at all. 

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH] gitweb: clean up user configuration part
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (21 preceding siblings ...)
  2006-08-01  0:59 ` [PATCH 22] Jakub Narebski
@ 2006-08-01 12:48 ` Matthias Lederhofer
  2006-08-01 13:53 ` [RFC/PATCH] gitweb: include perl files for configuration Matthias Lederhofer
  23 siblings, 0 replies; 54+ messages in thread
From: Matthias Lederhofer @ 2006-08-01 12:48 UTC (permalink / raw)
  To: git

 * add a marker where the user configuration starts/ends
 * replaced the two $projectroot = lines
 * add a comment to $projectlist
 * reorder the variables

Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
I tried to put the variables at top which will be edited most likely
(cannot have sane default values).
---
 gitweb/gitweb.cgi |   58 ++++++++++++++++++++++++++++++++---------------------
 1 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index 9448b72..ca2ef70 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -18,44 +18,42 @@ use File::Find qw();
 binmode STDOUT, ':utf8';
 
 our $cgi = new CGI;
-our $version = "267";
-our $my_url = $cgi->url();
-our $my_uri = $cgi->url(-absolute => 1);
-our $rss_link = "";
 
-# core git executable to use
-# this can just be "git" if your webserver has a sensible PATH
-our $GIT = "/usr/bin/git";
+##
+## BEGIN USER CONFIGURATION
+##
 
 # absolute fs-path which will be prepended to the project path
-#our $projectroot = "/pub/scm";
-our $projectroot = "/home/kay/public_html/pub/scm";
+our $projectroot = "/pub/git";
 
-# version of the core git binary
-our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+# source of projects list
+# file: list of projects, may use subdirectories
+# directory: all git repositories in the directory (not subdirectories)
+our $projects_list = "index/index.aux";
+#our $projects_list = $projectroot;
 
-# location for temporary files needed for diffs
-our $git_temp = "/tmp/gitweb";
-if (! -d $git_temp) {
-	mkdir($git_temp, 0700) || die_error("Couldn't mkdir $git_temp");
-}
+# html text to include at home page
+our $home_text = "indextext.html";
 
-# target of the home link on top of all pages
-our $home_link = $my_uri;
+# core git executable to use
+# this can just be "git" if your webserver has a sensible PATH
+our $GIT = "/usr/bin/git";
 
 # name of your site or organization to appear in page titles
 # replace this with something more descriptive for clearer bookmarks
 our $site_name = $ENV{'SERVER_NAME'} || "Untitled";
 
-# html text to include at home page
-our $home_text = "indextext.html";
+our $my_url = $cgi->url();
+our $my_uri = $cgi->url(-absolute => 1);
+our $rss_link = "";
+# target of the home link on top of all pages
+our $home_link = $my_uri;
 
 # URI of default stylesheet
 our $stylesheet = "gitweb.css";
 
-# source of projects list
-#our $projects_list = $projectroot;
-our $projects_list = "index/index.aux";
+# location for temporary files needed for diffs
+our $git_temp = "/tmp/gitweb";
 
 # default blob_plain mimetype and default charset for text/plain blob
 our $default_blob_plain_mimetype = 'text/plain';
@@ -65,6 +63,20 @@ # file to use for guessing MIME types be
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+##
+## END USER CONFIGURATION
+##
+
+# version of the core git binary
+our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
+
+our $version = "267";
+
+# create temp directory
+if (! -d $git_temp) {
+	mkdir($git_temp, 0700) || die_error("Couldn't mkdir $git_temp");
+}
+
 # input validation and dispatch
 our $action = $cgi->param('a');
 if (defined $action) {
-- 
1.4.2.rc2.g4713

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [RFC/PATCH] gitweb: include perl files for configuration
  2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
                   ` (22 preceding siblings ...)
  2006-08-01 12:48 ` [PATCH] gitweb: clean up user configuration part Matthias Lederhofer
@ 2006-08-01 13:53 ` Matthias Lederhofer
  23 siblings, 0 replies; 54+ messages in thread
From: Matthias Lederhofer @ 2006-08-01 13:53 UTC (permalink / raw)
  To: git

gitweb will first include all files after __DATA__ and then
$GITWEB_CONFIG

Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
I really hate upgrading gitweb because every time I've to copy the
configuration part from the old script to the new one.  I do some
regexp to find the values for some configuration values so I'd prefer
to include a perl file instead of a normal configuration file.

For example I'd use this with this patch:

$GIT = "/usr/local/bin/git";
$stylesheet = "/gitweb.css";
if ($ENV{'SCRIPT_NAME'} =~ m#^/([a-z0-9-]+)/#) {
    $projectroot = "/home/$1";
    $home_text =   $projectroot."/gitweb.html";
    $projects_list = $projectroot."/gitweb.list";
} else {
    $projectroot = "/home";
    $home_text = "/www/gitweb.html";
    $projects_list = "/www/gitweb.list";
}

In this setup there is one subdirectory per-user which contains a
symlink to ../gitweb.cgi allowing them to maintain their own gitweb.

Later (see gitweb.pl post) the Makefile could also add the path to the
configuration file automatically if a certain variable is set (by
appending the filename to gitweb.cgi).

Using __DATA__ instead of a variable holding the filename allows to
add the configuration file easily without editing the file in an
editor or trying to replace some part (without breaking something)
using sed.

This patch is on top of my last patch (user configuration cleanup).
---
 gitweb/gitweb.cgi |   35 ++++++++++++++++++++++++++++++++---
 1 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/gitweb/gitweb.cgi b/gitweb/gitweb.cgi
index ca2ef70..96f8852 100755
--- a/gitweb/gitweb.cgi
+++ b/gitweb/gitweb.cgi
@@ -23,6 +23,12 @@ ##
 ## BEGIN USER CONFIGURATION
 ##
 
+# You can let gitweb 'do' (perldoc -f do) configuration files after this
+# configuration section to override the values.  The configuration files
+# will be executed in this order:
+# - files after __DATA__ (first file first)
+# - file in the $GITWEB_CONFIG environment variable
+
 # absolute fs-path which will be prepended to the project path
 our $projectroot = "/pub/git";
 
@@ -67,10 +73,31 @@ ##
 ## END USER CONFIGURATION
 ##
 
-# version of the core git binary
-our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
-
 our $version = "267";
+# die_error uses this, circumvents some warnings
+our $git_version = 'unknown';
+
+# 'do' configuration files
+for my $file (<DATA>, $ENV{'GITWEB_CONFIG'}) {
+	next if (!defined($file));
+	$file =~ s/\r?\n$//;
+	if (! -e $file) {
+		warn("configuration file '$file' does not exist");
+		die_error('500 Internal Server Error', 'Configuration error');
+	}
+	undef $@;
+	undef $!;
+	next if (defined(do($file)));
+	if ($@) {
+		warn("parse error in configuration file '$file': $@");
+	} else {
+		warn("error in configuration file '$file': $!");
+	}
+	die_error('500 Internal Server Error', 'Configuration error');
+}
+
+# version of the core git binary
+$git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
 
 # create temp directory
 if (! -d $git_temp) {
@@ -2608,3 +2635,5 @@ sub git_opml {
 	      "</body>\n".
 	      "</opml>\n";
 }
+
+__DATA__
-- 
1.4.2.rc2.g4713

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: A few more fixups to gitweb
  2006-08-01  4:24   ` A few more fixups to gitweb Junio C Hamano
  2006-08-01  7:36     ` Jakub Narebski
@ 2006-08-01 20:10     ` Luben Tuikov
  1 sibling, 0 replies; 54+ messages in thread
From: Luben Tuikov @ 2006-08-01 20:10 UTC (permalink / raw)
  To: Junio C Hamano, Jakub Narebski; +Cc: git, Martin Langhoff, Matthias Lederhofer

--- Junio C Hamano <junkio@cox.net> wrote:
> One thing to note.  Please make sure that you do not see
> anything in Apache error log after you make your changes.  I do
> not remember the details but kernel.org folks were very unhappy
> earlier when gitweb spewed stuff into the error log, and if I
> recall correctly things that output to the error stream were not
> friendly to the http-server cache for some reason.

I've been meaning to mention this as well.  Gitweb patches,
especially recent ones, need more (thorough) testing, before
posted to the list for inclusion.

    Luben

^ permalink raw reply	[flat|nested] 54+ messages in thread

end of thread, other threads:[~2006-08-01 20:10 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-07-29 20:39 [PATCH 0] Some gitweb patches Jakub Narebski
2006-07-29 20:43 ` [PATCH 1] gitweb: whitespace cleanup Jakub Narebski
2006-07-29 20:51 ` [PATCH 2] gitweb: Use list for of open for running git commands, thorougly Jakub Narebski
2006-07-30  2:12   ` Jakub Narebski
2006-07-31 10:53   ` Junio C Hamano
2006-07-31 11:42     ` Jakub Narebski
2006-07-31 12:10       ` Jakub Narebski
2006-07-31 12:38         ` Jakub Narebski
2006-07-31 12:59     ` Jakub Narebski
2006-07-29 20:55 ` [PATCH 3] gitweb: simplify git_get_hash_by_path Jakub Narebski
2006-07-29 21:01 ` [PATCH 4] gitweb: More explicit error messages for open "-|" Jakub Narebski
2006-07-30  2:08 ` [PATCH 5] gitweb: Cleanup - chomp $line in consistent style Jakub Narebski
2006-07-30  2:11 ` [PATCH 6] gitweb: Correct error from changing "-|" open to list form in git_commit Jakub Narebski
2006-07-30 12:58 ` [PATCH 7] gitweb: Cleanup - chomp @lines in consistent style Jakub Narebski
2006-07-30 12:59 ` [PATCH 8] gitweb: Add git_page_nav for later use Jakub Narebski
2006-07-30 13:01 ` [PATCH 9] gitweb: Navbar refactoring - use git_page_nav to generate navigation bar Jakub Narebski
2006-07-30 13:02 ` [PATCH 10] gitweb: Replace form-feed character by ^L Jakub Narebski
2006-07-30 14:13 ` [PATCH 11] gitweb: Read project description using utf-8 encoding Jakub Narebski
2006-07-30 15:20   ` Jakub Narebski
2006-07-30 15:47   ` [PATCH 11] gitweb: Show project descriptions with utf-8 characters in project list correctly Jakub Narebski
2006-07-30 14:14 ` [PATCH 12] gitweb: Add "\n" after <br/> in git_page_nav Jakub Narebski
2006-07-30 15:49 ` [PATCH 13] gitweb: Pager refactoring - use git_get_paging_nav for pagination Jakub Narebski
2006-07-30 18:31 ` [PATCH 14] gitweb: Remove $project from git_get_paging_nav arguments Jakub Narebski
2006-07-30 18:32 ` [PATCH 15] gitweb: Headers refactoring - use git_header_div for header divs Jakub Narebski
2006-07-30 20:36 ` [PATCH 16] gitweb: Remove characters entities entirely when shortening string Jakub Narebski
2006-07-31 16:59   ` Jakub Narebski
2006-07-31 18:58   ` [PATCH 16b] gitweb: Remove characters entities entirely when shortening string -- correction Jakub Narebski
2006-07-31  0:21 ` [PATCH 17] gitweb: Ref refactoring - use git_get_referencing for marking tagged/head commits Jakub Narebski
2006-07-31  9:22 ` [PATCH 18] gitweb: Refactor generation of shortlog, tags and heads body Jakub Narebski
2006-07-31 16:33 ` [PATCH 19] gitweb: No need to quote path for list version of open "-|" Jakub Narebski
2006-07-31 18:55   ` Junio C Hamano
2006-07-31 19:00     ` Jakub Narebski
2006-08-01  2:17       ` Junio C Hamano
2006-08-01  2:18       ` There can be more than two levels of subdirectories Junio C Hamano
2006-07-31 18:48 ` [PATCH 20] gitweb: Reordering code and dividing it into categories Jakub Narebski
2006-07-31 19:22   ` [PATCH 20 (amend)] " Jakub Narebski
2006-07-31 21:46 ` [PATCH] gitweb: use a hash to lookup the sub for an action Matthias Lederhofer
2006-07-31 22:39   ` Junio C Hamano
2006-07-31 22:55   ` [PATCH 21] " Jakub Narebski
2006-08-01  2:50   ` [PATCH] " Luben Tuikov
2006-08-01  0:59 ` [PATCH 22] Jakub Narebski
2006-08-01  2:12   ` Perhaps an obvious cut and paste error Junio C Hamano
2006-08-01  7:23     ` Jakub Narebski
2006-08-01  4:24   ` A few more fixups to gitweb Junio C Hamano
2006-08-01  7:36     ` Jakub Narebski
2006-08-01  8:04       ` Junio C Hamano
2006-08-01  9:34         ` [PATCH 1/2] Use tabs for indent in shell scripts Jakub Narebski
2006-08-01  9:36           ` [PATCH 2/2] Set User-Agent string in shell scripts used for fetching Jakub Narebski
2006-08-01  9:51             ` Junio C Hamano
2006-08-01  9:50           ` [PATCH 1/2] Use tabs for indent in shell scripts Junio C Hamano
2006-08-01 10:01             ` Jakub Narebski
2006-08-01 20:10     ` A few more fixups to gitweb Luben Tuikov
2006-08-01 12:48 ` [PATCH] gitweb: clean up user configuration part Matthias Lederhofer
2006-08-01 13:53 ` [RFC/PATCH] gitweb: include perl files for configuration Matthias Lederhofer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).