diff options
Diffstat (limited to 'lib/PublicInbox/Fetch.pm')
-rw-r--r-- | lib/PublicInbox/Fetch.pm | 74 |
1 files changed, 34 insertions, 40 deletions
diff --git a/lib/PublicInbox/Fetch.pm b/lib/PublicInbox/Fetch.pm index 5261cad1..814d6e8e 100644 --- a/lib/PublicInbox/Fetch.pm +++ b/lib/PublicInbox/Fetch.pm @@ -2,54 +2,53 @@ # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> # Wrapper to "git fetch" remote public-inboxes package PublicInbox::Fetch; -use strict; -use v5.10.1; +use v5.12; use parent qw(PublicInbox::IPC); use URI (); -use PublicInbox::Spawn qw(popen_rd run_die spawn); +use PublicInbox::Spawn qw(popen_rd run_qx run_wait); use PublicInbox::Admin; use PublicInbox::LEI; use PublicInbox::LeiCurl; use PublicInbox::LeiMirror; +use PublicInbox::SHA qw(sha_all); use File::Temp (); -use PublicInbox::Config; -use IO::Compress::Gzip qw(gzip $GzipError); +use PublicInbox::Git qw(git_exe); sub new { bless {}, __PACKAGE__ } -sub fetch_args ($$) { - my ($lei, $opt) = @_; - my @cmd; # (git --git-dir=...) to be added by caller - $opt->{$_} = $lei->{$_} for (0..2); - # we support "-c $key=$val" for arbitrary git config options - # e.g.: git -c http.proxy=socks5h://127.0.0.1:9050 - push(@cmd, '-c', $_) for @{$lei->{opt}->{c} // []}; - push @cmd, 'fetch'; - push @cmd, '-q' if $lei->{opt}->{quiet}; - push @cmd, '-v' if $lei->{opt}->{verbose}; - @cmd; -} - sub remote_url ($$) { my ($lei, $dir) = @_; my $rn = $lei->{opt}->{'try-remote'} // [ 'origin', '_grokmirror' ]; for my $r (@$rn) { - my $cmd = [ qw(git config), "remote.$r.url" ]; - my $fh = popen_rd($cmd, undef, { -C => $dir, 2 => $lei->{2} }); - my $url = <$fh>; - close $fh or next; + my $cmd = [ git_exe, 'config', "remote.$r.url" ]; + my $url = run_qx($cmd, undef, { -C => $dir, 2 => $lei->{2} }); + next if $?; $url =~ s!/*\n!!s; return $url; } undef } +# PSGI mount prefixes and manifest.js.gz prefixes don't always align... +# TODO: remove, handle multi-inbox fetch +sub deduce_epochs ($$) { + my ($m, $path) = @_; + my ($v1_ent, @v2_epochs); + my $path_pfx = ''; + $path =~ s!/+\z!!; + do { + $v1_ent = $m->{$path}; + @v2_epochs = grep(m!\A\Q$path\E/git/[0-9]+\.git\z!, keys %$m); + } while (!defined($v1_ent) && !@v2_epochs && + $path =~ s!\A(/[^/]+)/!/! and $path_pfx .= $1); + ($path_pfx, $v1_ent ? $path : undef, @v2_epochs); +} + sub do_manifest ($$$) { my ($lei, $dir, $ibx_uri) = @_; my $muri = URI->new("$ibx_uri/manifest.js.gz"); my $ft = File::Temp->new(TEMPLATE => 'm-XXXX', UNLINK => 1, DIR => $dir, SUFFIX => '.tmp'); - my $fn = $ft->filename; my $mf = "$dir/manifest.js.gz"; my $m0; # current manifest.js.gz contents if (open my $fh, '<', $mf) { @@ -58,7 +57,7 @@ sub do_manifest ($$$) { }; warn($@) if $@; } - my ($bn) = ($fn =~ m!/([^/]+)\z!); + my ($bn) = ($ft->filename =~ m!/([^/]+)\z!); my $curl_cmd = $lei->{curl}->for_uri($lei, $muri, qw(-R -o), $bn); my $opt = { -C => $dir }; $opt->{$_} = $lei->{$_} for (0..2); @@ -69,7 +68,7 @@ sub do_manifest ($$$) { return; } my $m1 = eval { - PublicInbox::LeiMirror::decode_manifest($ft, $fn, $muri); + PublicInbox::LeiMirror::decode_manifest($ft, $ft, $muri); } or return [ 404, $muri ]; my $mdiff = { %$m1 }; @@ -88,15 +87,14 @@ sub do_manifest ($$$) { return; } my (undef, $v1_path, @v2_epochs) = - PublicInbox::LeiMirror::deduce_epochs($mdiff, $ibx_uri->path); + deduce_epochs($mdiff, $ibx_uri->path); [ 200, $muri, $v1_path, \@v2_epochs, $ft, $mf, $m1 ]; } sub get_fingerprint2 { my ($git_dir) = @_; - require Digest::SHA; - my $rd = popen_rd([qw(git show-ref)], undef, { -C => $git_dir }); - Digest::SHA::sha256(do { local $/; <$rd> }); + my $rd = popen_rd([git_exe, 'show-ref'], undef, { -C => $git_dir }); + sha_all(256, $rd)->digest; # ignore show-ref errors } sub writable_dir ($) { @@ -133,10 +131,10 @@ sub do_fetch { # main entry point $epoch = $nr; } else { warn "W: $edir missing remote.*.url\n"; - my $pid = spawn([qw(git config -l)], undef, - { 1 => $lei->{2}, 2 => $lei->{2} }); - waitpid($pid, 0); - $lei->child_error($?) if $?; + my $o = { -C => $edir }; + $o->{1} = $o->{2} = $lei->{2}; + run_wait([git_exe, qw(config -l)], undef, $o) + and $lei->child_error($?); } } @epochs = grep { !$skip->{$_} } @epochs if $skip; @@ -191,8 +189,8 @@ EOM my $opt = {}; # for spawn if (-d $d) { $fp2->[0] = get_fingerprint2($d) if $fp2; - $cmd = [ @$torsocks, 'git', "--git-dir=$d", - fetch_args($lei, $opt) ]; + $cmd = [ @$torsocks, git_exe, "--git-dir=$d", + PublicInbox::LeiMirror::fetch_args($lei, $opt)]; } else { my $e_uri = $ibx_uri->clone; my ($epath) = ($d =~ m!(/git/[0-9]+\.git)\z!); @@ -218,11 +216,7 @@ EOM } for my $i (@new_epoch) { $mg->epoch_cfg_set($i) } if ($ft) { - if ($mculled) { - my $json = PublicInbox::Config->json->encode($m1); - my $fn = $ft->filename; - gzip(\$json => $fn) or die "gzip: $GzipError"; - } + PublicInbox::LeiMirror::dump_manifest($m1 => $ft) if $mculled; PublicInbox::LeiMirror::ft_rename($ft, $mf, 0666); } $lei->child_error($xit << 8) if $fp2 && $xit; |