Skip to content

Commit a3c8ab3

Browse files
Matt McCutchengitster
authored andcommitted
gitweb: snapshot cleanups & support for offering multiple formats
- Centralize knowledge about snapshot formats (mime types, extensions, commands) in %known_snapshot_formats and improve how some of that information is specified. In particular, zip files are no longer a special case. - Add support for offering multiple snapshot formats to the user so that he/she can download a snapshot in the format he/she prefers. The site-wide or project configuration now gives a list of formats to offer, and if more than one format is offered, the "_snapshot_" link becomes something like "snapshot (_tar.bz2_ _zip_)". - If only one format is offered, a tooltip on the "_snapshot_" link tells the user what it is. - Fix out-of-date "tarball" -> "archive" in comment. Alert for gitweb site administrators: This patch changes the format of $feature{'snapshot'}{'default'} in gitweb_config.perl from a list of three pieces of information about a single format to a list of one or more formats you wish to offer from the set ('tgz', 'tbz2', 'zip'). Update your gitweb_config.perl appropriately. There was taken care for old-style gitweb configuration to work as it used to, but this backward compatibility works only for the values which correspond to gitweb.snapshot values of 'gzip', 'bzip2' and 'zip', i.e. ['x-gzip', 'gz', 'gzip'] ['x-bzip2', 'bz2', 'bzip2'] ['x-zip', 'zip', ''] The preferred names for gitweb.snapshot in repository configuration have also changed from 'gzip' and 'bzip2' to 'tgz' and 'tbz2', but the old names are still recognized for compatibility. Signed-off-by: Matt McCutchen <hashproduct@gmail.com> Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 6368f3f commit a3c8ab3

File tree

1 file changed

+116
-50
lines changed

1 file changed

+116
-50
lines changed

gitweb/gitweb.perl

Lines changed: 116 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,49 @@ BEGIN
114114
# - one might want to include '-B' option, e.g. '-B', '-M'
115115
our @diff_opts = ('-M'); # taken from git_commit
116116

117+
# information about snapshot formats that gitweb is capable of serving
118+
our %known_snapshot_formats = (
119+
# name => {
120+
# 'display' => display name,
121+
# 'type' => mime type,
122+
# 'suffix' => filename suffix,
123+
# 'format' => --format for git-archive,
124+
# 'compressor' => [compressor command and arguments]
125+
# (array reference, optional)}
126+
#
127+
'tgz' => {
128+
'display' => 'tar.gz',
129+
'type' => 'application/x-gzip',
130+
'suffix' => '.tar.gz',
131+
'format' => 'tar',
132+
'compressor' => ['gzip']},
133+
134+
'tbz2' => {
135+
'display' => 'tar.bz2',
136+
'type' => 'application/x-bzip2',
137+
'suffix' => '.tar.bz2',
138+
'format' => 'tar',
139+
'compressor' => ['bzip2']},
140+
141+
'zip' => {
142+
'display' => 'zip',
143+
'type' => 'application/x-zip',
144+
'suffix' => '.zip',
145+
'format' => 'zip'},
146+
);
147+
148+
# Aliases so we understand old gitweb.snapshot values in repository
149+
# configuration.
150+
our %known_snapshot_format_aliases = (
151+
'gzip' => 'tgz',
152+
'bzip2' => 'tbz2',
153+
154+
# backward compatibility: legacy gitweb config support
155+
'x-gzip' => undef, 'gz' => undef,
156+
'x-bzip2' => undef, 'bz2' => undef,
157+
'x-zip' => undef, '' => undef,
158+
);
159+
117160
# You define site-wide feature defaults here; override them with
118161
# $GITWEB_CONFIG as necessary.
119162
our %feature = (
@@ -144,20 +187,22 @@ BEGIN
144187
'override' => 0,
145188
'default' => [0]},
146189

147-
# Enable the 'snapshot' link, providing a compressed tarball of any
190+
# Enable the 'snapshot' link, providing a compressed archive of any
148191
# tree. This can potentially generate high traffic if you have large
149192
# project.
150193

194+
# Value is a list of formats defined in %known_snapshot_formats that
195+
# you wish to offer.
151196
# To disable system wide have in $GITWEB_CONFIG
152-
# $feature{'snapshot'}{'default'} = [undef];
197+
# $feature{'snapshot'}{'default'} = [];
153198
# To have project specific config enable override in $GITWEB_CONFIG
154199
# $feature{'snapshot'}{'override'} = 1;
155-
# and in project config gitweb.snapshot = none|gzip|bzip2|zip;
200+
# and in project config, a comma-separated list of formats or "none"
201+
# to disable. Example: gitweb.snapshot = tbz2,zip;
156202
'snapshot' => {
157203
'sub' => \&feature_snapshot,
158204
'override' => 0,
159-
# => [content-encoding, suffix, program]
160-
'default' => ['x-gzip', 'gz', 'gzip']},
205+
'default' => ['tgz']},
161206

162207
# Enable text search, which will list the commits which match author,
163208
# committer or commit text to a given string. Enabled by default.
@@ -256,28 +301,19 @@ sub feature_blame {
256301
}
257302

258303
sub feature_snapshot {
259-
my ($ctype, $suffix, $command) = @_;
304+
my (@fmts) = @_;
260305

261306
my ($val) = git_get_project_config('snapshot');
262307

263-
if ($val eq 'gzip') {
264-
return ('x-gzip', 'gz', 'gzip');
265-
} elsif ($val eq 'bzip2') {
266-
return ('x-bzip2', 'bz2', 'bzip2');
267-
} elsif ($val eq 'zip') {
268-
return ('x-zip', 'zip', '');
269-
} elsif ($val eq 'none') {
270-
return ();
308+
if ($val) {
309+
@fmts = ($val eq 'none' ? () : split /\s*[,\s]\s*/, $val);
310+
@fmts = grep { defined } map {
311+
exists $known_snapshot_format_aliases{$_} ?
312+
$known_snapshot_format_aliases{$_} : $_ } @fmts;
313+
@fmts = grep(exists $known_snapshot_formats{$_}, @fmts);
271314
}
272315

273-
return ($ctype, $suffix, $command);
274-
}
275-
276-
sub gitweb_have_snapshot {
277-
my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
278-
my $have_snapshot = (defined $ctype && defined $suffix);
279-
280-
return $have_snapshot;
316+
return @fmts;
281317
}
282318

283319
sub feature_grep {
@@ -563,6 +599,7 @@ (%)
563599
order => "o",
564600
searchtext => "s",
565601
searchtype => "st",
602+
snapshot_format => "sf",
566603
);
567604
my %mapping = @mapping;
568605

@@ -1257,6 +1294,39 @@ sub format_diff_line {
12571294
return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n";
12581295
}
12591296

1297+
# Generates undef or something like "_snapshot_" or "snapshot (_tbz2_ _zip_)",
1298+
# linked. Pass the hash of the tree/commit to snapshot.
1299+
sub format_snapshot_links {
1300+
my ($hash) = @_;
1301+
my @snapshot_fmts = gitweb_check_feature('snapshot');
1302+
my $num_fmts = @snapshot_fmts;
1303+
if ($num_fmts > 1) {
1304+
# A parenthesized list of links bearing format names.
1305+
return "snapshot (" . join(' ', map
1306+
$cgi->a({
1307+
-href => href(
1308+
action=>"snapshot",
1309+
hash=>$hash,
1310+
snapshot_format=>$_
1311+
)
1312+
}, $known_snapshot_formats{$_}{'display'})
1313+
, @snapshot_fmts) . ")";
1314+
} elsif ($num_fmts == 1) {
1315+
# A single "snapshot" link whose tooltip bears the format name.
1316+
my ($fmt) = @snapshot_fmts;
1317+
return $cgi->a({
1318+
-href => href(
1319+
action=>"snapshot",
1320+
hash=>$hash,
1321+
snapshot_format=>$fmt
1322+
),
1323+
-title => "in format: $known_snapshot_formats{$fmt}{'display'}"
1324+
}, "snapshot");
1325+
} else { # $num_fmts == 0
1326+
return undef;
1327+
}
1328+
}
1329+
12601330
## ----------------------------------------------------------------------
12611331
## git utility subroutines, invoking git commands
12621332

@@ -3321,8 +3391,6 @@ sub git_shortlog_body {
33213391
# uses global variable $project
33223392
my ($commitlist, $from, $to, $refs, $extra) = @_;
33233393

3324-
my $have_snapshot = gitweb_have_snapshot();
3325-
33263394
$from = 0 unless defined $from;
33273395
$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
33283396

@@ -3349,8 +3417,9 @@ sub git_shortlog_body {
33493417
$cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
33503418
$cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
33513419
$cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree");
3352-
if ($have_snapshot) {
3353-
print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
3420+
my $snapshot_links = format_snapshot_links($commit);
3421+
if (defined $snapshot_links) {
3422+
print " | " . $snapshot_links;
33543423
}
33553424
print "</td>\n" .
33563425
"</tr>\n";
@@ -4132,8 +4201,6 @@ sub git_blob {
41324201
}
41334202

41344203
sub git_tree {
4135-
my $have_snapshot = gitweb_have_snapshot();
4136-
41374204
if (!defined $hash_base) {
41384205
$hash_base = "HEAD";
41394206
}
@@ -4167,11 +4234,10 @@ sub git_tree {
41674234
hash_base=>"HEAD", file_name=>$file_name)},
41684235
"HEAD"),
41694236
}
4170-
if ($have_snapshot) {
4237+
my $snapshot_links = format_snapshot_links($hash);
4238+
if (defined $snapshot_links) {
41714239
# FIXME: Should be available when we have no hash base as well.
4172-
push @views_nav,
4173-
$cgi->a({-href => href(action=>"snapshot", hash=>$hash)},
4174-
"snapshot");
4240+
push @views_nav, $snapshot_links;
41754241
}
41764242
git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav));
41774243
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
@@ -4235,33 +4301,36 @@ sub git_tree {
42354301
}
42364302

42374303
sub git_snapshot {
4238-
my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
4239-
my $have_snapshot = (defined $ctype && defined $suffix);
4240-
if (!$have_snapshot) {
4241-
die_error('403 Permission denied', "Permission denied");
4304+
my @supported_fmts = gitweb_check_feature('snapshot');
4305+
4306+
my $format = $cgi->param('sf');
4307+
unless ($format =~ m/[a-z0-9]+/
4308+
&& exists($known_snapshot_formats{$format})
4309+
&& grep($_ eq $format, @supported_fmts)) {
4310+
die_error(undef, "Unsupported snapshot format");
42424311
}
42434312

42444313
if (!defined $hash) {
42454314
$hash = git_get_head_hash($project);
42464315
}
42474316

4248-
my $git = git_cmd_str();
4317+
my $git_command = git_cmd_str();
42494318
my $name = $project;
42504319
$name =~ s,([^/])/*\.git$,$1,;
42514320
$name = basename($name);
42524321
my $filename = to_utf8($name);
42534322
$name =~ s/\047/\047\\\047\047/g;
42544323
my $cmd;
4255-
if ($suffix eq 'zip') {
4256-
$filename .= "-$hash.$suffix";
4257-
$cmd = "$git archive --format=zip --prefix=\'$name\'/ $hash";
4258-
} else {
4259-
$filename .= "-$hash.tar.$suffix";
4260-
$cmd = "$git archive --format=tar --prefix=\'$name\'/ $hash | $command";
4324+
$filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}";
4325+
$cmd = "$git_command archive " .
4326+
"--format=$known_snapshot_formats{$format}{'format'}" .
4327+
"--prefix=\'$name\'/ $hash";
4328+
if (exists $known_snapshot_formats{$format}{'compressor'}) {
4329+
$cmd .= ' | ' . join ' ', @{$known_snapshot_formats{$format}{'compressor'}};
42614330
}
42624331

42634332
print $cgi->header(
4264-
-type => "application/$ctype",
4333+
-type => $known_snapshot_formats{$format}{'type'},
42654334
-content_disposition => 'inline; filename="' . "$filename" . '"',
42664335
-status => '200 OK');
42674336

@@ -4271,7 +4340,6 @@ sub git_snapshot {
42714340
print <$fd>;
42724341
binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
42734342
close $fd;
4274-
42754343
}
42764344

42774345
sub git_log {
@@ -4390,8 +4458,6 @@ sub git_commit {
43904458
my $refs = git_get_references();
43914459
my $ref = format_ref_marker($refs, $co{'id'});
43924460

4393-
my $have_snapshot = gitweb_have_snapshot();
4394-
43954461
git_header_html(undef, $expires);
43964462
git_print_page_nav('commit', '',
43974463
$hash, $co{'tree'}, $hash,
@@ -4430,9 +4496,9 @@ sub git_commit {
44304496
"<td class=\"link\">" .
44314497
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)},
44324498
"tree");
4433-
if ($have_snapshot) {
4434-
print " | " .
4435-
$cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
4499+
my $snapshot_links = format_snapshot_links($hash);
4500+
if (defined $snapshot_links) {
4501+
print " | " . $snapshot_links;
44364502
}
44374503
print "</td>" .
44384504
"</tr>\n";

0 commit comments

Comments
 (0)