Skip to content

On top of seveas/snapshot, allow one to specify a custom snapshot generator #41

Open
wants to merge 2 commits into from
View
1 ISSUES
@@ -4,4 +4,3 @@
* Gitweb compat URIs are borked - there were some I just wholesale ripped out. Put back..
* Sort out commitdiff so conflicted merges have an equivalent display to gitweb (d7f39bebabeb31ce9a7b4f1b6f3db9f391b78c3e as a reference)
* Need to sanitise the input ...
-* The snapshot action does not properly support tgz - requests for this format will receive a tar. tbz2 is not supported at all (yet).
View
8 gitalist.conf
@@ -20,3 +20,11 @@ sitename "A Gitalist"
<patches>
max = 16
</patches>
+
+<snapshot>
+ format = tar.bz2
+ tmpdir = /tmp/gitalist/snapshot
+# This command can be used instead of git archive to generate the snapshot
+# It must understand --git-dir, --output, --prefix and --format
+# custom_snapshot = /usr/local/bin/my_snapshot.pl
+</snapshot>
View
11 lib/Gitalist/Controller/Ref.pm
@@ -49,15 +49,18 @@ Provides a snapshot of a given commit.
sub snapshot : Chained('find') PathPart('snapshot') Args() {
my ($self, $c, $format) = @_;
- $format ||= 'tgz';
+ $format ||= Gitalist->config->{snapshot}{format} || "tar.bz2";
my @snap = $c->stash->{Repository}->snapshot(
sha1 => $c->stash->{Commit}->sha1,
format => $format
);
$c->response->status(200);
- $c->response->headers->header( 'Content-Disposition' =>
- "attachment; filename=$snap[0]");
- $c->response->body($snap[1]);
+ $c->response->content_type($snap[0]);
+ $c->response->content_length(-s $snap[2]);
+ $c->response->headers->header('Content-Disposition' =>
+ "attachment; filename=$snap[1]");
+ open(my $fh, '<', $snap[2]);
+ $c->response->body($fh);
}
=head2 patch
View
53 lib/Gitalist/Git/Repository.pm
@@ -12,6 +12,9 @@ class Gitalist::Git::Repository with (Gitalist::Git::HasUtils, Gitalist::Git::Se
use aliased 'DateTime' => 'DT';
use List::MoreUtils qw/any zip/;
use Encode qw/decode/;
+ use IPC::Run qw/run/;
+ use File::Spec qw/catfile/;
+ use File::Path qw/mkpath/;
use if $^O ne 'MSWin32' => 'I18N::Langinfo', qw/langinfo CODESET/;
@@ -150,20 +153,56 @@ class Gitalist::Git::Repository with (Gitalist::Git::HasUtils, Gitalist::Git::Se
NonEmptySimpleStr :$format
) {
# TODO - only valid formats are 'tar' and 'zip'
- my $formats = { tgz => 'tar', zip => 'zip' };
+ my $formats = {
+ 'tar.gz' => 'tar',
+ 'tar.bz2' => 'tar',
+ zip => 'zip',
+ };
+ my $compressors = {
+ 'tar.gz' => 'gzip',
+ 'tar.bz2' => 'bzip2',
+ 'tar.xz' => 'xz',
+ };
+ my $mimetypes = {
+ 'tar.gz' => 'application/x-gzip',
+ 'tar.bz2' => 'application/x-bzip2',
+ 'tar.xz' => 'application/octet-stream',
+ };
unless ($formats->exists($format)) {
die("No such format: $format");
}
- $format = $formats->{$format};
+ my $ga_format = $formats->{$format};
my $name = $self->name;
$name =~ s,([^/])/*\.git$,$1,;
- my $filename = $name;
- $filename .= "-$sha1.$format";
+ my $sha1_abbrev = $self->run_cmd(('log', '--pretty=format:%h', '-1', $sha1));
+ my $filename = "$name-$sha1_abbrev.$format";
+ my $ga_filename = "$name-$sha1_abbrev.$ga_format";
$name =~ s/\047/\047\\\047\047/g;
- my @cmd = ('archive', "--format=$format", "--prefix=$name/", $sha1);
- return ($filename, $self->run_cmd_fh(@cmd));
- # TODO - support compressed archives
+ my $local_dir = Gitalist->config->{snapshot}{tmpdir} || "/tmp/gitalist/snapshot";
+ $local_dir = File::Spec->catfile($local_dir, substr($sha1,0,2), substr($sha1,0,4));
+ my $local_filename = File::Spec->catfile($local_dir, $filename);
+ my $local_ga_filename = File::Spec->catfile($local_dir, $ga_filename);
+ if(!-e $local_filename) {
+ if(! -e $local_dir) {
+ mkpath($local_dir, 0, 0755);
+ }
+ my @cmd = ('archive', "--format=$ga_format", "--prefix=$name-$sha1_abbrev/", "--output=$local_ga_filename", $sha1);
+ if(my $custom = Gitalist->config->{snapshot}->{custom_snapshot}) {
+ shift @cmd;
+ unshift @cmd, ($custom, '--git-dir' => $self->path);
+ require IPC::Run;
+ IPC::Run::run [ @cmd ], \my($in, $out, $err);
+ }
+ else {
+ $self->run_cmd(@cmd);
+ }
+ if($compressors->exists($format)) {
+ run [$compressors->{$format}, $local_ga_filename];
+ }
+ }
+
+ return ($mimetypes->{$format}, $filename, $local_filename);
}
method reflog (@logargs) {
View
1 root/fragment/repository/shortlog.tt2
@@ -33,6 +33,7 @@
<a href="[% c.uri_for_action("/ref/commit", [Repository.name, line.sha1]) %]" title="Commit details" class="button commit">commit</a>
<a href="[% c.uri_for_action("/ref/diff_fancy", [Repository.name, line.sha1]) %]" title="Commit difference" class="button diff">commitdiff</a>
<a href="[% c.uri_for_action("/ref/tree", [Repository.name, line.sha1]) %]" title="Tree" class="button tree">tree</a>
+ <a href="[% c.uri_for_action("/ref/snapshot", [Repository.name, line.sha1]) %]" title="Snapshot" class="button snapshot">snapshot</a>
</td>
</tr>
[% END %]
View
5 root/static/css/core.css
@@ -258,6 +258,9 @@ a.longlog{
a.blob{
background:transparent url([% c.uri_for('/static/i/icons/blob.png') %]) no-repeat;
}
+a.snapshot{
+ background:transparent url([% c.uri_for('/static/i/icons/blob.png') %]) no-repeat;
+}
a.blame{
background:transparent url([% c.uri_for('/static/i/icons/blame.png') %]) no-repeat;
}
@@ -444,7 +447,7 @@ BUT the final width needs to be set with javascript based on the parent element
*/
.action-list{
- width:120px;
+ width:160px;
}
.diff-tree{
View
95 script/snapshot_example.pl
@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+#
+# This is an example of a custom snapshot generator for gitweb/gitalist. It is
+# in active use by the perl 5 porters on perl5.git.perl.org.
+#
+# It doesn't do much, it only adds a .patch file with patch info as used by the
+# perl build/test process.
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use POSIX qw(strftime);
+use IPC::Cmd qw(run);
+use Data::Dumper;
+use File::Spec;
+use File::Basename;
+use version;
+
+$ENV{PATH}="/usr/local/bin:/bin/:/usr/bin";
+
+my $format = 'tar';
+my $output;
+my $git_dir;
+my $prefix;
+
+my $result = GetOptions(
+ 'format=s' => \$format,
+ 'output=s', => \$output,
+ 'git-dir=s', => \$git_dir,
+ 'prefix=s', => \$prefix,
+);
+my $sha1 = $ARGV[0];
+
+# Get commit info:
+# - branch name. If it's on multiple, prefer the name blead, then maint-*, then others
+my $branches;
+my $res = scalar run(
+ command => [ "git", "--git-dir", $git_dir, "branch", "--contains", $sha1, '--all' ],
+ buffer => \$branches,
+);
+chomp($branches);
+my @branches = sort branchcmp (map { s/^..//; $_ } split(/\n/, $branches));
+my $branch = $branches[0];
+$branch =~ s![/ ]!-!g;
+
+# - Abbreviated commit and timestamp
+my ($sha1_abbrev,$timestamp);
+$res = scalar run(
+ command => [ "git", "--git-dir", $git_dir, "log", '--pretty=format:%h,%ct', '-1', $sha1 ],
+ buffer => \$sha1_abbrev,
+);
+($sha1_abbrev, $timestamp) = split /,/, $sha1_abbrev;
+
+# - And describe output
+my $describe;
+$res = scalar run(
+ command => [ "git", "--git-dir", $git_dir, 'describe', $sha1 ],
+ buffer => \$describe,
+);
+if(!$res) {
+ $describe = "";
+}
+chomp($describe);
+
+# Now create the base snapshot
+run(
+ command => ["git", "--git-dir", $git_dir, "archive",
+ "--format", $format, "--prefix", $prefix,
+ "--output", $output, $sha1],
+);
+
+# And add the .patch file
+my $patch = File::Spec->catfile(dirname($output), "$sha1_abbrev.patch");
+open(my $fh, ">", $patch);
+print $fh join(" ", $branch, isotime($timestamp), $sha1, $describe);
+run(
+ command => ["tar", "-f", $output, '--transform', "s,.*$sha1_abbrev,$prefix,",
+ "--owner=root", "--group=root", "--mode=664", "--append", $patch]
+);
+
+# Done :-)
+
+sub branchcmp {
+ return -1 if ($a eq 'blead');
+ return 1 if ($b eq 'blead');
+ return -1 if ($a =~ /^maint/ && $b !~ /^maint/);
+ return 1 if ($a =~ /^maint/ && $b !~ /^maint/);
+ return $a cmp $b if ($a !~ /^maint/ && $b !~ /^maint/);
+ $a =~ s/maint-([0-9.]+).*/$1/;
+ $b =~ s/maint-([0-9.]+).*/$1/;
+ return version->parse($a) <=> version->parse($b);
+}
+
+sub isotime { strftime "%Y-%m-%d.%H:%M:%S",gmtime(shift||time) }
Something went wrong with that request. Please try again.