public-inbox.git  about / heads / tags
an "archives first" approach to mailing lists
blob 35bcb2d9147025587283e0b77dbc68a174174df5 2141 bytes (raw)
$ git show repobrowse:lib/PublicInbox/RepoGitDiff.pm	# shows this blob on the CLI

 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;

git clone https://public-inbox.org/public-inbox.git
git clone http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git