use POSIX qw(dup2);
use IO::Socket::INET;
our @EXPORT = qw(tmpdir tcp_server tcp_connect require_git require_mods
- run_script start_script key2sub);
+ run_script start_script key2sub xsys xqx mime_load);
+
+sub mime_load ($;&) {
+ my ($path, $cb) = @_;
+ if (open(my $fh, '<', $path)) {
+ PublicInbox::MIME->new(\(do { local $/; <$fh> }));
+ } elsif ($cb) {
+ require File::Temp;
+
+ my $mime = $cb->();
+ my ($dir) = ($path =~ m!(.+)/(?:[^/]+)\z!);
+ -d $dir or die "BUG: dir=$dir is not the dir of $path";
+ my $fh = File::Temp->new(DIR => $dir);
+ $fh->autoflush(1);
+ print $fh $mime->as_string or die "print: $!";
+ my $fn = $fh->filename;
+ rename($fn, $path) or die "link $fn => $path: $!";
+ $fh->unlink_on_destroy(0);
+ pop @_; # retry via tail recursion
+ goto &mime_load;
+ } else {
+ die "open $path: $!";
+ }
+}
sub tmpdir (;$) {
my ($base) = @_;
sub key2script ($) {
my ($key) = @_;
- return $key if (index($key, '/') >= 0);
+ return $key if ($key eq 'git' || index($key, '/') >= 0);
# n.b. we may have scripts which don't start with "public-inbox" in
# the future:
$key =~ s/\A([-\.])/public-inbox$1/;
sub wait_for_tail () { sleep(2) }
+# like system() built-in, but uses spawn() for env/rdr + vfork
+sub xsys {
+ my ($cmd, $env, $rdr) = @_;
+ if (ref($cmd)) {
+ $rdr ||= {};
+ } else {
+ $cmd = [ @_ ];
+ $env = undef;
+ $rdr = {};
+ }
+ run_script($cmd, $env, { %$rdr, run_mode => 0 });
+ $? >> 8
+}
+
+# like `backtick` or qx{} op, but uses spawn() for env/rdr + vfork
+sub xqx {
+ my ($cmd, $env, $rdr) = @_;
+ $rdr //= {};
+ run_script($cmd, $env, { %$rdr, run_mode => 0, 1 => \(my $out) });
+ wantarray ? split(/^/m, $out) : $out;
+}
+
sub start_script {
my ($cmd, $env, $opt) = @_;
my ($key, @argv) = @$cmd;
}
sub join {
- my ($self) = @_;
+ my ($self, $sig) = @_;
my $pid = delete $self->{pid} or return;
+ CORE::kill($sig, $pid) if defined $sig;
my $ret = waitpid($pid, 0);
defined($ret) or die "waitpid($pid): $!";
$ret == $pid or die "waitpid($pid) != $ret";
PublicInbox::TestCommon::wait_for_tail();
CORE::kill('TERM', $tail);
}
- my $pid = delete $self->{pid} or return;
- CORE::kill('TERM', $pid);
+ $self->join('TERM');
}
1;