about summary refs log tree commit homepage
path: root/lib/PublicInbox/RepoGitDiff.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2017-02-09 01:37:03 +0000
committerEric Wong <e@80x24.org>2017-02-09 01:37:03 +0000
commitd9563ea5516e8e786debf223e10ec11695aee9d7 (patch)
treea0842b1ee0953bc8e65d21d5d96432f41973adb7 /lib/PublicInbox/RepoGitDiff.pm
parentfb9ed5324ec7de9420956840ba9a6585b81e8231 (diff)
downloadpublic-inbox-d9563ea5516e8e786debf223e10ec11695aee9d7.tar.gz
We'll still be keeping "repobrowse" for the public API
for use with .psgi files, but shortening the name means
less typing and we may have command-line tools, too.
Diffstat (limited to 'lib/PublicInbox/RepoGitDiff.pm')
-rw-r--r--lib/PublicInbox/RepoGitDiff.pm73
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/PublicInbox/RepoGitDiff.pm b/lib/PublicInbox/RepoGitDiff.pm
new file mode 100644
index 00000000..bb71e738
--- /dev/null
+++ b/lib/PublicInbox/RepoGitDiff.pm
@@ -0,0 +1,73 @@
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# shows the /diff endpoint for git repositories for cgit compatibility
+# usage: /repo.git/diff?id=COMMIT_ID&id2=COMMIT_ID2
+#
+# We probably will not link to this outright because it's expensive,
+# but exists to preserve URL compatibility with cgit.
+package PublicInbox::RepoGitDiff;
+use strict;
+use warnings;
+use base qw(PublicInbox::RepoBase);
+use PublicInbox::Hval qw(utf8_html);
+use PublicInbox::RepoGitDiffCommon;
+use PublicInbox::Qspawn;
+
+sub git_diff_sed ($$) {
+        my ($self, $req) = @_;
+        git_diff_sed_init($req);
+        $req->{dstate} = DSTATE_STAT;
+        # this filters for $fh->write or $body->getline (see Qspawn)
+        sub {
+                my $dst = delete $req->{dhtml} || '';
+                if (defined $_[0]) { # $_[0] == scalar buffer
+                        $req->{dbuf} .= $_[0];
+                        git_diff_sed_run(\$dst, $req);
+                } else { # undef means EOF from "git show", flush the last bit
+                        git_diff_sed_close(\$dst, $req);
+                        $dst .= '</pre></body></html>';
+                }
+                $dst;
+        }
+}
+
+sub call_git_diff {
+        my ($self, $req) = @_;
+        my $env = $req->{env};
+        my $q = PublicInbox::RepoGitQuery->new($env);
+        my $id = $q->{id};
+        my $id2 = $q->{id2};
+
+        my $git = $req->{repo_info}->{git};
+        my $cmd = $git->cmd(qw(diff-tree -z --numstat -p --encoding=UTF-8
+                                --no-color -M -B -D -r), $id2, $id, '--');
+        my $expath = $req->{expath};
+        push @$cmd, $expath if $expath ne '';
+        my $o = { nofollow => 1, noindex => 1 };
+        my $ex = $expath eq '' ? '' : " $expath";
+        $req->{dhtml} = $self->html_start($req, 'diff', $o). "\n\n".
+                                utf8_html("git diff-tree -r -M -B -D ".
+                                "$id2 $id --$ex"). "\n\n";
+        $req->{p} = [ $id2 ];
+        $req->{h} = $id;
+        my $rdr = { 2 => $git->err_begin };
+        my $qsp = PublicInbox::Qspawn->new($cmd, undef, $rdr);
+        # $env->{'qspawn.quiet'} = 1;
+        $qsp->psgi_return($env, undef, sub { # parse header
+                my ($r) = @_;
+                if (!defined $r) {
+                        [ 500, [ 'Content-Type', 'text/html' ], [ $git->err ]];
+                } elsif ($r == 0) {
+                        [ 200, [ 'Content-Type', 'text/html' ], [
+                                delete($req->{dhtml}).
+                                'No differences</pre></body></html>' ]
+                        ]
+                } else {
+                        $env->{'qspawn.filter'} = git_diff_sed($self, $req);
+                        [ 200, [ 'Content-Type', 'text/html' ] ];
+                }
+        });
+}
+
+1;