X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FGit.pm;h=b2ae75c8ae312042562c35dc568047bc8af49a0e;hb=23af251dd607c4e75ab1e68063f2c885c48cc035;hp=7c08be47bbe4ac74e9f77349cd81046441d697a5;hpb=dd5a4f6497d4a5d94f61186a85516a56d7db8c29;p=public-inbox.git diff --git a/lib/PublicInbox/Git.pm b/lib/PublicInbox/Git.pm index 7c08be47..b2ae75c8 100644 --- a/lib/PublicInbox/Git.pm +++ b/lib/PublicInbox/Git.pm @@ -1,4 +1,4 @@ -# Copyright (C) 2014-2021 all contributors +# Copyright (C) all contributors # License: GPLv2 or later # # Used to read files from a git repository without excessive forking. @@ -19,7 +19,7 @@ use Time::HiRes qw(stat); use PublicInbox::Spawn qw(popen_rd spawn); use PublicInbox::Tmpfile; use IO::Poll qw(POLLIN); -use Carp qw(croak); +use Carp qw(croak carp); use Digest::SHA (); use PublicInbox::DS qw(dwaitpid); our @EXPORT_OK = qw(git_unquote git_quote); @@ -71,7 +71,7 @@ sub new { sub git_path ($$) { my ($self, $path) = @_; - $self->{-git_path}->{$path} ||= do { + $self->{-git_path}->{$path} //= do { local $/ = "\n"; chomp(my $str = $self->qx(qw(rev-parse --git-path), $path)); @@ -94,6 +94,13 @@ sub alternates_changed { $self->{alt_st} = $st; # always a true value } +sub object_format { + $_[0]->{object_format} //= do { + my $fmt = $_[0]->qx(qw(config extensions.objectformat)); + $fmt eq "sha256\n" ? \'sha256' : \undef; + } +} + sub last_check_err { my ($self) = @_; my $fh = $self->{err_c} or return; @@ -114,7 +121,7 @@ sub _bidi_pipe { return; } pipe(my ($out_r, $out_w)) or $self->fail("pipe failed: $!"); - my $rdr = { 0 => $out_r }; + my $rdr = { 0 => $out_r, pgid => 0 }; my $gd = $self->{git_dir}; if ($gd =~ s!/([^/]+/[^/]+)\z!/!) { $rdr->{-C} = $gd; @@ -158,7 +165,8 @@ sub my_read ($$$) { return; # unrecoverable error } } - \substr($$rbuf, 0, $len, ''); + my $no_pad = substr($$rbuf, 0, $len, ''); + \$no_pad; } sub my_readline ($$) { @@ -179,8 +187,8 @@ sub my_readline ($$) { } } -sub cat_async_retry ($$$$$) { - my ($self, $inflight, $req, $cb, $arg) = @_; +sub cat_async_retry ($$) { + my ($self, $inflight) = @_; # {inflight} may be non-existent, but if it isn't we delete it # here to prevent cleanup() from waiting: @@ -189,12 +197,13 @@ sub cat_async_retry ($$$$$) { $self->{inflight} = $inflight; batch_prepare($self); - my $buf = "$req\n"; + my $buf = ''; for (my $i = 0; $i < @$inflight; $i += 3) { $buf .= "$inflight->[$i]\n"; } print { $self->{out} } $buf or $self->fail("write error: $!"); - unshift(@$inflight, \$req, $cb, $arg); # \$ref to indicate retried + my $req = shift @$inflight; + unshift(@$inflight, \$req); # \$ref to indicate retried cat_async_step($self, $inflight); # take one step } @@ -202,7 +211,7 @@ sub cat_async_retry ($$$$$) { sub cat_async_step ($$) { my ($self, $inflight) = @_; die 'BUG: inflight empty or odd' if scalar(@$inflight) < 3; - my ($req, $cb, $arg) = splice(@$inflight, 0, 3); + my ($req, $cb, $arg) = @$inflight[0, 1, 2]; my $rbuf = delete($self->{rbuf}) // \(my $new = ''); my ($bref, $oid, $type, $size); my $head = my_readline($self->{in}, $rbuf); @@ -217,8 +226,7 @@ sub cat_async_step ($$) { # ref($req) indicates it's already been retried # -gcf2 retries internally, so it never hits this path: if (!ref($req) && !$in_cleanup && $self->alternates_changed) { - return cat_async_retry($self, $inflight, - $req, $cb, $arg); + return cat_async_retry($self, $inflight); } $type = 'missing'; $oid = ref($req) ? $$req : $req if $oid eq ''; @@ -227,8 +235,9 @@ sub cat_async_step ($$) { $self->fail("bad result from async cat-file: $head$err"); } $self->{rbuf} = $rbuf if $$rbuf ne ''; + splice(@$inflight, 0, 3); # don't retry $cb on ->fail eval { $cb->($bref, $oid, $type, $size, $arg) }; - async_err($self, "E: cat $req ($oid) $@") if $@; + async_err($self, $req, $oid, $@, 'cat') if $@; } sub cat_async_wait ($) { @@ -259,7 +268,7 @@ sub cat_file { sub check_async_step ($$) { my ($self, $inflight_c) = @_; die 'BUG: inflight empty or odd' if scalar(@$inflight_c) < 3; - my ($req, $cb, $arg) = splice(@$inflight_c, 0, 3); + my ($req, $cb, $arg) = @$inflight_c[0, 1, 2]; my $rbuf = delete($self->{rbuf_c}) // \(my $new = ''); chomp(my $line = my_readline($self->{in_c}, $rbuf)); my ($hex, $type, $size) = split(/ /, $line); @@ -273,8 +282,9 @@ sub check_async_step ($$) { $self->fail(defined($ret) ? 'read EOF' : "read: $!") if !$ret; } $self->{rbuf_c} = $rbuf if $$rbuf ne ''; + splice(@$inflight_c, 0, 3); # don't retry $cb on ->fail eval { $cb->($hex, $type, $size, $arg, $self) }; - async_err($self, "E: check $req ($hex) $@") if $@; + async_err($self, $req, $hex, $@, 'check') if $@; } sub check_async_wait ($) { @@ -339,9 +349,10 @@ sub async_abort ($) { while (scalar(@{$self->{inflight_c} // []}) || scalar(@{$self->{inflight} // []})) { for my $c ('', '_c') { - my $q = $self->{"inflight$c"}; + my $q = $self->{"inflight$c"} or next; while (@$q) { my ($req, $cb, $arg) = splice(@$q, 0, 3); + $req = $$req if ref($req); $req =~ s/ .*//; # drop git_dir for Gcf2Client eval { $cb->(undef, $req, undef, undef, $arg) }; warn "E: (in abort) $req: $@" if $@; @@ -359,10 +370,11 @@ sub fail { # may be augmented in subclasses croak(ref($self) . ' ' . ($self->{git_dir} // '') . ": $msg"); } -sub async_err ($$) { - my ($self, $msg) = @_; - return warn($msg) if $async_warn; - $self->fail($msg); +sub async_err ($$$$$) { + my ($self, $req, $oid, $err, $action) = @_; + $req = $$req if ref($req); # retried + my $msg = "E: $action $req ($oid): $err"; + $async_warn ? carp($msg) : $self->fail($msg); } # $git->popen(qw(show f00)); # or @@ -438,13 +450,8 @@ sub packed_bytes { sub DESTROY { cleanup(@_) } sub local_nick ($) { - my ($self) = @_; - my $ret = '???'; # don't show full FS path, basename should be OK: - if ($self->{git_dir} =~ m!/([^/]+)(?:/*\.git/*)?\z!) { - $ret = "$1.git"; - } - wantarray ? ($ret) : $ret; + $_[0]->{git_dir} =~ m!/([^/]+?)(?:/*\.git/*)?\z! ? "$1.git" : '???'; } sub host_prefix_url ($$) { @@ -461,7 +468,7 @@ sub pub_urls { if (my $urls = $self->{cgit_url}) { return map { host_prefix_url($env, $_) } @$urls; } - local_nick($self); + (local_nick($self)); } sub cat_async_begin {