threads / discuss / 5308

gitweb: Support for snapshot

Subject: gitweb: Support for snapshot

## tl;dr

14 messages between Aug 17, 2006 and Aug 19, 2006.

replies: 13people: 5as markdown or json

Aneesh Kumar K.V· Aug 17, 2006, 15:29 UTC · lore
This adds snapshort support in gitweb. To enable one need to
set gitweb.snapshot = true in the config file.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@hp.com>
---
 gitweb/gitweb.perl |   41 +++++++++++++++++++++++++++++++++++++----
 1 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 04282fa..52653a0 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -15,6 +15,7 @@ use CGI::Carp qw(fatalsToBrowser);
 use Encode;
 use Fcntl ':mode';
 use File::Find qw();
+use File::Basename qw(basename);
 binmode STDOUT, ':utf8';
 
 our $cgi = new CGI;
@@ -175,6 +176,7 @@ my %actions = (
 	"tag" => \&git_tag,
 	"tags" => \&git_tags,
 	"tree" => \&git_tree,
+	"snapshot" => \&git_snapshot,
 );
 
 $action = 'summary' if (!defined($action));
@@ -1320,6 +1322,7 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
+	my $have_snapshot = git_get_project_config_bool('snapshot');
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1344,8 +1347,11 @@ sub git_shortlog_body {
 		print "</td>\n" .
 		      "<td class=\"link\">" .
 		      $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
-		      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
-		      "</td>\n" .
+		      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
+		if ($have_snapshot) {
+			print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+		}
+		print "</td>\n" .
 		      "</tr>\n";
 	}
 	if (defined $extra) {
@@ -2112,6 +2118,29 @@ sub git_tree {
 	git_footer_html();
 }
 
+sub git_snapshot {
+
+	if (!defined $hash) {
+		$hash = git_get_head_hash($project);
+	}
+
+	my $filename = basename($project) . "-$hash.tar.gz";
+
+	print $cgi->header(-type => 'application/x-tar',
+			-content-encoding => 'gzip',
+			'-content-disposition' => "inline; filename=\"$filename\"",
+			-status => '200 OK');
+
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
+				die_error(undef, "Execute git-tar-tree failed.");
+	binmode STDOUT, ':raw';
+	print <$fd>;
+	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
+	close $fd;
+
+
+}
+
 sub git_log {
 	my $head = git_get_head_hash($project);
 	if (!defined $hash) {
@@ -2206,6 +2235,7 @@ sub git_commit {
 	}
 	my $refs = git_get_references();
 	my $ref = format_ref_marker($refs, $co{'id'});
+	my $have_snapshot = git_get_project_config_bool('snapshot');
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
@@ -2241,8 +2271,11 @@ sub git_commit {
 	      "<td class=\"sha1\">" .
 	      $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) .
 	      "</td>" .
-	      "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree") .
-	      "</td>" .
+	      "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree");
+	if ($have_snapshot) {
+		print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
+	}
+	print "</td>" .
 	      "</tr>\n";
 	my $parents = $co{'parents'};
 	foreach my $par (@$parents) {
-- 
1.4.2.rc1.g83e1-dirty
Aneesh Kumar K.V· Aug 18, 2006, 05:06 UTC · re: Aneesh Kumar K.V · lore

[PATCH] gitweb: Support for snapshot

Now I read RFC 2616 the content-encoding need to be specified as x-gzip. Also i am not sure whether the fact that it is registered with IANA exempt us from adding it to html header.

The corrected patch below. 
This adds snapshort support in gitweb. To enable one need to
set gitweb.snapshot = true in the config file.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@gmail.com>
---
 gitweb/gitweb.perl |   41 +++++++++++++++++++++++++++++++++++++----
 1 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 04282fa..d6f96a3 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -15,6 +15,7 @@ use CGI::Carp qw(fatalsToBrowser);
 use Encode;
 use Fcntl ':mode';
 use File::Find qw();
+use File::Basename qw(basename);
 binmode STDOUT, ':utf8';
 
 our $cgi = new CGI;
@@ -175,6 +176,7 @@ my %actions = (
 	"tag" => \&git_tag,
 	"tags" => \&git_tags,
 	"tree" => \&git_tree,
+	"snapshot" => \&git_snapshot,
 );
 
 $action = 'summary' if (!defined($action));
@@ -1320,6 +1322,7 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
+	my $have_snapshot = git_get_project_config_bool('snapshot');
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1344,8 +1347,11 @@ sub git_shortlog_body {
 		print "</td>\n" .
 		      "<td class=\"link\">" .
 		      $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
-		      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
-		      "</td>\n" .
+		      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
+		if ($have_snapshot) {
+			print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+		}
+		print "</td>\n" .
 		      "</tr>\n";
 	}
 	if (defined $extra) {
@@ -2112,6 +2118,29 @@ sub git_tree {
 	git_footer_html();
 }
 
+sub git_snapshot {
+
+	if (!defined $hash) {
+		$hash = git_get_head_hash($project);
+	}
+
+	my $filename = basename($project) . "-$hash.tar.gz";
+
+	print $cgi->header(-type => 'application/x-tar',
+			-content-encoding => 'x-gzip',
+			'-content-disposition' => "inline; filename=\"$filename\"",
+			-status => '200 OK');
+
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
+				die_error(undef, "Execute git-tar-tree failed.");
+	binmode STDOUT, ':raw';
+	print <$fd>;
+	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
+	close $fd;
+
+
+}
+
 sub git_log {
 	my $head = git_get_head_hash($project);
 	if (!defined $hash) {
@@ -2206,6 +2235,7 @@ sub git_commit {
 	}
 	my $refs = git_get_references();
 	my $ref = format_ref_marker($refs, $co{'id'});
+	my $have_snapshot = git_get_project_config_bool('snapshot');
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
@@ -2241,8 +2271,11 @@ sub git_commit {
 	      "<td class=\"sha1\">" .
 	      $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) .
 	      "</td>" .
-	      "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree") .
-	      "</td>" .
+	      "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)}, "tree");
+	if ($have_snapshot) {
+		print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
+	}
+	print "</td>" .
 	      "</tr>\n";
 	my $parents = $co{'parents'};
 	foreach my $par (@$parents) {
-- 
1.4.2.rc1.g83e1-dirty
Luben Tuikov· Aug 18, 2006, 19:51 UTC · re: Aneesh Kumar K.V · lore

Re: [PATCH] gitweb: Support for snapshot

--- "Aneesh Kumar K.V" <aneesh.kumar@gmail.com> wrote:
> This adds snapshort support in gitweb. To enable one need to
> set gitweb.snapshot = true in the config file.

Could you use bzip2? It generates smaller files (better compression), which is a good thing when downloading over a network.

   Luben
Show 106 quoted lines
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@gmail.com>
> ---
>  gitweb/gitweb.perl |   41 +++++++++++++++++++++++++++++++++++++----
>  1 files changed, 37 insertions(+), 4 deletions(-)
> 
> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
> index 04282fa..d6f96a3 100755
> --- a/gitweb/gitweb.perl
> +++ b/gitweb/gitweb.perl
> @@ -15,6 +15,7 @@ use CGI::Carp qw(fatalsToBrowser);
>  use Encode;
>  use Fcntl ':mode';
>  use File::Find qw();
> +use File::Basename qw(basename);
>  binmode STDOUT, ':utf8';
>  
>  our $cgi = new CGI;
> @@ -175,6 +176,7 @@ my %actions = (
>  	"tag" => \&git_tag,
>  	"tags" => \&git_tags,
>  	"tree" => \&git_tree,
> +	"snapshot" => \&git_snapshot,
>  );
>  
>  $action = 'summary' if (!defined($action));
> @@ -1320,6 +1322,7 @@ sub git_difftree_body {
>  sub git_shortlog_body {
>  	# uses global variable $project
>  	my ($revlist, $from, $to, $refs, $extra) = @_;
> +	my $have_snapshot = git_get_project_config_bool('snapshot');
>  	$from = 0 unless defined $from;
>  	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
>  
> @@ -1344,8 +1347,11 @@ sub git_shortlog_body {
>  		print "</td>\n" .
>  		      "<td class=\"link\">" .
>  		      $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
> -		      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") .
> -		      "</td>\n" .
> +		      $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
> +		if ($have_snapshot) {
> +			print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
> +		}
> +		print "</td>\n" .
>  		      "</tr>\n";
>  	}
>  	if (defined $extra) {
> @@ -2112,6 +2118,29 @@ sub git_tree {
>  	git_footer_html();
>  }
>  
> +sub git_snapshot {
> +
> +	if (!defined $hash) {
> +		$hash = git_get_head_hash($project);
> +	}
> +
> +	my $filename = basename($project) . "-$hash.tar.gz";
> +
> +	print $cgi->header(-type => 'application/x-tar',
> +			-content-encoding => 'x-gzip',
> +			'-content-disposition' => "inline; filename=\"$filename\"",
> +			-status => '200 OK');
> +
> +	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
> +				die_error(undef, "Execute git-tar-tree failed.");
> +	binmode STDOUT, ':raw';
> +	print <$fd>;
> +	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
> +	close $fd;
> +
> +
> +}
> +
>  sub git_log {
>  	my $head = git_get_head_hash($project);
>  	if (!defined $hash) {
> @@ -2206,6 +2235,7 @@ sub git_commit {
>  	}
>  	my $refs = git_get_references();
>  	my $ref = format_ref_marker($refs, $co{'id'});
> +	my $have_snapshot = git_get_project_config_bool('snapshot');
>  	my $formats_nav = '';
>  	if (defined $file_name && defined $co{'parent'}) {
>  		my $parent = $co{'parent'};
> @@ -2241,8 +2271,11 @@ sub git_commit {
>  	      "<td class=\"sha1\">" .
>  	      $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class =>
> "list"}, $co{'tree'}) .
>  	      "</td>" .
> -	      "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'},
> hash_base=>$hash)}, "tree") .
> -	      "</td>" .
> +	      "<td class=\"link\">" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'},
> hash_base=>$hash)}, "tree");
> +	if ($have_snapshot) {
> +		print " | " .  $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
> +	}
> +	print "</td>" .
>  	      "</tr>\n";
>  	my $parents = $co{'parents'};
>  	foreach my $par (@$parents) {
> -- 
> 1.4.2.rc1.g83e1-dirty
> 
> 
Timo Hirvonen· Aug 18, 2006, 20:05 UTC · re: Luben Tuikov · lore

Re: [PATCH] gitweb: Support for snapshot

Luben Tuikov <ltuikov@yahoo.com> wrote:
Show 6 quoted lines
> --- "Aneesh Kumar K.V" <aneesh.kumar@gmail.com> wrote:
> > This adds snapshort support in gitweb. To enable one need to
> > set gitweb.snapshot = true in the config file.
> 
> Could you use bzip2?  It generates smaller files (better compression),
> which is a good thing when downloading over a network.

bzip2 is much slower than gzip. Often just uncompressing .tar.bz2 takes more time than downloading bigger .tar.gz file. For small projects it doesn't matter which one you use.

-- 
http://onion.dynserv.net/~timo/
Aneesh Kumar· Aug 19, 2006, 08:10 UTC · lore

Re: [PATCH] gitweb: Support for snapshot

On 8/19/06, Junio C Hamano <junkio@cox.net> wrote:
Show 21 quoted lines
> Luben Tuikov <ltuikov@yahoo.com> writes:
>
> > --- "Aneesh Kumar K.V" <aneesh.kumar@gmail.com> wrote:
> >> This adds snapshort support in gitweb. To enable one need to
> >> set gitweb.snapshot = true in the config file.
> >
> > Could you use bzip2?  It generates smaller files (better compression),
> > which is a good thing when downloading over a network.
>
> Because bzip2 is heavier on the server than gzip is (and gzip is
> heavier than "gzip -1" is), there obviously is a trade-off.  We
> would want it to be configurable just like blame and snapshot
> itself.
>
> Maybe:
>
>         config.snapshot = no | yes | gzip | bzip2 ...
>
> By the way, I think it is a mistake to use only $GIT_DIR/config
> to control these features.
>
I have coded this at
What should be the content-encoding in this case x-$snapshot ?
This is the untested diff that i have. Is this what we are looking for ?
-aneesh
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f8d1036..6ad3141 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -67,6 +67,15 @@ # file to use for guessing MIME types be
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+# don't enable snapshot support by default
+# possible values are no|gzip|bzip2|
+our $snapshot = "no";
+
+# this indicate whether the snapshot support can be overridden
+# by a project specific config.
+# possible values are yes|no
+our $snapshot_override = "no";
+
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
 require $GITWEB_CONFIG if -e $GITWEB_CONFIG;
 
@@ -1397,7 +1406,7 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+	my ($have_snapshot, $snapshot_comp) = git_get_project_snapshot_config();
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -2200,13 +2209,14 @@ sub git_snapshot {
 	}
 
 	my $filename = basename($project) . "-$hash.tar.gz";
+	my ($have_snapshot, $snapshot_comp) = git_get_project_snapshot_config();
 
 	print $cgi->header(-type => 'application/x-tar',
-			-content-encoding => 'x-gzip',
+			-content-encoding => "x-$snapshot_comp",
 			'-content-disposition' => "inline; filename=\"$filename\"",
 			-status => '200 OK');
 
-	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $snapshot_comp" or
 				die_error(undef, "Execute git-tar-tree failed.");
 	binmode STDOUT, ':raw';
 	print <$fd>;
@@ -2215,6 +2225,27 @@ sub git_snapshot {
 
 
 }
+sub git_get_project_snapshot_config()
+{
+	my $snap;
+
+	if ($snapshot =~ m/no/) {
+		return (0, undef);
+	}
+
+	if ($snapshot_override =~ m/no/) {
+		return (1, $snapshot);
+	}
+
+	$snap = git_get_project_config('snapshot');
+
+	if ($snap and $snap =~ m/no/) {
+		return (0, undef);
+	}
+	return (1, $snap);
+}
+
+}
 
 sub git_log {
 	my $head = git_get_head_hash($project);
@@ -2293,7 +2324,7 @@ sub git_commit {
 	}
 	my $refs = git_get_references();
 	my $ref = format_ref_marker($refs, $co{'id'});
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+	my ($have_snapshot, $snapshot_comp) = git_get_project_snapshot_config();
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
Junio C Hamano· Aug 19, 2006, 10:51 UTC · re: Aneesh Kumar · lore

Re: [PATCH] gitweb: Support for snapshot

What I had in mind is more like this.
 * The global hash %feature defines optional features that site
   administrator can enable (or allow repo-owners to enable).
   The hash is keyed with feature name.
 * The value of the hash is an array whose first two elements
   are a sub and a bool, and the rest of the elements are the
   default values of feature specific parameters.
 * The bool tells gitweb_check_feature if the feature is
   overridable per repository, and the sub is called with the
   rest of elements in the array only when it is overridable.
   The sub should read from the repository config and if the
   values are satisfactory return them; otherwise it should
   throw back the default parameters.
 * When you want to know if a feature with enabled (and with
   what option), you call gitweb_check_feature with the feature
   name.  It will return either the default parameters for the
   feature, or the parameters overridden by the repository.

In the example, I do not allow overriding the setting of 'blame', so calling gitweb_check_feature('blame') would always return 0 (because the third element of the feature array is that value).

If you want to allow repositories to override, you put true value as the second member; then repositories that define their own gitweb.blame can override the default.

The patch demonstrates the use of overridable configuration; gitweb.snapshot can be left undefined (to get site-wide default), or defined to be 'none' (to disable it for the repository even when site-wide default allows it), or 'gzip', or 'bzip2'.

While I was at it, I got rid of git_get_project_config_bool() which was poorly designed. It did not understand various ways you can spell true and false, and did not distinguish between defining a variable to false and not having any definition for the variable.

I did this patch as a demonstration of the overall framework, so minor details of feature_xxx implementation might be wrong. Obviously patch is not tested.

But personally, this patch makes things a bit easier to read (but I am biased -- I wrote it).

---
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f8d1036..af8867e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -67,6 +67,51 @@ # file to use for guessing MIME types be
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+################################################################
+# Feature configuration.
+# These subs are only called when per repository
+# overrides are allowed.  They take the default options,
+# inspect the repository and return the values from there if
+# the repository wants to override the system default.
+
+sub feature_blame {
+	my ($val) = git_get_project_config('blame', '--bool');
+	if ($val eq 'true') { return 1; }
+	elsif ($val eq 'false') { return 0; }
+
+	return $_[0];
+}
+
+sub feature_snapshot {
+	my ($ctype, $suffix, $command) = @_;
+	my ($val) = git_get_project_config('snapshot');
+	if ($val eq 'gzip') { return ('gzip', 'gz'); }
+	elsif ($val eq 'bzip2') { return ('bzip2', 'bz2'); }
+	elsif ($val eq 'none') { return (); }
+
+	return ($ctype, $suffix, $command);
+}
+
+# You define site-wide feature defaults here; override them with
+# $GITWEB_CONFIG as necessary.
+our %feature = 
+(
+	# feature	=> [feature-sub, allow-override, default options...]
+
+	'blame'		=> [\&feature_blame, 0, 0],
+ 	'snapshot'	=> [\&feature_snapshot, 0, 'x-gzip', 'gz', 'gzip'],
+);
+
+sub gitweb_check_feature {
+	my ($name) = @_;
+	return undef unless exists $feature{$name};
+	my ($sub, $override, @defaults) = @{$feature{$name}};
+	if (!$override) { return @defaults; }
+	return $sub->(@defaults);
+}
+
+################################################################
+
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
 require $GITWEB_CONFIG if -e $GITWEB_CONFIG;
 
@@ -485,24 +530,19 @@ sub git_get_type {
 }
 
 sub git_get_project_config {
-	my $key = shift;
+	my ($key, $type) = @_;
 
 	return unless ($key);
 	$key =~ s/^gitweb\.//;
 	return if ($key =~ m/\W/);
 
-	my $val = qx($GIT repo-config --get gitweb.$key);
+	my @x = ($GIT, 'repo-config', '--get');
+	if (defined $type) { push @x, $type; }
+	push @x, "gitweb.$key";
+	my $val = qx(@x);
 	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;
@@ -1397,7 +1437,10 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1858,7 +1901,10 @@ sub git_tag {
 sub git_blame2 {
 	my $fd;
 	my $ftype;
-	die_error(undef, "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error(undef, "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -1916,7 +1962,10 @@ sub git_blame2 {
 
 sub git_blame {
 	my $fd;
-	die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error(undef, "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -2195,25 +2244,31 @@ sub git_tree {
 
 sub git_snapshot {
 
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+	if (!$have_snapshot) {
+		die_error(undef, "Permission denied");
+	}
+
 	if (!defined $hash) {
 		$hash = git_get_head_hash($project);
 	}
 
-	my $filename = basename($project) . "-$hash.tar.gz";
+	my $filename = basename($project) . "-$hash.tar.$suffix";
 
 	print $cgi->header(-type => 'application/x-tar',
-			-content-encoding => 'x-gzip',
-			'-content-disposition' => "inline; filename=\"$filename\"",
-			-status => '200 OK');
+			   -content-encoding => $ctype,
+			   '-content-disposition' =>
+			   "inline; filename=\"$filename\"",
+			   -status => '200 OK');
 
-	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
-				die_error(undef, "Execute git-tar-tree failed.");
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" or
+		die_error(undef, "Execute git-tar-tree failed.");
 	binmode STDOUT, ':raw';
 	print <$fd>;
 	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
 	close $fd;
 
-
 }
 
 sub git_log {
Jakub Narebski· Aug 19, 2006, 11:09 UTC · re: Junio C Hamano · lore

Re: [PATCH] gitweb: Support for snapshot

Junio C Hamano wrote:
Show 9 quoted lines
> +sub feature_snapshot {
> +       my ($ctype, $suffix, $command) = @_;
> +       my ($val) = git_get_project_config('snapshot');
> +       if ($val eq 'gzip') { return ('gzip', 'gz'); }
> +       elsif ($val eq 'bzip2') { return ('bzip2', 'bz2'); }
> +       elsif ($val eq 'none') { return (); }
> +
> +       return ($ctype, $suffix, $command);
> +}

Should it be ('x-gzip', 'gzip', 'gz') and ('x-bzip2', 'bzip2', 'bz2'), i.e. with $ctype first?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Jakub Narebski· Aug 19, 2006, 11:13 UTC · re: Junio C Hamano · lore

Re: [PATCH] gitweb: Support for snapshot

Junio C Hamano wrote:
>  * The value of the hash is an array whose first two elements
>    are a sub and a bool, and the rest of the elements are the
>    default values of feature specific parameters.

Which means that it is not that easy to change defaults from $GITWEB_CONFIG ($feature{'blame'}->[1] = 1; ?).

And there is no way to enable for example 'blame' support for all repositories...

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Aneesh Kumar K.V· Aug 19, 2006, 11:58 UTC · re: Jakub Narebski · lore

Re: [PATCH] gitweb: Support for snapshot

Jakub Narebski wrote:
Show 9 quoted lines
> Junio C Hamano wrote:
> 
>>  * The value of the hash is an array whose first two elements
>>    are a sub and a bool, and the rest of the elements are the
>>    default values of feature specific parameters.
> 
> Which means that it is not that easy to change defaults from 
> $GITWEB_CONFIG ($feature{'blame'}->[1] = 1; ?).
> 
how about 
   'blame'         => [\&feature_blame, $feature_blame_override, 0],
and picking only $feature_blame_override from $GITWEB_CONFIG
-aneesh 
Aneesh Kumar K.V· Aug 19, 2006, 13:56 UTC · re: Junio C Hamano · lore

Re: [PATCH] gitweb: Support for snapshot

Junio C Hamano wrote:
Show 8 quoted lines
> 
> I did this patch as a demonstration of the overall framework, so
> minor details of feature_xxx implementation might be wrong.
> Obviously patch is not tested.
> 
> But personally, this patch makes things a bit easier to read
> (but I am biased -- I wrote it).
> 

I tested this and added some comments. I also fixed some code. I am attaching the full diff. BTW git-repo-config have the below bug.

$ git repo-config --bool --get gitweb.blame true $ git repo-config --get --bool gitweb.blame $

So i dropped --get from the git_get_project_config
-aneesh
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f8d1036..1037ab9 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -67,6 +67,58 @@ # file to use for guessing MIME types be
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+# Feature configuration.
+# These subs are only called when per repository
+# overrides are allowed.  They take the default options,
+# inspect the repository and return the values from there if
+# the repository wants to override the system default.
+
+# To enable system wide have in $GITWEB_CONFIG
+# $feature{'blame'} =  [\&feature_blame, 0, 1];
+# To disbale project wide 
+# you should have allow-override enabled in  $GITWEB_CONFIG
+# and in project config   gitweb.blame = 0;
+sub feature_blame {
+	my ($val) = git_get_project_config('blame', '--bool');
+	if ($val eq 'true') { return 1; }
+	elsif ($val eq 'false') { return 0; }
+
+	return $_[0];
+}
+
+# To disable system wide have in $GITWEB_CONFIG
+# $feature{'snapshot'} =  [\&feature_snapshot, 0, undef, undef, undef];
+# To change the  encoding type 
+# you should have allow-override enabled in  $GITWEB_CONFIG
+# and in project config  gitweb.snapshot = bzip2
+sub feature_snapshot {
+	my ($ctype, $suffix, $command) = @_;
+	my ($val) = git_get_project_config('snapshot');
+	if ($val eq 'gzip') { return ('x-gzip', 'gz', 'gzip'); }
+	elsif ($val eq 'bzip2') { return ('x-bzip2', 'bz2', 'bzip2'); }
+	elsif ($val eq 'none') { return (); }
+
+	return ($ctype, $suffix, $command);
+}
+
+# You define site-wide feature defaults here; override them with
+# $GITWEB_CONFIG as necessary.
+our %feature =
+(
+	# feature	=> [feature-sub, allow-override, default options...]
+
+	'blame'		=> [\&feature_blame, 0, 0],
+	'snapshot'	=> [\&feature_snapshot, 0, 'x-gzip', 'gz', 'gzip'],
+);
+
+sub gitweb_check_feature {
+	my ($name) = @_;
+	return undef unless exists $feature{$name};
+	my ($sub, $override, @defaults) = @{$feature{$name}};
+	if (!$override) { return @defaults; }
+	return $sub->(@defaults);
+}
+
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
 require $GITWEB_CONFIG if -e $GITWEB_CONFIG;
 
@@ -485,24 +537,20 @@ sub git_get_type {
 }
 
 sub git_get_project_config {
-	my $key = shift;
+	my ($key, $type) = @_;
 
 	return unless ($key);
 	$key =~ s/^gitweb\.//;
 	return if ($key =~ m/\W/);
 
-	my $val = qx($GIT repo-config --get gitweb.$key);
+	my @x = ($GIT, 'repo-config');
+	if (defined $type) { push @x, $type; }
+	push @x, "gitweb.$key";
+	my $val = qx(@x);
+	chomp $val;
 	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;
@@ -1397,7 +1445,10 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1858,7 +1909,10 @@ sub git_tag {
 sub git_blame2 {
 	my $fd;
 	my $ftype;
-	die_error(undef, "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error(undef, "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -1916,7 +1970,10 @@ sub git_blame2 {
 
 sub git_blame {
 	my $fd;
-	die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error(undef, "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -2069,7 +2126,7 @@ sub git_blob {
 			die_error(undef, "No file name defined");
 		}
 	}
-	my $have_blame = git_get_project_config_bool ('blame');
+	my $have_blame = gitweb_check_feature('blame');
 	open my $fd, "-|", $GIT, "cat-file", "blob", $hash
 		or die_error(undef, "Couldn't cat $file_name, $hash");
 	my $mimetype = blob_mimetype($fd, $file_name);
@@ -2134,7 +2191,7 @@ sub git_tree {
 	git_header_html();
 	my %base_key = ();
 	my $base = "";
-	my $have_blame = git_get_project_config_bool ('blame');
+	my $have_blame = gitweb_check_feature('blame');
 	if (defined $hash_base && (my %co = parse_commit($hash_base))) {
 		$base_key{hash_base} = $hash_base;
 		git_print_page_nav('tree','', $hash_base);
@@ -2195,25 +2252,31 @@ sub git_tree {
 
 sub git_snapshot {
 
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+	if (!$have_snapshot) {
+		die_error(undef, "Permission denied");
+	}
+
 	if (!defined $hash) {
 		$hash = git_get_head_hash($project);
 	}
 
-	my $filename = basename($project) . "-$hash.tar.gz";
+	my $filename = basename($project) . "-$hash.tar.$suffix";
 
 	print $cgi->header(-type => 'application/x-tar',
-			-content-encoding => 'x-gzip',
-			'-content-disposition' => "inline; filename=\"$filename\"",
-			-status => '200 OK');
+			   -content-encoding => $ctype,
+			   '-content-disposition' =>
+			   "inline; filename=\"$filename\"",
+			   -status => '200 OK');
 
-	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
-				die_error(undef, "Execute git-tar-tree failed.");
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" or
+		die_error(undef, "Execute git-tar-tree failed.");
 	binmode STDOUT, ':raw';
 	print <$fd>;
 	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
 	close $fd;
 
-
 }
 
 sub git_log {
@@ -2293,7 +2356,10 @@ sub git_commit {
 	}
 	my $refs = git_get_references();
 	my $ref = format_ref_marker($refs, $co{'id'});
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
Jakub Narebski· Aug 19, 2006, 14:22 UTC · re: Aneesh Kumar K.V · lore

Re: [PATCH] gitweb: Support for snapshot

Aneesh Kumar K.V wrote:
> I tested this and added some comments. I also fixed some code. 
> I am attaching the full diff. 
Below comments to the patch.
Show 8 quoted lines
> BTW git-repo-config have the below bug. 
> 
> $ git repo-config --bool --get gitweb.blame
> true
> $ git repo-config --get --bool gitweb.blame
> $
> 
> So i dropped --get from the git_get_project_config

Wouldn't it be better to correct the error in git-repo-config? Or (easier) add '--get' last (see comments)?

> +# Feature configuration.

Wouldn't it make it easier to understand code to put %feature hash and gitweb_check_feature subroutine _before_ subroutines for specific features?

Show 7 quoted lines
> +# These subs are only called when per repository
> +# overrides are allowed.  They take the default options,
> +# inspect the repository and return the values from there if
> +# the repository wants to override the system default.
> +
> +# To enable system wide have in $GITWEB_CONFIG
> +# $feature{'blame'} =  [\&feature_blame, 0, 1];

This enables system wide, but also disables per-project override. To enable system wide, while allowing for per project disabling it should read # $feature{'blame'} = [\&feature_blame, 1, 1]; # overridable, enabled by default

> +# To disbale project wide 
Typo. disbale -> disable.
> +# you should have allow-override enabled in  $GITWEB_CONFIG

Example: # $feature{'blame'} = [\&feature_blame, 1, 1]; # overridable, enabled by default or just

$feature{'blame'}->[1] = 1;
(See below for comments on that form)
> +# and in project config   gitweb.blame = 0;

Example: # $ git repo-config --bool gitweb.blame false

> +# To disable system wide have in $GITWEB_CONFIG
> +# $feature{'snapshot'} =  [\&feature_snapshot, 0, undef, undef, undef];

It would be enough to put: $feature{'snapshot'} = [\&feature_snapshot, 0, undef];

Show 9 quoted lines
> +# You define site-wide feature defaults here; override them with
> +# $GITWEB_CONFIG as necessary.
> +our %feature =
> +(
> +       # feature       => [feature-sub, allow-override, default options...]
> +
> +       'blame'         => [\&feature_blame, 0, 0],
> +       'snapshot'      => [\&feature_snapshot, 0, 'x-gzip', 'gz', 'gzip'],
> +);

By the way, wouldn't it be better to use _hash_ for mixed meaning than _array_? I.e.

our %feature =
(
       # feature       => {'sub' => feature-sub, 'override' => allow-override, 'default' => default options...]
       'blame'         => {'sub' => \&feature_blame, 'override' => 0, 'default' => 0},
   #or 'blame'         => {'sub' => \&feature_blame, 'override' => 0, 'default' => [ 0 ]},
       'snapshot'      => {'sub' => \&feature_snapshot, 'override' => 0, 'default => [ 'x-gzip', 'gz', 'gzip' ]},
);

Then you could enable override, or change default simplier in $GITWEB_CONFIG, e.g. $feature{'blame'}{'override'} = 1; instead of $feature{'blame'}[1] = 1;

By the way, it has more sense to have feature by default (i.e. in gitweb.perl) with override enabled if it is set to on.

>  sub git_get_project_config {
[...]
> -       my $val = qx($GIT repo-config --get gitweb.$key);
> +       my @x = ($GIT, 'repo-config');
> +       if (defined $type) { push @x, $type; }
Just add '--get' as the last argument, _after_ type:
  +       push @x, '--get';
Show 5 quoted lines
> +       push @x, "gitweb.$key";
> +       my $val = qx(@x);
> +       chomp $val;
>         return ($val);
>  }
Show 5 quoted lines
> -       die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame'));
> +
> +       if (!gitweb_check_feature('blame')) {
> +               die_error(undef, "Permission denied");
> +       }

Why did you drop '403 Permission denied' HTTP return code from call to die_error? (And not set in other similar cases)?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Aneesh Kumar K.V· Aug 19, 2006, 16:17 UTC · re: Jakub Narebski · lore

Re: [PATCH] gitweb: Support for snapshot

Jakub Narebski wrote:
Show 7 quoted lines
> Aneesh Kumar K.V wrote:
> 
>> I tested this and added some comments. I also fixed some code. 
>> I am attaching the full diff. 
> 
> Below comments to the patch.
> 
updated patch attached. I guess i have taken care of all your comments. 
-aneesh 
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f8d1036..e8a4a6f 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -67,6 +67,68 @@ # file to use for guessing MIME types be
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+# You define site-wide feature defaults here; override them with
+# $GITWEB_CONFIG as necessary.
+our %feature =
+(
+
+# feature  => {'sub' => feature-sub, 'override' => allow-override, 'default' => [ default options...]
+
+'blame'         => {'sub' => \&feature_blame, 'override' => 0, 'default' => [0]},
+'snapshot'      => {'sub' => \&feature_snapshot, 'override' => 0, 'default' => ['x-gzip', 'gz', 'gzip']},
+
+);
+
+sub gitweb_check_feature {
+	my ($name) = @_;
+	return undef unless exists $feature{$name};
+	my ($sub, $override, @defaults) = ($feature{$name}{'sub'},
+						$feature{$name}{'override'},
+						@{$feature{$name}{'default'}});
+	if (!$override) { return @defaults; }
+	return $sub->(@defaults);
+}
+
+# To enable system wide have in $GITWEB_CONFIG
+# $feature{'blame'}{'default'} =  [0];
+# To have project specific config enable override in  $GITWEB_CONFIG
+# $feature{'blame'}{'override'} =  1;
+# and in project config gitweb.blame = 0|1;
+
+sub feature_blame {
+	my ($val) = git_get_project_config('blame', '--bool');
+
+	if ($val eq 'true') {
+		return 1;
+	} elsif ($val eq 'false') {
+		return 0;
+	}
+
+	return $_[0];
+}
+
+# To disable system wide have in $GITWEB_CONFIG
+# $feature{'snapshot'}{'default'} =  [undef];
+# To have project specific config enable override in  $GITWEB_CONFIG
+# $feature{'blame'}{'override'} =  1;
+# and in project config  gitweb.snapshot = no|gzip|bzip2
+
+sub feature_snapshot {
+	my ($ctype, $suffix, $command) = @_;
+
+	my ($val) = git_get_project_config('snapshot');
+
+	if ($val eq 'gzip') {
+		return ('x-gzip', 'gz', 'gzip');
+	} elsif ($val eq 'bzip2') {
+		return ('x-bzip2', 'bz2', 'bzip2');
+	} elsif ($val eq 'none') {
+		return ();
+	}
+
+	return ($ctype, $suffix, $command);
+}
+
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
 require $GITWEB_CONFIG if -e $GITWEB_CONFIG;
 
@@ -485,24 +547,21 @@ sub git_get_type {
 }
 
 sub git_get_project_config {
-	my $key = shift;
+	my ($key, $type) = @_;
 
 	return unless ($key);
 	$key =~ s/^gitweb\.//;
 	return if ($key =~ m/\W/);
 
-	my $val = qx($GIT repo-config --get gitweb.$key);
+	my @x = ($GIT, 'repo-config');
+	if (defined $type) { push @x, $type; }
+	push @x, "--get";
+	push @x, "gitweb.$key";
+	my $val = qx(@x);
+	chomp $val;
 	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;
@@ -1397,7 +1456,10 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1858,7 +1920,10 @@ sub git_tag {
 sub git_blame2 {
 	my $fd;
 	my $ftype;
-	die_error(undef, "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error('403 Permission denied', "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -1916,7 +1981,10 @@ sub git_blame2 {
 
 sub git_blame {
 	my $fd;
-	die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error('403 Permission denied', "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -2069,7 +2137,7 @@ sub git_blob {
 			die_error(undef, "No file name defined");
 		}
 	}
-	my $have_blame = git_get_project_config_bool ('blame');
+	my $have_blame = gitweb_check_feature('blame');
 	open my $fd, "-|", $GIT, "cat-file", "blob", $hash
 		or die_error(undef, "Couldn't cat $file_name, $hash");
 	my $mimetype = blob_mimetype($fd, $file_name);
@@ -2134,7 +2202,7 @@ sub git_tree {
 	git_header_html();
 	my %base_key = ();
 	my $base = "";
-	my $have_blame = git_get_project_config_bool ('blame');
+	my $have_blame = gitweb_check_feature('blame');
 	if (defined $hash_base && (my %co = parse_commit($hash_base))) {
 		$base_key{hash_base} = $hash_base;
 		git_print_page_nav('tree','', $hash_base);
@@ -2195,25 +2263,31 @@ sub git_tree {
 
 sub git_snapshot {
 
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+	if (!$have_snapshot) {
+		die_error('403 Permission denied', "Permission denied");
+	}
+
 	if (!defined $hash) {
 		$hash = git_get_head_hash($project);
 	}
 
-	my $filename = basename($project) . "-$hash.tar.gz";
+	my $filename = basename($project) . "-$hash.tar.$suffix";
 
 	print $cgi->header(-type => 'application/x-tar',
-			-content-encoding => 'x-gzip',
-			'-content-disposition' => "inline; filename=\"$filename\"",
-			-status => '200 OK');
+			   -content-encoding => $ctype,
+			   '-content-disposition' =>
+			   "inline; filename=\"$filename\"",
+			   -status => '200 OK');
 
-	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
-				die_error(undef, "Execute git-tar-tree failed.");
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" or
+		die_error(undef, "Execute git-tar-tree failed.");
 	binmode STDOUT, ':raw';
 	print <$fd>;
 	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
 	close $fd;
 
-
 }
 
 sub git_log {
@@ -2293,7 +2367,10 @@ sub git_commit {
 	}
 	my $refs = git_get_references();
 	my $ref = format_ref_marker($refs, $co{'id'});
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
Aneesh Kumar K.V· Aug 19, 2006, 16:26 UTC · re: Aneesh Kumar K.V · lore

Re: [PATCH] gitweb: Support for snapshot

Aneesh Kumar K.V wrote:
Show 10 quoted lines
> Jakub Narebski wrote:
>> Aneesh Kumar K.V wrote:
>>
>>> I tested this and added some comments. I also fixed some code. I am 
>>> attaching the full diff. 
>>
>> Below comments to the patch.
>>
> 
> updated patch attached. I guess i have taken care of all your comments.
After fixing some comments and adding signed-off
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@gmail.com>
-aneesh
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f8d1036..063735d 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -67,6 +67,68 @@ # file to use for guessing MIME types be
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+# You define site-wide feature defaults here; override them with
+# $GITWEB_CONFIG as necessary.
+our %feature =
+(
+
+# feature  => {'sub' => feature-sub, 'override' => allow-override, 'default' => [ default options...]
+
+'blame'         => {'sub' => \&feature_blame, 'override' => 0, 'default' => [0]},
+'snapshot'      => {'sub' => \&feature_snapshot, 'override' => 0, 'default' => ['x-gzip', 'gz', 'gzip']},
+
+);
+
+sub gitweb_check_feature {
+	my ($name) = @_;
+	return undef unless exists $feature{$name};
+	my ($sub, $override, @defaults) = ($feature{$name}{'sub'},
+						$feature{$name}{'override'},
+						@{$feature{$name}{'default'}});
+	if (!$override) { return @defaults; }
+	return $sub->(@defaults);
+}
+
+# To enable system wide have in $GITWEB_CONFIG
+# $feature{'blame'}{'default'} =  [1];
+# To have project specific config enable override in  $GITWEB_CONFIG
+# $feature{'blame'}{'override'} =  1;
+# and in project config gitweb.blame = 0|1;
+
+sub feature_blame {
+	my ($val) = git_get_project_config('blame', '--bool');
+
+	if ($val eq 'true') {
+		return 1;
+	} elsif ($val eq 'false') {
+		return 0;
+	}
+
+	return $_[0];
+}
+
+# To disable system wide have in $GITWEB_CONFIG
+# $feature{'snapshot'}{'default'} =  [undef];
+# To have project specific config enable override in  $GITWEB_CONFIG
+# $feature{'blame'}{'override'} =  1;
+# and in project config  gitweb.snapshot = none|gzip|bzip2
+
+sub feature_snapshot {
+	my ($ctype, $suffix, $command) = @_;
+
+	my ($val) = git_get_project_config('snapshot');
+
+	if ($val eq 'gzip') {
+		return ('x-gzip', 'gz', 'gzip');
+	} elsif ($val eq 'bzip2') {
+		return ('x-bzip2', 'bz2', 'bzip2');
+	} elsif ($val eq 'none') {
+		return ();
+	}
+
+	return ($ctype, $suffix, $command);
+}
+
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
 require $GITWEB_CONFIG if -e $GITWEB_CONFIG;
 
@@ -485,24 +547,21 @@ sub git_get_type {
 }
 
 sub git_get_project_config {
-	my $key = shift;
+	my ($key, $type) = @_;
 
 	return unless ($key);
 	$key =~ s/^gitweb\.//;
 	return if ($key =~ m/\W/);
 
-	my $val = qx($GIT repo-config --get gitweb.$key);
+	my @x = ($GIT, 'repo-config');
+	if (defined $type) { push @x, $type; }
+	push @x, "--get";
+	push @x, "gitweb.$key";
+	my $val = qx(@x);
+	chomp $val;
 	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;
@@ -1397,7 +1456,10 @@ sub git_difftree_body {
 sub git_shortlog_body {
 	# uses global variable $project
 	my ($revlist, $from, $to, $refs, $extra) = @_;
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	$from = 0 unless defined $from;
 	$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
 
@@ -1858,7 +1920,10 @@ sub git_tag {
 sub git_blame2 {
 	my $fd;
 	my $ftype;
-	die_error(undef, "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error('403 Permission denied', "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -1916,7 +1981,10 @@ sub git_blame2 {
 
 sub git_blame {
 	my $fd;
-	die_error('403 Permission denied', "Permission denied") if (!git_get_project_config_bool ('blame'));
+
+	if (!gitweb_check_feature('blame')) {
+		die_error('403 Permission denied', "Permission denied");
+	}
 	die_error('404 Not Found', "File name not defined") if (!$file_name);
 	$hash_base ||= git_get_head_hash($project);
 	die_error(undef, "Couldn't find base commit") unless ($hash_base);
@@ -2069,7 +2137,7 @@ sub git_blob {
 			die_error(undef, "No file name defined");
 		}
 	}
-	my $have_blame = git_get_project_config_bool ('blame');
+	my $have_blame = gitweb_check_feature('blame');
 	open my $fd, "-|", $GIT, "cat-file", "blob", $hash
 		or die_error(undef, "Couldn't cat $file_name, $hash");
 	my $mimetype = blob_mimetype($fd, $file_name);
@@ -2134,7 +2202,7 @@ sub git_tree {
 	git_header_html();
 	my %base_key = ();
 	my $base = "";
-	my $have_blame = git_get_project_config_bool ('blame');
+	my $have_blame = gitweb_check_feature('blame');
 	if (defined $hash_base && (my %co = parse_commit($hash_base))) {
 		$base_key{hash_base} = $hash_base;
 		git_print_page_nav('tree','', $hash_base);
@@ -2195,25 +2263,31 @@ sub git_tree {
 
 sub git_snapshot {
 
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+	if (!$have_snapshot) {
+		die_error('403 Permission denied', "Permission denied");
+	}
+
 	if (!defined $hash) {
 		$hash = git_get_head_hash($project);
 	}
 
-	my $filename = basename($project) . "-$hash.tar.gz";
+	my $filename = basename($project) . "-$hash.tar.$suffix";
 
 	print $cgi->header(-type => 'application/x-tar',
-			-content-encoding => 'x-gzip',
-			'-content-disposition' => "inline; filename=\"$filename\"",
-			-status => '200 OK');
+			   -content-encoding => $ctype,
+			   '-content-disposition' =>
+			   "inline; filename=\"$filename\"",
+			   -status => '200 OK');
 
-	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | gzip" or
-				die_error(undef, "Execute git-tar-tree failed.");
+	open my $fd, "-|", "$GIT tar-tree $hash \'$project\' | $command" or
+		die_error(undef, "Execute git-tar-tree failed.");
 	binmode STDOUT, ':raw';
 	print <$fd>;
 	binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
 	close $fd;
 
-
 }
 
 sub git_log {
@@ -2293,7 +2367,10 @@ sub git_commit {
 	}
 	my $refs = git_get_references();
 	my $ref = format_ref_marker($refs, $co{'id'});
-	my $have_snapshot = git_get_project_config_bool('snapshot');
+
+	my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+	my $have_snapshot = (defined $ctype && defined $suffix);
+
 	my $formats_nav = '';
 	if (defined $file_name && defined $co{'parent'}) {
 		my $parent = $co{'parent'};
Junio C Hamano· Aug 19, 2006, 21:49 UTC · re: Jakub Narebski · lore

Re: [PATCH] gitweb: Support for snapshot

Jakub Narebski <jnareb@gmail.com> writes:
Show 8 quoted lines
> Below comments to the patch.
>...
> Wouldn't it make it easier to understand code to put %feature hash 
> and gitweb_check_feature subroutine _before_ subroutines for specific
> features?
>
> It would be enough to put:
> $feature{'snapshot'} =  [\&feature_snapshot, 0, undef];

Yes; although actually even 'undef' is not needed, I think it makes sense to have at least one there ;-).

Show 11 quoted lines
> By the way, wouldn't it be better to use _hash_ for mixed meaning
> than _array_? I.e.
>
> our %feature =
> (
>        # feature       => {'sub' => feature-sub, 'override' => allow-override, 'default' => default options...]
>
>        'blame'         => {'sub' => \&feature_blame, 'override' => 0, 'default' => 0},
>    #or 'blame'         => {'sub' => \&feature_blame, 'override' => 0, 'default' => [ 0 ]},
>        'snapshot'      => {'sub' => \&feature_snapshot, 'override' => 0, 'default => [ 'x-gzip', 'gz', 'gzip' ]},
> );

I like it better except that you made it wider than my terminal again making it a lot harder to read.

← back to recent threads