1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| | # 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/COMMIT_ID_A..COMMIT_ID_B
#
# 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;
}
}
# $REPO/diff/$BEFORE..$AFTER
sub call_git_diff {
my ($self, $req) = @_;
my ($id_a, $id_b) = split(/\.\./, $req->{tip});
my $env = $req->{env};
my $git = $req->{-repo}->{git};
my $cmd = $git->cmd(qw(diff-tree -z --numstat -p --encoding=UTF-8
--no-color -M -B -D -r), "$id_a..$id_b", '--');
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 ".
"$id_a..$id_b --$ex"). "\n\n";
$req->{p} = [ $id_a ];
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) {
$self->rt(500, 'plain', $git->err);
} elsif ($r == 0) {
$self->rt(200, 'html',
delete($req->{dhtml}).
'No differences</pre></body></html>');
} else {
$env->{'qspawn.filter'} = git_diff_sed($self, $req);
$self->rt(200, 'html');
}
});
}
1;
|