X-Git-Url: https://git.madduck.net/code/myrepos.git/blobdiff_plain/791dd2c6b4bff3e46b8dd45bf1b6d0aa8d15b5bc..ecae835d593673f0f721b4de19ce2718f8ecb3bb:/mr diff --git a/mr b/mr index 2b1a36c..76c629c 100755 --- a/mr +++ b/mr @@ -160,10 +160,8 @@ recurse into deeper repositories. =item -j number Run the specified number of jobs in parallel. This can greatly speed up -operations such as updates. - -Note that in -j mode, all output of the jobs goes to standard output, even -output that would normally go to standard error. +operations such as updates. It is not recommended for interactive +operations. =back @@ -443,6 +441,7 @@ if ($jobs > 1) { else { foreach my $repo (@repos) { record($repo, action($action, @$repo)); + print "\n"; } } if (! @ok && ! @failed && ! @skipped) { @@ -538,7 +537,6 @@ sub action { #{{{ join(" ", map { s/\//\/\//g; s/"/\"/g; '"'.$_.'"' } @ARGV); print STDERR "mr $action: running >>$command<<\n" if $verbose; my $ret=system($command); - print "\n"; if ($ret != 0) { if (($? & 127) == 2) { print STDERR "mr $action: interrupted\n"; @@ -569,63 +567,73 @@ sub action { #{{{ } #}}} # run actions on multiple repos, in parallel -my %jobs; sub mrs { #{{{ $| = 1; + my @active; my @fhs; my @out; my $running=0; while (@fhs or @repos) { while ($running < $jobs && @repos) { - $SIG{CHLD}='DEFAULT'; $running++; my $repo = shift @repos; - my $pid = open(my $fh, "-|"); - if (! $pid) { - open(STDERR, ">&STDOUT"); + pipe(my $outfh, CHILD_STDOUT); + pipe(my $errfh, CHILD_STDERR); + my $pid; + unless ($pid = fork) { + die "mr $action: cannot fork: $!" unless defined $pid; + open(STDOUT, ">&CHILD_STDOUT") || die "mr $action cannot reopen stdout: $!"; + open(STDERR, ">&CHILD_STDERR") || die "mr $action cannot reopen stderr: $!"; + close CHILD_STDOUT; + close CHILD_STDERR; + close $outfh; + close $errfh; exit action($action, @$repo); } - $jobs{$pid}=$repo; - push @fhs, $fh; - push @out, ""; - reaper(); - $SIG{CHLD}=\&reaper; + close CHILD_STDOUT; + close CHILD_STDERR; + push @active, [$pid, $repo]; + push @fhs, [$outfh, $errfh]; + push @out, ['', '']; } - my ($rin, $rout) = ('','', ''); + my ($rin, $rout) = ('',''); my $nfound; - foreach my $x (@fhs) { - next unless defined $x; - vec($rin, fileno($x), 1) = 1; + foreach my $fh (@fhs) { + next unless defined $fh; + vec($rin, fileno($fh->[0]), 1) = 1 if defined $fh->[0]; + vec($rin, fileno($fh->[1]), 1) = 1 if defined $fh->[1]; } $nfound = select($rout=$rin, undef, undef, 1); - foreach my $i (0..$#fhs) { - my $fh = $fhs[$i]; - next unless defined $fh; - if (vec($rout, fileno($fh), 1) == 1) { - my $r = ''; - if (sysread($fh, $r, 1024) == 0) { - close($fh); - $fhs[$i] = undef; - $running--; - print $out[$i]; - $out[$i]=''; + foreach my $channel (0, 1) { + foreach my $i (0..$#fhs) { + next unless defined $fhs[$i]; + my $fh = $fhs[$i][$channel]; + next unless defined $fh; + if (vec($rout, fileno($fh), 1) == 1) { + my $r = ''; + if (sysread($fh, $r, 1024) == 0) { + close($fh); + $fhs[$i][$channel] = undef; + if (! defined $fhs[$i][0] && + ! defined $fhs[$i][1]) { + waitpid($active[$i][0], 0); + print STDOUT $out[$i][0]; + print STDERR $out[$i][1]; + print "\n"; + record($active[$i][1], $? >> 8); + splice(@fhs, $i, 1); + splice(@active, $i, 1); + splice(@out, $i, 1); + $running--; + } + } + $out[$i][$channel] .= $r; } - $out[$i] .= $r; } } - while (@fhs and !defined $fhs[0]) { - shift @fhs; - shift @out; - } } } #}}} -sub reaper { #{{{ - while ((my $pid = waitpid(-1, &WNOHANG)) > 0) { - record($jobs{$pid}, $? >> 8) if exists $jobs{$pid}; - } -} #}}} - sub record { #{{{ my $dir=shift()->[0]; my $ret=shift;