]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
repobrowse: git commit is more callback driven
authorEric Wong <e@80x24.org>
Sun, 28 Feb 2016 03:35:07 +0000 (03:35 +0000)
committerEric Wong <e@80x24.org>
Tue, 5 Apr 2016 18:58:27 +0000 (18:58 +0000)
We'll be moving to Danga::Socket for giant diff generation in
future commits.  So this is a step towards being more
callback-driven...

lib/PublicInbox/RepobrowseGitCommit.pm
t/repobrowse_git_commit.t

index edc277176f66c043f5584789e51c7f2aafc2485b..156e3e22236ea60f33b3d6a1eca5453c0fcc0c2a 100644 (file)
@@ -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 {
index f13cd909e5b0933240759c765ab878329342a1e3..969a0b5e82cdccf5849b1f10d6113822b6f05776 100644 (file)
@@ -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();