-# 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
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
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";
}
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
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");
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) = @_;
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:
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};
}
$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;