about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-12-26 09:44:44 +0000
committerEric Wong <e@80x24.org>2016-12-26 10:06:14 +0000
commit65ed2d84d4d87c7c94dee9e880f694a8607a4d1c (patch)
tree28060aa39d39296bda9a284074a80449c669e683
parent659cdc6edac406aba897f1986f063d3b7f45313b (diff)
downloadpublic-inbox-65ed2d84d4d87c7c94dee9e880f694a8607a4d1c.tar.gz
This is expensive, so we will utilize the qspawn system
to prevent excessive overhead.
-rw-r--r--lib/PublicInbox/RepobrowseGitSnapshot.pm64
1 files changed, 12 insertions, 52 deletions
diff --git a/lib/PublicInbox/RepobrowseGitSnapshot.pm b/lib/PublicInbox/RepobrowseGitSnapshot.pm
index 4783e150..9e3ff83e 100644
--- a/lib/PublicInbox/RepobrowseGitSnapshot.pm
+++ b/lib/PublicInbox/RepobrowseGitSnapshot.pm
@@ -10,6 +10,7 @@ use strict;
 use warnings;
 use base qw(PublicInbox::RepobrowseBase);
 use PublicInbox::Git;
+use PublicInbox::Qspawn;
 our $SUFFIX;
 BEGIN {
         # as described in git-archive(1), users may add support for
@@ -73,58 +74,17 @@ sub call_git_snapshot ($$) { # invoked by PublicInbox::RepobrowseBase::call
         return $self->r(404) if (!defined $tree || $tree eq '');
 
         my $pfx = "$repo_info->{snapshot_pfx}-$ref/";
-        my @cmd = ('archive', "--prefix=$pfx", "--format=$fmt", $tree);
-        $req->{rpipe} = $git->popen(\@cmd, undef, { 2 => $git->err_begin });
-
-        my $env = $req->{env};
-        my $vin;
-        my $end = sub {
-                my ($n) = @_;
-                if (my $fh = delete $req->{fh}) {
-                        $fh->close;
-                } elsif (my $res = delete $req->{res}) {
-                        $res->($self->r(500));
-                }
-                if (my $rpipe = delete $req->{rpipe}) {
-                        $rpipe->close; # _may_ be Danga::Socket::close
-                }
-        };
-        my $fail = sub {
-                if ($!{EAGAIN} || $!{EINTR}) {
-                        select($vin, undef, undef, undef) if $vin;
-                        # $vin is undef on async, so this is a noop
-                        return;
-                }
-                my $e = $!;
-                $end->();
-                my $err = $env->{'psgi.errors'};
-                $err->print("git archive ($git->{git_dir}): $e\n");
-        };
-        my $cb = sub {
-                my $n = $req->{rpipe}->sysread(my $buf, 65536);
-                return $fail->() unless defined $n;
-                return $end->() if $n == 0;
-                if (my $res = delete $req->{res}) {
-                        my $h = [ 'Content-Type',
-                                $FMT_TYPES{$fmt} || 'application/octet-stream',
-                                'Content-Disposition',
-                                qq(inline; filename="$orig_fn"),
-                                'ETag', qq("$tree") ];
-                        $req->{fh} = $res->([200, $h]);
-                }
-                $req->{fh}->write($buf);
-        };
-        if (my $async = $env->{'pi-httpd.async'}) {
-                $req->{rpipe} = $async->($req->{rpipe}, $cb);
-                sub { $req->{res} = $_[0] } # let Danga::Socket handle the rest.
-        } else { # synchronous loop for other PSGI servers
-                $vin = '';
-                vec($vin, fileno($req->{rpipe}), 1) = 1;
-                sub {
-                        $req->{res} = $_[0]; # Plack response callback
-                        while ($req->{rpipe}) { $cb->() }
-                }
-        }
+        my $cmd = [ 'git', "--git-dir=$git->{git_dir}", 'archive',
+                        "--prefix=$pfx", "--format=$fmt", $tree ];
+        my $qsp = PublicInbox::Qspawn->new($cmd);
+        $qsp->psgi_return($req->{env}, undef, sub {
+                my $r = $_[0];
+                return $self->r(500) unless $r;
+                [ 200, [ 'Content-Type', $FMT_TYPES{$fmt} ||
+                                        'application/octet-stream',
+                        'Content-Disposition', qq(inline; filename="$orig_fn"),
+                        'ETag', qq("$tree") ] ];
+        });
 }
 
 1;