]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/SolverGit.pm
update copyrights for 2021
[public-inbox.git] / lib / PublicInbox / SolverGit.pm
index c54d6d5499b6f86ed9e49c166bfbf9bd00dcccc6..1d70975e855b48b08811594987015a28a1c13296 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2019-2020 all contributors <meta@public-inbox.org>
+# Copyright (C) 2019-2021 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 
 # "Solve" blobs which don't exist in git code repositories by
@@ -16,6 +16,8 @@ use PublicInbox::Git qw(git_unquote git_quote);
 use PublicInbox::MsgIter qw(msg_part_text);
 use PublicInbox::Qspawn;
 use PublicInbox::Tmpfile;
+use PublicInbox::GitAsyncCat;
+use PublicInbox::Eml;
 use URI::Escape qw(uri_escape_utf8);
 
 # POSIX requires _POSIX_ARG_MAX >= 4096, and xargs is required to
@@ -214,7 +216,7 @@ sub filename_query ($) {
 
 sub find_smsgs ($$$) {
        my ($self, $ibx, $want) = @_;
-       my $srch = $ibx->search or return;
+       my $srch = $ibx->isrch or return;
 
        my $post = $want->{oid_b} or die 'BUG: no {oid_b}';
        $post =~ /\A[a-f0-9]+\z/ or die "BUG: oid_b not hex: $post";
@@ -515,16 +517,16 @@ sub di_url ($$) {
 }
 
 sub retry_current {
-       my ($self, $want) = @_;
-       push @{$_[0]->{todo}}, $_[1];
-       goto \&next_step # retry solve_existing
+       my ($self, $want) = @_;
+       push @{$self->{todo}}, $want;
+       next_step($self); # retry solve_existing
 }
 
-sub try_harder {
+sub try_harder ($$) {
        my ($self, $want) = @_;
 
        # do we have more inboxes to try?
-       goto \&retry_current if scalar @{$want->{try_ibxs}};
+       return retry_current($self, $want) if scalar @{$want->{try_ibxs}};
 
        my $cur_want = $want->{oid_b};
        if (length($cur_want) > $OID_MIN) { # maybe a shorter OID will work
@@ -532,7 +534,7 @@ sub try_harder {
                chop($cur_want);
                dbg($self, "retrying $want->{oid_b} as $cur_want");
                $want->{oid_b} = $cur_want;
-               goto \&retry_current; # retry with shorter abbrev
+               return retry_current($self, $want); # retry with shorter abbrev
        }
 
        dbg($self, "could not find $cur_want");
@@ -540,6 +542,46 @@ sub try_harder {
        die "E: $@" if $@;
 }
 
+sub extract_diffs_done {
+       my ($self, $want) = @_;
+
+       delete $want->{try_smsgs};
+       delete $want->{cur_ibx};
+
+       my $diffs = delete $self->{tmp_diffs};
+       if (scalar @$diffs) {
+               unshift @{$self->{patches}}, @$diffs;
+               dbg($self, "found $want->{oid_b} in " .  join(" ||\n\t",
+                       map { di_url($self, $_) } @$diffs));
+
+               # good, we can find a path to the oid we $want, now
+               # lets see if we need to apply more patches:
+               my $di = $diffs->[0];
+               my $src = $di->{oid_a};
+
+               unless ($src =~ /\A0+\z/) {
+                       # we have to solve it using another oid, fine:
+                       my $job = { oid_b => $src, path_b => $di->{path_a} };
+                       push @{$self->{todo}}, $job;
+               }
+               return next_step($self); # onto the next todo item
+       }
+       try_harder($self, $want);
+}
+
+sub extract_diff_async {
+       my ($bref, $oid, $type, $size, $x) = @_;
+       my ($self, $want, $smsg) = @$x;
+       if (defined($oid)) {
+               $smsg->{blob} eq $oid or
+                               ERR($self, "BUG: $smsg->{blob} != $oid");
+               PublicInbox::Eml->new($bref)->each_part(\&extract_diff, $x, 1);
+       }
+
+       scalar(@{$want->{try_smsgs}}) ? retry_current($self, $want)
+                                       : extract_diffs_done($self, $want);
+}
+
 sub resolve_patch ($$) {
        my ($self, $want) = @_;
 
@@ -550,39 +592,20 @@ sub resolve_patch ($$) {
 
        if (my $msgs = $want->{try_smsgs}) {
                my $smsg = shift @$msgs;
-               if (my $eml = $want->{cur_ibx}->smsg_eml($smsg)) {
-                       $eml->each_part(\&extract_diff,
-                                       [ $self, $want, $smsg ], 1);
-               }
-
-               # try the remaining smsgs later
-               goto \&retry_current if scalar @$msgs;
-
-               delete $want->{try_smsgs};
-               delete $want->{cur_ibx};
-
-               my $diffs = delete $self->{tmp_diffs};
-               if (scalar @$diffs) {
-                       unshift @{$self->{patches}}, @$diffs;
-                       dbg($self, "found $cur_want in " .  join(" ||\n\t",
-                               map { di_url($self, $_) } @$diffs));
-
-                       # good, we can find a path to the oid we $want, now
-                       # lets see if we need to apply more patches:
-                       my $di = $diffs->[0];
-                       my $src = $di->{oid_a};
-
-                       unless ($src =~ /\A0+\z/) {
-                               # we have to solve it using another oid, fine:
-                               my $job = {
-                                       oid_b => $src,
-                                       path_b => $di->{path_a},
-                               };
-                               push @{$self->{todo}}, $job;
+               if ($self->{psgi_env}->{'pi-httpd.async'}) {
+                       return git_async_cat($want->{cur_ibx}->git,
+                                               $smsg->{blob},
+                                               \&extract_diff_async,
+                                               [$self, $want, $smsg]);
+               } else {
+                       if (my $eml = $want->{cur_ibx}->smsg_eml($smsg)) {
+                               $eml->each_part(\&extract_diff,
+                                               [ $self, $want, $smsg ], 1);
                        }
-                       goto \&next_step; # onto the next todo item
                }
-               goto \&try_harder;
+
+               return scalar(@$msgs) ? retry_current($self, $want)
+                                       : extract_diffs_done($self, $want);
        }
 
        # see if we can find the blob in an existing git repo:
@@ -603,9 +626,9 @@ sub resolve_patch ($$) {
                        return;
                }
                mark_found($self, $cur_want, $existing);
-               goto \&next_step; # onto patch application
+               return next_step($self); # onto patch application
        } elsif ($existing > 0) {
-               goto \&retry_current;
+               return retry_current($self, $want);
        } else { # $existing == 0: we may retry if inbox scan (below) fails
                delete $want->{try_gits};
        }
@@ -617,9 +640,9 @@ sub resolve_patch ($$) {
                $want->{try_smsgs} = $msgs;
                $want->{cur_ibx} = $ibx;
                $self->{tmp_diffs} = [];
-               goto \&retry_current;
+               return retry_current($self, $want);
        }
-       goto \&try_harder;
+       try_harder($self, $want);
 }
 
 # this API is designed to avoid creating self-referential structures;