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 8700D1F61D for ; Mon, 29 Aug 2022 09:26:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1661765208; bh=8tu0KrVQfHVVEDMEn8t5wWLLN8qRQqg9pi+lYhEQ6as=; h=From:To:Subject:Date:In-Reply-To:References:From; b=49qRCs3fbZ5NS7FJ6DgrRIEe2FjQLG3A4ZUH/RhuJRl3lwabXkV3C2SmabuP3ZCSF RF6Tlv01o1rCOPGw27hpUDjx4OTENpsdtlmVaKnARCljNYAOSlDrmJ+Ewl/kM5gQyV Mc3vGsuQwjMpfwjWAqNnDMGNljJSh/b5OaSnWdRg= From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 06/18] viewvcs: add patch download link for single-parent commits Date: Mon, 29 Aug 2022 09:26:35 +0000 Message-Id: <20220829092647.1512215-7-e@80x24.org> In-Reply-To: <20220829092647.1512215-1-e@80x24.org> References: <20220829092647.1512215-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: The email signature field will echo the format-patch arguments used so it can be used as hint for users learning to more of the git CLI. --- lib/PublicInbox/ViewVCS.pm | 43 ++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/PublicInbox/ViewVCS.pm b/lib/PublicInbox/ViewVCS.pm index 8fb0844d..84358d0e 100644 --- a/lib/PublicInbox/ViewVCS.pm +++ b/lib/PublicInbox/ViewVCS.pm @@ -23,6 +23,7 @@ use PublicInbox::Linkify; use PublicInbox::Tmpfile; use PublicInbox::ViewDiff qw(flush_diff); use PublicInbox::View; +use PublicInbox::Eml; use Text::Wrap qw(wrap); use PublicInbox::Hval qw(ascii_html to_filename); my $hl = eval { @@ -33,7 +34,7 @@ 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', '%P', '%p', '%H', '%T', '%s', +my $SHOW_FMT = '--pretty=format:'.join('%n', '%P', '%p', '%H', '%T', '%s', '%f', '%an <%ae> %ai', '%cn <%ce> %ci', '%b%x00'); sub html_page ($$;@) { @@ -127,8 +128,8 @@ sub show_commit_start { # ->psgi_qx callback chop(my $buf = do { local $/ = "\0"; <$fh> }); chomp $buf; my ($P, $p); - ($P, $p, @$ctx{qw(cmt_H cmt_T cmt_s cmt_au cmt_co cmt_b)}) - = split(/\n/, $buf, 8); + ($P, $p, @$ctx{qw(cmt_H cmt_T cmt_s cmt_f cmt_au cmt_co cmt_b)}) + = split(/\n/, $buf, 9); return cmt_finalize($ctx) if !$P; @{$ctx->{-cmt_P}} = split(/ /, $P); @{$ctx->{-cmt_p}} = split(/ /, $p); # abbreviated @@ -164,7 +165,8 @@ sub cmt_finalize { my ($P, $p, $pt) = delete @$ctx{qw(-cmt_P -cmt_p -cmt_pt)}; $_ = qq().shift(@$p).' '.shift(@$pt) for @$P; if (@$P == 1) { - $x = qq(\n parent $P->[0]); + $x = qq{ (patch)\n parent $P->[0]}; } elsif (@$P > 1) { $x = qq(\n parents $P->[0]\n); shift @$P; @@ -230,8 +232,41 @@ EOM delete($ctx->{env}->{'qspawn.wcb'})->([200, $res_hdr, [$x]]); } +sub stream_patch_parse_hdr { # {parse_hdr} for Qspawn + my ($r, $bref, $ctx) = @_; + if (!defined $r) { # sysread error + html_page($ctx, 500, dbg_log($ctx)); + } elsif (index($$bref, "\n\n") >= 0) { + my $eml = bless { hdr => $bref }, 'PublicInbox::Eml'; + my $fn = to_filename($eml->header('Subject') // ''); + $fn = substr($fn // 'PATCH-no-subject', 6); # drop "PATCH-" + return [ 200, [ 'Content-Type', 'text/plain; charset=UTF-8', + 'Content-Disposition', + qq(inline; filename=$fn.patch) ] ]; + } elsif ($r == 0) { + my $log = dbg_log($ctx); + warn "premature EOF on $ctx->{patch_oid} $log"; + return html_page($ctx, 500, $log); + } else { + undef; # bref keeps growing until "\n\n" + } +} + +sub show_patch ($$) { + my ($ctx, $res) = @_; + my ($git, $oid) = @$res; + my @cmd = ('git', "--git-dir=$git->{git_dir}", + qw(format-patch -1 --stdout -C), + "--signature=git format-patch -1 --stdout -C $oid", $oid); + my $qsp = PublicInbox::Qspawn->new(\@cmd); + $ctx->{env}->{'qspawn.wcb'} = delete $ctx->{-wcb}; + $ctx->{patch_oid} = $oid; + $qsp->psgi_return($ctx->{env}, undef, \&stream_patch_parse_hdr, $ctx); +} + sub show_commit ($$) { my ($ctx, $res) = @_; + return show_patch($ctx, $res) if ($ctx->{fn} // '') =~ /\.patch\z/; 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