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.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 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 5F0501FC73 for ; Wed, 25 Dec 2019 07:51:10 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 29/30] solvergit: allow passing arg to user-supplied callback Date: Wed, 25 Dec 2019 07:51:03 +0000 Message-Id: <20191225075104.22184-30-e@80x24.org> In-Reply-To: <20191225075104.22184-1-e@80x24.org> References: <20191225075104.22184-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: This allows us to get rid of the requirement to capture on-stack variables with an anonymous sub, as illustrated with the update to viewvcs to take advantage of this. --- lib/PublicInbox/SolverGit.pm | 28 ++++++++++++++++------------ lib/PublicInbox/ViewVCS.pm | 19 ++++++++++--------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm index 6dfa20f7..6b6586e9 100644 --- a/lib/PublicInbox/SolverGit.pm +++ b/lib/PublicInbox/SolverGit.pm @@ -55,11 +55,16 @@ sub dbg ($$) { print { $_[0]->{out} } $_[1], "\n" or ERR($_[0], "print(dbg): $!"); } +sub done_err ($$) { + my ($self, $err) = @_; + my $ucb = delete($self->{user_cb}) or return; + $ucb->($err, $self->{uarg}); +} + sub ERR ($$) { my ($self, $err) = @_; print { $self->{out} } $err, "\n"; - my $ucb = delete($self->{user_cb}); - eval { $ucb->($err) } if $ucb; + eval { done_err($self, $err) }; die $err; } @@ -313,22 +318,21 @@ sub extract_old_mode ($) { sub do_finish ($$) { my ($self, $user_cb) = @_; - my $found = $self->{found}; - my $oid_want = $self->{oid_want}; + my ($found, $oid_want, $uarg) = @$self{qw(found oid_want uarg)}; if (my $exists = $found->{$oid_want}) { - return $user_cb->($exists); + return $user_cb->($exists, $uarg); } # let git disambiguate if oid_want was too short, # but long enough to be unambiguous: my $tmp_git = $self->{tmp_git}; if (my @res = $tmp_git->check($oid_want)) { - return $user_cb->($found->{$res[0]}); + return $user_cb->($found->{$res[0]}, $uarg); } if (my $err = $tmp_git->last_check_err) { dbg($self, $err); } - $user_cb->(undef); + $user_cb->(undef, $uarg); } sub do_step ($) { @@ -362,8 +366,7 @@ sub do_step ($) { if ($err) { $err =~ s/^\s*Exception:\s*//; # bad word to show users :P dbg($self, "E: $err"); - my $ucb = delete($self->{user_cb}); - eval { $ucb->($err) } if $ucb; + eval { done_err($self, $err) }; } } @@ -524,7 +527,7 @@ sub resolve_patch ($$) { join("\n", $found_git->pub_urls($self->{psgi_env}))); if ($cur_want eq $self->{oid_want} || $type ne 'blob') { - eval { delete($self->{user_cb})->($existing) }; + eval { done_err($self, $existing) }; die "E: $@" if $@; return; } @@ -569,11 +572,12 @@ sub resolve_patch ($$) { # this API is designed to avoid creating self-referential structures; # so user_cb never references the SolverGit object sub new { - my ($class, $ibx, $user_cb) = @_; + my ($class, $ibx, $user_cb, $uarg) = @_; bless { gits => $ibx->{-repo_objs}, user_cb => $user_cb, + uarg => $uarg, # -cur_di, -qsp, -msg => temporary fields for Qspawn callbacks # TODO: config option for searching related inboxes @@ -591,7 +595,7 @@ sub solve ($$$$$) { # should we even get here? Probably not, but somebody # could be manually typing URLs: - return (delete $self->{user_cb})->(undef) if $oid_want =~ /\A0+\z/; + return done_err($self, undef) if $oid_want =~ /\A0+\z/; $self->{oid_want} = $oid_want; $self->{out} = $out; diff --git a/lib/PublicInbox/ViewVCS.pm b/lib/PublicInbox/ViewVCS.pm index a6dbb9a9..ead8c2b4 100644 --- a/lib/PublicInbox/ViewVCS.pm +++ b/lib/PublicInbox/ViewVCS.pm @@ -112,8 +112,10 @@ sub show_other ($$$$) { $qsp->psgi_qx($env, undef, \&show_other_result, $ctx); } +# user_cb for SolverGit, called as: user_cb->($result_or_error, $uarg) sub solve_result { - my ($ctx, $res, $log, $hints, $fn) = @_; + my ($res, $ctx) = @_; + my ($log, $hints, $fn) = delete @$ctx{qw(log hints fn)}; unless (seek($log, 0, 0)) { $ctx->{env}->{'psgi.errors'}->print("seek(log): $!\n"); @@ -192,21 +194,20 @@ sub solve_result { sub show ($$;$) { my ($ctx, $oid_b, $fn) = @_; my $qp = $ctx->{qp}; - my $hints = {}; + my $hints = $ctx->{hints} = {}; while (my ($from, $to) = each %QP_MAP) { defined(my $v = $qp->{$from}) or next; $hints->{$to} = $v; } - my $log = tmpfile("solve.$oid_b"); - my $solver = PublicInbox::SolverGit->new($ctx->{-inbox}, sub { - solve_result($ctx, $_[0], $log, $hints, $fn); - }); - - # PSGI server will call this and give us a callback + $ctx->{'log'} = tmpfile("solve.$oid_b"); + $ctx->{fn} = $fn; + my $solver = PublicInbox::SolverGit->new($ctx->{-inbox}, + \&solve_result, $ctx); + # PSGI server will call this immediately and give us a callback (-wcb) sub { $ctx->{-wcb} = $_[0]; # HTTP write callback - $solver->solve($ctx->{env}, $log, $oid_b, $hints); + $solver->solve($ctx->{env}, $ctx->{log}, $oid_b, $hints); }; }