@matheusbsbs / matheus-bagliano / commits / b629275fd0
Fork 0

gitweb: Smarter snapshot names

Teach gitweb how to produce nicer snapshot names by only using the short hash id. If clients make requests using a tree-ish that is not a partial or full SHA-1 hash, then the short hash will also be appended to whatever they asked for. If clients request snapshot of a tag (which means that $hash ('h') parameter has 'refs/tags/' prefix), use only tag name. Update tests cases in t9502-gitweb-standalone-parse-output. Gitweb uses the following format for snapshot filenames: <sanitized project name>-<version info>.<snapshot suffix> where <sanitized project name> is project name with '.git' or '/.git' suffix stripped, unless '.git' is the whole project name. For snapshot prefix it uses: <sanitized project name>-<version info>/ as compared to <sanitized project name>/ before (without version info). Current rules for <version info>: * if 'h' / $hash parameter is SHA-1 or shortened SHA-1, use SHA-1 shortened to to 7 characters * otherwise if 'h' / $hash parameter is tag name (it begins with 'refs/tags/' prefix, use tag name (with 'refs/tags/' stripped * otherwise if 'h' / $hash parameter starts with 'refs/heads/' prefix, strip this prefix, convert '/' into '.', and append shortened SHA-1 after '-', i.e. use <sanitized hash>-<shortened sha1> Signed-off-by: Mark Rada <marada@uwaterloo.ca> Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Jakub Narebski <jnareb@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Mark Rada committed Nov 7, 2009 at 16:13 UTC b629275fd02aa07c2630d1a8c8a14011ff164043
2 files changed +93 -21
gitweb/gitweb.perl
+60 -16
@@ -1983,16 +1983,27 @@ sub quote_command {
1983
1984 # get HEAD ref of given project as hash
1985 sub git_get_head_hash {
1986 - my $project = shift;
1986 + return git_get_full_hash(shift, 'HEAD');
1987 +}
1988 +
1989 +sub git_get_full_hash {
1990 + return git_get_hash(@_);
1991 +}
1992 +
1993 +sub git_get_short_hash {
1994 + return git_get_hash(@_, '--short=7');
1995 +}
1996 +
1997 +sub git_get_hash {
1998 + my ($project, $hash, @options) = @_;
1999 my $o_git_dir = $git_dir;
2000 my $retval = undef;
2001 $git_dir = "$projectroot/$project";
1990 - if (open my $fd, "-|", git_cmd(), "rev-parse", "--verify", "HEAD") {
1991 - my $head = <$fd>;
2002 + if (open my $fd, '-|', git_cmd(), 'rev-parse',
2003 + '--verify', '-q', @options, $hash) {
2004 + $retval = <$fd>;
2005 + chomp $retval if defined $retval;
2006 close $fd;
1993 - if (defined $head && $head =~ /^([0-9a-fA-F]{40})$/) {
1994 - $retval = $1;
1995 - }
2007 }
2008 if (defined $o_git_dir) {
2009 $git_dir = $o_git_dir;
@@ -5179,6 +5190,43 @@ sub git_tree {
5190 git_footer_html();
5191 }
5192
5193 +sub snapshot_name {
5194 + my ($project, $hash) = @_;
5195 +
5196 + # path/to/project.git -> project
5197 + # path/to/project/.git -> project
5198 + my $name = to_utf8($project);
5199 + $name =~ s,([^/])/*\.git$,$1,;
5200 + $name = basename($name);
5201 + # sanitize name
5202 + $name =~ s/[[:cntrl:]]/?/g;
5203 +
5204 + my $ver = $hash;
5205 + if ($hash =~ /^[0-9a-fA-F]+$/) {
5206 + # shorten SHA-1 hash
5207 + my $full_hash = git_get_full_hash($project, $hash);
5208 + if ($full_hash =~ /^$hash/ && length($hash) > 7) {
5209 + $ver = git_get_short_hash($project, $hash);
5210 + }
5211 + } elsif ($hash =~ m!^refs/tags/(.*)$!) {
5212 + # tags don't need shortened SHA-1 hash
5213 + $ver = $1;
5214 + } else {
5215 + # branches and other need shortened SHA-1 hash
5216 + if ($hash =~ m!^refs/(?:heads|remotes)/(.*)$!) {
5217 + $ver = $1;
5218 + }
5219 + $ver .= '-' . git_get_short_hash($project, $hash);
5220 + }
5221 + # in case of hierarchical branch names
5222 + $ver =~ s!/!.!g;
5223 +
5224 + # name = project-version_string
5225 + $name = "$name-$ver";
5226 +
5227 + return wantarray ? ($name, $name) : $name;
5228 +}
5229 +
5230 sub git_snapshot {
5231 my $format = $input_params{'snapshot_format'};
5232 if (!@snapshot_fmts) {
@@ -5203,24 +5251,20 @@ sub git_snapshot {
5251 die_error(400, 'Object is not a tree-ish');
5252 }
5253
5206 - my $name = $project;
5207 - $name =~ s,([^/])/*\.git$,$1,;
5208 - $name = basename($name);
5209 - my $filename = to_utf8($name);
5210 - $name =~ s/\047/\047\\\047\047/g;
5211 - my $cmd;
5212 - $filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}";
5213 - $cmd = quote_command(
5254 + my ($name, $prefix) = snapshot_name($project, $hash);
5255 + my $filename = "$name$known_snapshot_formats{$format}{'suffix'}";
5256 + my $cmd = quote_command(
5257 git_cmd(), 'archive',
5258 "--format=$known_snapshot_formats{$format}{'format'}",
5216 - "--prefix=$name/", $hash);
5259 + "--prefix=$prefix/", $hash);
5260 if (exists $known_snapshot_formats{$format}{'compressor'}) {
5261 $cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}});
5262 }
5263
5264 + $filename =~ s/(["\\])/\\$1/g;
5265 print $cgi->header(
5266 -type => $known_snapshot_formats{$format}{'type'},
5223 - -content_disposition => 'inline; filename="' . "$filename" . '"',
5267 + -content_disposition => 'inline; filename="' . $filename . '"',
5268 -status => '200 OK');
5269
5270 open my $fd, "-|", $cmd
t/t9502-gitweb-standalone-parse-output.sh
+33 -5
@@ -56,29 +56,57 @@ test_debug '
56
57 test_expect_success 'snapshot: full sha1' '
58 gitweb_run "p=.git;a=snapshot;h=$FULL_ID;sf=tar" &&
59 - check_snapshot ".git-$FULL_ID" ".git"
59 + check_snapshot ".git-$SHORT_ID"
60 '
61 test_debug 'cat gitweb.headers && cat file_list'
62
63 test_expect_success 'snapshot: shortened sha1' '
64 gitweb_run "p=.git;a=snapshot;h=$SHORT_ID;sf=tar" &&
65 - check_snapshot ".git-$SHORT_ID" ".git"
65 + check_snapshot ".git-$SHORT_ID"
66 +'
67 +test_debug 'cat gitweb.headers && cat file_list'
68 +
69 +test_expect_success 'snapshot: almost full sha1' '
70 + ID=$(git rev-parse --short=30 HEAD) &&
71 + gitweb_run "p=.git;a=snapshot;h=$ID;sf=tar" &&
72 + check_snapshot ".git-$SHORT_ID"
73 '
74 test_debug 'cat gitweb.headers && cat file_list'
75
76 test_expect_success 'snapshot: HEAD' '
77 gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tar" &&
71 - check_snapshot ".git-HEAD" ".git"
78 + check_snapshot ".git-HEAD-$SHORT_ID"
79 '
80 test_debug 'cat gitweb.headers && cat file_list'
81
82 test_expect_success 'snapshot: short branch name (master)' '
83 gitweb_run "p=.git;a=snapshot;h=master;sf=tar" &&
77 - check_snapshot ".git-master" ".git"
84 + ID=$(git rev-parse --verify --short=7 master) &&
85 + check_snapshot ".git-master-$ID"
86 +'
87 +test_debug 'cat gitweb.headers && cat file_list'
88 +
89 +test_expect_success 'snapshot: short tag name (first)' '
90 + gitweb_run "p=.git;a=snapshot;h=first;sf=tar" &&
91 + ID=$(git rev-parse --verify --short=7 first) &&
92 + check_snapshot ".git-first-$ID"
93 +'
94 +test_debug 'cat gitweb.headers && cat file_list'
95 +
96 +test_expect_success 'snapshot: full branch name (refs/heads/master)' '
97 + gitweb_run "p=.git;a=snapshot;h=refs/heads/master;sf=tar" &&
98 + ID=$(git rev-parse --verify --short=7 master) &&
99 + check_snapshot ".git-master-$ID"
100 +'
101 +test_debug 'cat gitweb.headers && cat file_list'
102 +
103 +test_expect_success 'snapshot: full tag name (refs/tags/first)' '
104 + gitweb_run "p=.git;a=snapshot;h=refs/tags/first;sf=tar" &&
105 + check_snapshot ".git-first"
106 '
107 test_debug 'cat gitweb.headers && cat file_list'
108
81 -test_expect_failure 'snapshot: hierarchical branch name (xx/test)' '
109 +test_expect_success 'snapshot: hierarchical branch name (xx/test)' '
110 gitweb_run "p=.git;a=snapshot;h=xx/test;sf=tar" &&
111 ! grep "filename=.*/" gitweb.headers
112 '