# Copyright (C) 2015 all contributors
# License: AGPL-3.0+
# shows the /commit/ endpoint for git repositories
#
# anchors used:
# D - diffstat
# P - parents
# ...and various filenames from to_attr
# The 'D' and 'P' anchors may conflict with odd filenames, but we won't
# punish the common case with extra bytes if somebody uses 'D' or 'P'
# in filenames.
package PublicInbox::RepoGitCommit;
use strict;
use warnings;
use base qw(PublicInbox::RepoBase);
use PublicInbox::Hval qw(utf8_html to_attr);
use PublicInbox::RepoGit qw(git_unquote git_commit_title);
use PublicInbox::RepoGitDiffCommon;
use PublicInbox::Qspawn;
use constant {
GIT_FMT => '--pretty=format:'.join('%n',
'%H', '%s', '%an <%ae>', '%ai', '%cn <%ce>', '%ci',
'%t', '%p', '%D', '%b%x00'),
CC_EMPTY => " This is a merge, and the combined diff is empty.\n",
CC_MERGE => " This is a merge, showing combined diff:\n\n"
};
sub commit_header {
my ($self, $req) = @_;
my ($H, $s, $au, $ad, $cu, $cd, $t, $p, $D, $rest) =
split("\n", $req->{dbuf}, 10);
$s = utf8_html($s);
$au = utf8_html($au);
$cu = utf8_html($cu);
my @p = split(' ', $p);
my $rel = $req->{relcmd};
my $x = $self->html_start($req, $s) . "\n" .
qq( commit $H (patch)\n) .
qq( tree $t);
my $git = $req->{-repo}->{git};
# extra show path information, if any
my $extra = $req->{extra};
my $path = '';
if (@$extra) {
my @t;
my $ep;
$x .= ' -- ';
$x .= join('/', map {
push @t, $_;
my $e = PublicInbox::Hval->utf8($_, join('/', @t));
$ep = $e->as_path;
my $eh = $e->as_html;
$ep = "${rel}src/$ep/$H";
qq($eh);
} @$extra);
$path = "/$ep";
}
$x .= "\n author $au\t$ad\ncommitter $cu\t$cd\n";
my $np = scalar @p;
if ($np == 1) {
my $p = $p[0];
$x .= git_parent_line(' parent', $p, $git, $rel);
} elsif ($np > 1) {
$req->{mhelp} = CC_MERGE;
my @common = ($git, $rel);
my @t = @p;
my $p = shift @t;
$x .= git_parent_line(' parents', $p, @common);
foreach $p (@t) {
$x .= git_parent_line(' ', $p, @common);
}
}
$x .= "\n";
$x .= $s;
$x .= "\n\n";
my $bx00;
# FIXME: deal with excessively long commit message bodies
($bx00, $req->{dbuf}) = split("\0", $rest, 2);
$req->{anchors} = {};
$req->{H} = $H;
$req->{p} = \@p;
$x .= utf8_html($bx00) . "---\n";
}
sub git_commit_sed ($$) {
my ($self, $req) = @_;
git_diff_sed_init($req);
my $dbuf = \($req->{dbuf});
# this filters for $fh->write or $body->getline (see Qspawn)
sub {
my $dst = '';
if (defined $_[0]) { # $_[0] == scalar buffer
$$dbuf .= $_[0];
if ($req->{dstate} == DSTATE_INIT) {
return $dst if index($$dbuf, "\0") < 0;
$req->{dstate} = DSTATE_STAT;
$dst .= commit_header($self, $req);
}
git_diff_sed_run(\$dst, $req);
} else { # undef means EOF from "git show", flush the last bit
git_diff_sed_close(\$dst, $req);
$dst .= CC_EMPTY if delete $req->{mhelp};
show_unchanged(\$dst, $req);
$dst .= '