lib/PublicInbox/Admin.pm | 31 +++++++++---------------------- lib/PublicInbox/SolverGit.pm | 6 +++--- lib/PublicInbox/Spawn.pm | 8 ++++++-- lib/PublicInbox/SpawnPP.pm | 7 +++++-- diff --git a/lib/PublicInbox/Admin.pm b/lib/PublicInbox/Admin.pm index 5a3554cfe460c9efb8189f93422fc90a9a5efe9b..44b44b6eb185c311b693d30edf5d0ead3c1bfa4b 100644 --- a/lib/PublicInbox/Admin.pm +++ b/lib/PublicInbox/Admin.pm @@ -10,6 +10,7 @@ use Cwd 'abs_path'; use base qw(Exporter); our @EXPORT_OK = qw(resolve_repo_dir); require PublicInbox::Config; +use PublicInbox::Spawn qw(popen_rd); sub resolve_repo_dir { my ($cd, $ver) = @_; @@ -18,28 +19,14 @@ if (-d $prefix && -f "$prefix/inbox.lock") { # v2 $$ver = 2 if $ver; return abs_path($prefix); } - - my @cmd = qw(git rev-parse --git-dir); - my $cmd = join(' ', @cmd); - my $pid = open my $fh, '-|'; - defined $pid or die "forking $cmd failed: $!\n"; - if ($pid == 0) { - if (defined $cd) { - chdir $cd or die "chdir $cd failed: $!\n"; - } - exec @cmd; - die "Failed to exec $cmd: $!\n"; - } else { - my $dir = eval { - local $/; - <$fh>; - }; - close $fh or die "error in $cmd (cwd:$cd): $!\n"; - chomp $dir; - $$ver = 1 if $ver; - return abs_path($cd) if ($dir eq '.' && defined $cd); - abs_path($dir); - } + my $cmd = [ qw(git rev-parse --git-dir) ]; + my $fh = popen_rd($cmd, undef, {-C => $cd}); + my $dir = do { local $/; <$fh> }; + close $fh or die "error in ".join(' ', @$cmd)." (cwd:$cd): $!\n"; + chomp $dir; + $$ver = 1 if $ver; + return abs_path($cd) if ($dir eq '.' && defined $cd); + abs_path($dir); } # for unconfigured inboxes diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm index 036666469ee1750b0886d676c27575d4c9665fbc..c57fb4c6b5c5e60f35a4004864b185512c2eb21d 100644 --- a/lib/PublicInbox/SolverGit.pm +++ b/lib/PublicInbox/SolverGit.pm @@ -472,7 +472,7 @@ my $dn = $self->{tmp}->dirname; my $patches = $self->{patches}; # we need --ignore-whitespace because some patches are CRLF - my @cmd = (qw(git -C), $dn, qw(apply --cached --ignore-whitespace + my @cmd = (qw(git apply --cached --ignore-whitespace --unidiff-zero --whitespace=warn --verbose)); my $len = length(join(' ', @cmd)); my $total = $self->{tot}; @@ -491,8 +491,8 @@ $prv_oid_b = $di->{oid_b}; } while (@$patches && $len < $ARG_SIZE_MAX && !oids_same_ish($patches->[0]->{oid_b}, $prv_oid_b)); - my $rdr = { 2 => 1 }; - my $qsp = PublicInbox::Qspawn->new(\@cmd, $self->{git_env}, $rdr); + my $opt = { 2 => 1, -C => $dn }; + my $qsp = PublicInbox::Qspawn->new(\@cmd, $self->{git_env}, $opt); $self->{-cur_di} = $di; $self->{-qsp} = $qsp; $qsp->psgi_qx($self->{psgi_env}, undef, \&apply_result, $self); diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm index 6d42d5bc70c39318865848013d2f7e96b77acbf8..d624c521ade4cc20f16c04b3e6f634e3e7753d65 100644 --- a/lib/PublicInbox/Spawn.pm +++ b/lib/PublicInbox/Spawn.pm @@ -84,7 +84,8 @@ * unstable internal API. It'll be updated depending on * whatever we'll need in the future. * Be sure to update PublicInbox::SpawnPP if this changes */ -int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref) +int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref, + const char *cd) { AV *redir = (AV *)SvRV(redirref); AV *cmd = (AV *)SvRV(cmdref); @@ -118,6 +119,8 @@ xerr("dup2"); } for (sig = 1; sig < NSIG; sig++) signal(sig, SIG_DFL); /* ignore errors on signals */ + if (*cd && chdir(cd) < 0) + xerr("chdir"); max = av_len(rlim); for (i = 0; i < max; i += 3) { @@ -216,7 +219,8 @@ next; } push @$rlim, $r, @$v; } - my $pid = pi_fork_exec($redir, $f, $cmd, \@env, $rlim); + my $cd = $opts->{'-C'} // ''; # undef => NULL mapping doesn't work? + my $pid = pi_fork_exec($redir, $f, $cmd, \@env, $rlim, $cd); $pid < 0 ? undef : $pid; } diff --git a/lib/PublicInbox/SpawnPP.pm b/lib/PublicInbox/SpawnPP.pm index 2ac02c564c76e36b24353f1b32d85e3677c0c9ad..cd682a6b6e006aeee72c390f70f9277a4b72946d 100644 --- a/lib/PublicInbox/SpawnPP.pm +++ b/lib/PublicInbox/SpawnPP.pm @@ -9,8 +9,8 @@ use warnings; use POSIX qw(dup2 :signal_h); # Pure Perl implementation for folks that do not use Inline::C -sub pi_fork_exec ($$$$$) { - my ($redir, $f, $cmd, $env, $rlim) = @_; +sub pi_fork_exec ($$$$$$) { + my ($redir, $f, $cmd, $env, $rlim, $cd) = @_; my $old = POSIX::SigSet->new(); my $set = POSIX::SigSet->new(); $set->fillset or die "fillset failed: $!"; @@ -32,6 +32,9 @@ my $parent_fd = $redir->[$child_fd]; next if $parent_fd == $child_fd; dup2($parent_fd, $child_fd) or die "dup2($parent_fd, $child_fd): $!\n"; + } + if ($cd ne '') { + chdir $cd or die "chdir $cd: $!"; } if ($ENV{MOD_PERL}) { exec which('env'), '-i', @$env, @$cmd;