Browse Source

Merge branch 'mr/gitweb-snapshot'

* mr/gitweb-snapshot:
  t/gitweb-lib: Split HTTP response with non-GNU sed
  gitweb: Smarter snapshot names
  gitweb: Document current snapshot rules via new tests
  t/gitweb-lib.sh: Split gitweb output into headers and body
  gitweb: check given hash before trying to create snapshot
maint
Junio C Hamano 15 years ago
parent
commit
2a971012b6
  1. 83
      gitweb/gitweb.perl
  2. 16
      t/gitweb-lib.sh
  3. 39
      t/t9501-gitweb-standalone-http-status.sh
  4. 115
      t/t9502-gitweb-standalone-parse-output.sh

83
gitweb/gitweb.perl

@ -2020,16 +2020,27 @@ sub quote_command {


# get HEAD ref of given project as hash # get HEAD ref of given project as hash
sub git_get_head_hash { sub git_get_head_hash {
my $project = shift; return git_get_full_hash(shift, 'HEAD');
}

sub git_get_full_hash {
return git_get_hash(@_);
}

sub git_get_short_hash {
return git_get_hash(@_, '--short=7');
}

sub git_get_hash {
my ($project, $hash, @options) = @_;
my $o_git_dir = $git_dir; my $o_git_dir = $git_dir;
my $retval = undef; my $retval = undef;
$git_dir = "$projectroot/$project"; $git_dir = "$projectroot/$project";
if (open my $fd, "-|", git_cmd(), "rev-parse", "--verify", "HEAD") { if (open my $fd, '-|', git_cmd(), 'rev-parse',
my $head = <$fd>; '--verify', '-q', @options, $hash) {
$retval = <$fd>;
chomp $retval if defined $retval;
close $fd; close $fd;
if (defined $head && $head =~ /^([0-9a-fA-F]{40})$/) {
$retval = $1;
}
} }
if (defined $o_git_dir) { if (defined $o_git_dir) {
$git_dir = $o_git_dir; $git_dir = $o_git_dir;
@ -5285,6 +5296,43 @@ sub git_tree {
git_footer_html(); git_footer_html();
} }


sub snapshot_name {
my ($project, $hash) = @_;

# path/to/project.git -> project
# path/to/project/.git -> project
my $name = to_utf8($project);
$name =~ s,([^/])/*\.git$,$1,;
$name = basename($name);
# sanitize name
$name =~ s/[[:cntrl:]]/?/g;

my $ver = $hash;
if ($hash =~ /^[0-9a-fA-F]+$/) {
# shorten SHA-1 hash
my $full_hash = git_get_full_hash($project, $hash);
if ($full_hash =~ /^$hash/ && length($hash) > 7) {
$ver = git_get_short_hash($project, $hash);
}
} elsif ($hash =~ m!^refs/tags/(.*)$!) {
# tags don't need shortened SHA-1 hash
$ver = $1;
} else {
# branches and other need shortened SHA-1 hash
if ($hash =~ m!^refs/(?:heads|remotes)/(.*)$!) {
$ver = $1;
}
$ver .= '-' . git_get_short_hash($project, $hash);
}
# in case of hierarchical branch names
$ver =~ s!/!.!g;

# name = project-version_string
$name = "$name-$ver";

return wantarray ? ($name, $name) : $name;
}

sub git_snapshot { sub git_snapshot {
my $format = $input_params{'snapshot_format'}; my $format = $input_params{'snapshot_format'};
if (!@snapshot_fmts) { if (!@snapshot_fmts) {
@ -5302,28 +5350,27 @@ sub git_snapshot {
die_error(403, "Unsupported snapshot format"); die_error(403, "Unsupported snapshot format");
} }


if (!defined $hash) { my $type = git_get_type("$hash^{}");
$hash = git_get_head_hash($project); if (!$type) {
die_error(404, 'Object does not exist');
} elsif ($type eq 'blob') {
die_error(400, 'Object is not a tree-ish');
} }


my $name = $project; my ($name, $prefix) = snapshot_name($project, $hash);
$name =~ s,([^/])/*\.git$,$1,; my $filename = "$name$known_snapshot_formats{$format}{'suffix'}";
$name = basename($name); my $cmd = quote_command(
my $filename = to_utf8($name);
$name =~ s/\047/\047\\\047\047/g;
my $cmd;
$filename .= "-$hash$known_snapshot_formats{$format}{'suffix'}";
$cmd = quote_command(
git_cmd(), 'archive', git_cmd(), 'archive',
"--format=$known_snapshot_formats{$format}{'format'}", "--format=$known_snapshot_formats{$format}{'format'}",
"--prefix=$name/", $hash); "--prefix=$prefix/", $hash);
if (exists $known_snapshot_formats{$format}{'compressor'}) { if (exists $known_snapshot_formats{$format}{'compressor'}) {
$cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}}); $cmd .= ' | ' . quote_command(@{$known_snapshot_formats{$format}{'compressor'}});
} }


$filename =~ s/(["\\])/\\$1/g;
print $cgi->header( print $cgi->header(
-type => $known_snapshot_formats{$format}{'type'}, -type => $known_snapshot_formats{$format}{'type'},
-content_disposition => 'inline; filename="' . "$filename" . '"', -content_disposition => 'inline; filename="' . $filename . '"',
-status => '200 OK'); -status => '200 OK');


open my $fd, "-|", $cmd open my $fd, "-|", $cmd

16
t/gitweb-lib.sh

@ -52,10 +52,24 @@ gitweb_run () {
rm -f gitweb.log && rm -f gitweb.log &&
perl -- "$SCRIPT_NAME" \ perl -- "$SCRIPT_NAME" \
>gitweb.output 2>gitweb.log && >gitweb.output 2>gitweb.log &&
perl -w -e '
open O, ">gitweb.headers";
while (<>) {
print O;
last if (/^\r$/ || /^$/);
}
open O, ">gitweb.body";
while (<>) {
print O;
}
close O;
' gitweb.output &&
if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi


# gitweb.log is left for debugging # gitweb.log is left for debugging
# gitweb.output is used to parse http output # gitweb.output is used to parse HTTP output
# gitweb.headers contains only HTTP headers
# gitweb.body contains body of message, without headers
} }


. ./test-lib.sh . ./test-lib.sh

39
t/t9501-gitweb-standalone-http-status.sh

@ -75,4 +75,43 @@ test_expect_success \
test_debug 'cat gitweb.output' test_debug 'cat gitweb.output'




# ----------------------------------------------------------------------
# snapshot hash ids

test_expect_success 'snapshots: good tree-ish id' '
gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" &&
grep "Status: 200 OK" gitweb.output
'
test_debug 'cat gitweb.output'

test_expect_success 'snapshots: bad tree-ish id' '
gitweb_run "p=.git;a=snapshot;h=frizzumFrazzum;sf=tgz" &&
grep "404 - Object does not exist" gitweb.output
'
test_debug 'cat gitweb.output'

test_expect_success 'snapshots: bad tree-ish id (tagged object)' '
echo object > tag-object &&
git add tag-object &&
git commit -m "Object to be tagged" &&
git tag tagged-object `git hash-object tag-object` &&
gitweb_run "p=.git;a=snapshot;h=tagged-object;sf=tgz" &&
grep "400 - Object is not a tree-ish" gitweb.output
'
test_debug 'cat gitweb.output'

test_expect_success 'snapshots: good object id' '
ID=`git rev-parse --verify HEAD` &&
gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" &&
grep "Status: 200 OK" gitweb.output
'
test_debug 'cat gitweb.output'

test_expect_success 'snapshots: bad object id' '
gitweb_run "p=.git;a=snapshot;h=abcdef01234;sf=tgz" &&
grep "404 - Object does not exist" gitweb.output
'
test_debug 'cat gitweb.output'


test_done test_done

115
t/t9502-gitweb-standalone-parse-output.sh

@ -0,0 +1,115 @@
#!/bin/sh
#
# Copyright (c) 2009 Mark Rada
#

test_description='gitweb as standalone script (parsing script output).

This test runs gitweb (git web interface) as a CGI script from the
commandline, and checks that it produces the correct output, either
in the HTTP header or the actual script output.'


. ./gitweb-lib.sh

# ----------------------------------------------------------------------
# snapshot file name and prefix

cat >>gitweb_config.perl <<\EOF

$known_snapshot_formats{'tar'} = {
'display' => 'tar',
'type' => 'application/x-tar',
'suffix' => '.tar',
'format' => 'tar',
};

$feature{'snapshot'}{'default'} = ['tar'];
EOF

# Call check_snapshot with the arguments "<basename> [<prefix>]"
#
# This will check that gitweb HTTP header contains proposed filename
# as <basename> with '.tar' suffix added, and that generated tarfile
# (gitweb message body) has <prefix> as prefix for al files in tarfile
#
# <prefix> default to <basename>
check_snapshot () {
basename=$1
prefix=${2:-"$1"}
echo "basename=$basename"
grep "filename=.*$basename.tar" gitweb.headers >/dev/null 2>&1 &&
"$TAR" tf gitweb.body >file_list &&
! grep -v "^$prefix/" file_list
}

test_expect_success setup '
test_commit first foo &&
git branch xx/test &&
FULL_ID=$(git rev-parse --verify HEAD) &&
SHORT_ID=$(git rev-parse --verify --short=7 HEAD)
'
test_debug '
echo "FULL_ID = $FULL_ID"
echo "SHORT_ID = $SHORT_ID"
'

test_expect_success 'snapshot: full sha1' '
gitweb_run "p=.git;a=snapshot;h=$FULL_ID;sf=tar" &&
check_snapshot ".git-$SHORT_ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: shortened sha1' '
gitweb_run "p=.git;a=snapshot;h=$SHORT_ID;sf=tar" &&
check_snapshot ".git-$SHORT_ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: almost full sha1' '
ID=$(git rev-parse --short=30 HEAD) &&
gitweb_run "p=.git;a=snapshot;h=$ID;sf=tar" &&
check_snapshot ".git-$SHORT_ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: HEAD' '
gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tar" &&
check_snapshot ".git-HEAD-$SHORT_ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: short branch name (master)' '
gitweb_run "p=.git;a=snapshot;h=master;sf=tar" &&
ID=$(git rev-parse --verify --short=7 master) &&
check_snapshot ".git-master-$ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: short tag name (first)' '
gitweb_run "p=.git;a=snapshot;h=first;sf=tar" &&
ID=$(git rev-parse --verify --short=7 first) &&
check_snapshot ".git-first-$ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: full branch name (refs/heads/master)' '
gitweb_run "p=.git;a=snapshot;h=refs/heads/master;sf=tar" &&
ID=$(git rev-parse --verify --short=7 master) &&
check_snapshot ".git-master-$ID"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: full tag name (refs/tags/first)' '
gitweb_run "p=.git;a=snapshot;h=refs/tags/first;sf=tar" &&
check_snapshot ".git-first"
'
test_debug 'cat gitweb.headers && cat file_list'

test_expect_success 'snapshot: hierarchical branch name (xx/test)' '
gitweb_run "p=.git;a=snapshot;h=xx/test;sf=tar" &&
! grep "filename=.*/" gitweb.headers
'
test_debug 'cat gitweb.headers'

test_done
Loading…
Cancel
Save