From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.2 required=3.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, T_SCC_BODY_TEXT_LINE shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 64DB71F620 for ; Mon, 22 Aug 2022 02:33:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1661135627; bh=0k7Qmv+11+Jl77DU2fS1RPxSkBm7l15IJqECUFKK6I8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Dl1b2J9/vZARJYKXuITxr2/qXgu2kA8/u3LjH4qS5R5GErS0Ges3ojBhl+gPlIaqf Y8IjzAeoH4LkkxfwcMHb7j3XjemsDJtqcWX3OX19f7Bg9GsSJ7n7+KXLoK2MRSxJLG C3xPKC9A+sP9gIqGOFDqdoCT+SkqW1lK68WtxhfI= From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 7/7] viewvcs: start improving display of git commits Date: Mon, 22 Aug 2022 02:33:46 +0000 Message-Id: <20220822023346.938859-8-e@80x24.org> In-Reply-To: <20220822023346.938859-1-e@80x24.org> References: <20220822023346.938859-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: For non-merge git commits, we already have ViewDiff for displaying patch emails, we can reuse it to display non-merge git commits. AFAIK, this is the first web-based git repository viewer to display the output of "git-patch-id --stable". It currently fills in the search form box with "patchid:", but maybe it'll do more than that. More work will be done to support bidirectional mapping of commits to emails in the future. --- lib/PublicInbox/ViewVCS.pm | 99 +++++++++++++++++++++++++++++++++++- lib/PublicInbox/WwwStream.pm | 9 ++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/lib/PublicInbox/ViewVCS.pm b/lib/PublicInbox/ViewVCS.pm index 94656ad3..96883f6c 100644 --- a/lib/PublicInbox/ViewVCS.pm +++ b/lib/PublicInbox/ViewVCS.pm @@ -2,7 +2,6 @@ # License: AGPL-3.0+ # show any VCS object, similar to "git show" -# FIXME: we only show blobs for now # # This can use a "solver" to reconstruct blobs based on git # patches (with abbreviated OIDs in the header). However, the @@ -16,10 +15,12 @@ package PublicInbox::ViewVCS; use strict; use v5.10.1; +use File::Temp 0.19 (); # newdir use PublicInbox::SolverGit; use PublicInbox::WwwStream qw(html_oneshot); use PublicInbox::Linkify; use PublicInbox::Tmpfile; +use PublicInbox::ViewDiff qw(flush_diff); use PublicInbox::Hval qw(ascii_html to_filename); my $hl = eval { require PublicInbox::HlMod; @@ -29,6 +30,8 @@ my $hl = eval { my %QP_MAP = ( A => 'oid_a', a => 'path_a', b => 'path_b' ); our $MAX_SIZE = 1024 * 1024; # TODO: configurable my $BIN_DETECT = 8000; # same as git +my $SHOW_FMT = '--pretty=format:'.join('%n', '%H', '%T', '%P', '%s', + '%an <%ae>%x09%ai', '%cn <%ce>%x09%ci', '%b%x00'); sub html_page ($$$) { my ($ctx, $code, $strref) = @_; @@ -88,6 +91,99 @@ sub show_other_result ($$) { html_page($ctx, 200, $bref); } +sub show_commit_result ($$) { + my ($bref, $ctx) = @_; + my ($qsp_err, $logref, $tmp) = @$ctx{qw(-qsp_err -logref -tmp)}; + if ($qsp_err) { + $$logref .= "git show/patch-id error:$qsp_err"; + return html_page($ctx, 500, $logref); + } + my $upfx = $ctx->{-upfx} = '../../'; # from "/$INBOX/$OID/s/" + my $patchid = (split(/ /, $$bref))[0]; # ignore commit + if (defined $patchid) { + $ctx->{-q_value_html} = "patchid:$patchid"; + $patchid = "\n patchid $patchid"; + } else { + $patchid = ''; + } + my $l = $ctx->{-linkify} = PublicInbox::Linkify->new; + open my $fh, '<:utf8', "$tmp/h" or die "open $tmp/h: $!"; + chop(my $buf = do { local $/ = "\0"; <$fh> }); + my ($H, $T, $P, $s, $au, $co, $bdy) = split(/\n/, $buf, 7); + chomp $bdy; + # try to keep author and committer dates lined up + my $x = length($au) - length($co); + if ($x > 0) { + $x = ' ' x $x; + $co =~ s/\t/$x\t/; + } elsif ($x < 0) { + $x = ' ' x (-$x); + $au =~ s/\t/$x\t/; + } + $_ = ascii_html($_) for ($au, $co); + $_ = $l->to_html($_) for ($s, $bdy); + $ctx->{-title_html} = $s; + my @p = split(/ /, $P); + if (@p == 1) { + $P = qq(\n parent $P); + } elsif (@p > 1) { + $P = qq(\n parents $p[0]\n); + shift @p; + $P .= qq( $_\n) for @p; + chop $P; + } else { # root commit + $P = ' (root commit)'; + } + PublicInbox::WwwStream::html_init($ctx); + $ctx->zmore(< commit $H$P + tree $T + author $au +committer $co$patchid + +$s\n +EOM + $ctx->zmore($bdy); + open $fh, '<', "$tmp/p" or die "open $tmp/p: $!"; + if (-s $fh > $MAX_SIZE) { + $ctx->zmore("---\n patch is too large to show\n"); + } else { # prepare flush_diff: + $buf = ''; + $ctx->{obuf} = \$buf; + $ctx->{-apfx} = $ctx->{-spfx} = $upfx; + $ctx->{-anchors} = {}; + $bdy = ''; + read($fh, $bdy, -s _); + $bdy =~ s/\r?\n/\n/gs; + flush_diff($ctx, \$bdy); + $ctx->zmore($buf); + } + $x = $ctx->zflush($ctx->_html_end); + my $res_hdr = delete $ctx->{-res_hdr}; + push @$res_hdr, 'Content-Length', length($x); + delete($ctx->{env}->{'qspawn.wcb'})->([200, $res_hdr, [$x]]); +} + +sub show_commit ($$$$) { + my ($ctx, $res, $logref, $fn) = @_; + my ($git, $oid) = @$res; + # patch-id needs two passes, and we use the initial show to ensure + # a patch embedded inside the commit message body doesn't get fed + # to patch-id: + my $cmd = [ '/bin/sh', '-c', + "git show '$SHOW_FMT' -z --no-notes --no-patch $oid >h && ". + "git show --pretty=format:%n -M --stat -p $oid >p && ". + "git patch-id --stable $git->{git_dir} }; + my $tmp = File::Temp->newdir("show-$oid-XXXX", TMPDIR => 1); + my $qsp = PublicInbox::Qspawn->new($cmd, $xenv, { -C => "$tmp" }); + $qsp->{qsp_err} = \($ctx->{-qsp_err} = ''); + $ctx->{-logref} = $logref; + $ctx->{-tmp} = $tmp; + $ctx->{env}->{'qspawn.wcb'} = delete $ctx->{-wcb}; + $qsp->psgi_qx($ctx->{env}, undef, \&show_commit_result, $ctx); +} + sub show_other ($$$$) { my ($ctx, $res, $logref, $fn) = @_; my ($git, $oid, $type, $size) = @$res; @@ -122,6 +218,7 @@ sub solve_result { ref($res) eq 'ARRAY' or return html_page($ctx, 500, \$log); my ($git, $oid, $type, $size, $di) = @$res; + return show_commit($ctx, $res, \$log, $fn) if $type eq 'commit'; return show_other($ctx, $res, \$log, $fn) if $type ne 'blob'; my $path = to_filename($di->{path_b} // $hints->{path_b} // 'blob'); my $raw_link = "(raw)"; diff --git a/lib/PublicInbox/WwwStream.pm b/lib/PublicInbox/WwwStream.pm index 0416db0b..ab006c40 100644 --- a/lib/PublicInbox/WwwStream.pm +++ b/lib/PublicInbox/WwwStream.pm @@ -201,4 +201,13 @@ sub aresponse { $ctx->psgi_response($code, $res_hdr); } +sub html_init { + my ($ctx) = @_; + $ctx->{base_url} = base_url($ctx); + my $h = $ctx->{-res_hdr} = ['Content-Type', 'text/html; charset=UTF-8']; + $ctx->{gz} = PublicInbox::GzipFilter::gz_or_noop($h, $ctx->{env}); + bless $ctx, __PACKAGE__; + $ctx->zmore(html_top($ctx)); +} + 1;