about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--lib/PublicInbox/RepobrowseGitCommit.pm51
-rw-r--r--t/repobrowse_git_commit.t8
2 files changed, 43 insertions, 16 deletions
diff --git a/lib/PublicInbox/RepobrowseGitCommit.pm b/lib/PublicInbox/RepobrowseGitCommit.pm
index edc27717..156e3e22 100644
--- a/lib/PublicInbox/RepobrowseGitCommit.pm
+++ b/lib/PublicInbox/RepobrowseGitCommit.pm
@@ -23,7 +23,12 @@ use constant GIT_FMT => '--pretty=format:'.join('%n',
         '%t', '%p', '%D', '%b%x00');
 
 sub git_commit_stream {
-        my ($self, $req, $q, $H, $log, $fh) = @_;
+        my ($self, $req) = @_;
+        my $log = $req->{log};
+        my $H = <$log>;
+        defined $H or return git_commit_404($req);
+        my $fh = delete($req->{res})->([200, ['Content-Type'=>'text/html']]);
+        $req->{fh} = $fh;
         chomp(my $h = <$log>); # abbreviated commit
         my $l;
         chomp(my $s = utf8_html($l = <$log>)); # subject
@@ -38,6 +43,7 @@ sub git_commit_stream {
         my $git = $req->{repo_info}->{git};
 
         my $rel = $req->{relcmd};
+        my $q = $req->{'q'};
         my $qs = $q->qs(id => $h);
         chomp $H;
         my $x = $self->html_start($req, $s) . "\n" .
@@ -146,34 +152,47 @@ sub call_git_commit {
         }
 
         my $git = $req->{repo_info}->{git};
-        my @cmd = (qw(show -z --numstat -p --encoding=UTF-8
-                        --no-notes --no-color -c), $git->abbrev);
-
-        my $log = $git->popen(@cmd, GIT_FMT, $id, '--');
-        my $H = <$log>;
-
-        # maybe the path didn't exist, yet, zip them back up
-        return git_commit_404($req, $q) unless defined $H;
+        my $cmd = [ qw(show -z --numstat -p --encoding=UTF-8
+                        --no-notes --no-color -c),
+                        $git->abbrev, GIT_FMT, $id, '--' ];
+        $req->{log} = $git->popen($cmd, undef, { 2 => $git->err_begin });
+        $req->{end} = sub {
+                $req->{cb} = $req->{end} = undef;
+                if (my $fh = delete $req->{fh}) {
+                        $fh->close;
+                } elsif (my $res = delete $req->{res}) {
+                        $res->(r(500));
+                }
+                if (my $log = delete $req->{log}) {
+                        $log->close; # _may_ be Danga::Socket::close
+                }
+                # zero the error file for now, be careful about printing
+                # $id to psgi.errors w/o sanitizing...
+                $git->err;
+        };
+        $req->{'q'} = $q;
+        $req->{cb} = sub { # read git-show output and stream to client
+                git_commit_stream($self, $req);
+                $req->{end}->();
+        };
         sub {
-                my ($res) = @_; # Plack callback
-                my $fh = $res->([200, ['Content-Type'=>'text/html']]);
-                git_commit_stream($self, $req, $q, $H, $log, $fh);
-                $fh->close;
+                $req->{res} = $_[0];
+                $req->{cb}->();
         }
 }
 
 sub git_commit_404 {
-        my ($req, $q) = @_;
+        my ($req) = @_;
         my $x = 'Missing commit or path';
         my $pfx = "$req->{relcmd}commit";
 
         my $try = 'try';
         $x = "<html><head><title>$x</title></head><body><pre><b>$x</b>\n\n";
-        my $qs = $q->qs(id => '');
+        my $qs = $req->{'q'}->qs(id => '');
         $x .= "<a\nhref=\"$pfx$qs\">$try the latest commit in HEAD</a>\n";
         $x .= '</pre></body>';
 
-        [ 404, ['Content-Type'=>'text/html'], [ $x ] ];
+        delete($req->{res})->([404, ['Content-Type'=>'text/html'], [ $x ]]);
 }
 
 sub git_show_diffstat {
diff --git a/t/repobrowse_git_commit.t b/t/repobrowse_git_commit.t
index f13cd909..969a0b5e 100644
--- a/t/repobrowse_git_commit.t
+++ b/t/repobrowse_git_commit.t
@@ -18,6 +18,14 @@ test_psgi($test->{app}, sub {
         is($res->code, 301, 'got 301 with query string');
         is($res->header('Location'), "$req$q#path:to:something",
                 'redirected to anchor from path with query');
+
+        $res = $cb->(GET($req));
+        is($res->code, 200, 'got proper 200 response for default');
+        my $body = dechunk($res);
+        like($body, qr!</html>\z!, 'response body finished');
+
+        $res = $cb->(GET($req.$q));
+        is($res->code, 404, 'got 404 response for default');
 });
 
 done_testing();