1
0
mirror of https://github.com/danog/process.git synced 2024-12-02 09:37:55 +01:00

Consume process output before closing

This commit is contained in:
Niklas Keller 2018-07-12 08:19:24 +02:00
parent 083d5a8ed5
commit b0e690d3ee
3 changed files with 74 additions and 32 deletions

View File

@ -4,6 +4,7 @@ namespace Amp\Process\Internal\Posix;
use Amp\Deferred; use Amp\Deferred;
use Amp\Process\Internal\ProcessHandle; use Amp\Process\Internal\ProcessHandle;
use Amp\Promise;
/** @internal */ /** @internal */
final class Handle extends ProcessHandle final class Handle extends ProcessHandle

View File

@ -44,7 +44,8 @@ final class Runner implements ProcessRunner
$pid = \rtrim(@\fgets($stream)); $pid = \rtrim(@\fgets($stream));
/** @var $deferreds Deferred[] */ /** @var Handle $handle */
/** @var Deferred[] $deferreds */
list($handle, $pipes, $deferreds) = $data; list($handle, $pipes, $deferreds) = $data;
if (!$pid || !\is_numeric($pid)) { if (!$pid || !\is_numeric($pid)) {
@ -67,11 +68,47 @@ final class Runner implements ProcessRunner
$deferreds[1]->resolve($pipes[1]); $deferreds[1]->resolve($pipes[1]);
$deferreds[2]->resolve($pipes[2]); $deferreds[2]->resolve($pipes[2]);
if ("" !== $exitCode = \rtrim(@\fgets($stream))) {
$handle->status = ProcessStatus::ENDED;
$handle->joinDeferred->resolve((int) $exitCode);
self::free($handle);
return;
}
if ($handle->extraDataPipeWatcher !== null) { if ($handle->extraDataPipeWatcher !== null) {
Loop::enable($handle->extraDataPipeWatcher); Loop::enable($handle->extraDataPipeWatcher);
} }
} }
private static function free(Handle $handle)
{
/** @var Handle $handle */
if ($handle->extraDataPipeWatcher !== null) {
Loop::cancel($handle->extraDataPipeWatcher);
$handle->extraDataPipeWatcher = null;
}
/** @var Handle $handle */
if ($handle->extraDataPipeStartWatcher !== null) {
Loop::cancel($handle->extraDataPipeStartWatcher);
$handle->extraDataPipeStartWatcher = null;
}
if (\is_resource($handle->extraDataPipe)) {
\fclose($handle->extraDataPipe);
}
$handle->stdin->close();
$handle->stdout->close();
$handle->stderr->close();
if (\is_resource($handle->proc)) {
\proc_close($handle->proc);
}
}
/** @inheritdoc */ /** @inheritdoc */
public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle public function start(string $command, string $cwd = null, array $env = [], array $options = []): ProcessHandle
{ {
@ -164,7 +201,7 @@ final class Runner implements ProcessRunner
$handle->joinDeferred->fail(new ProcessException("The process was killed")); $handle->joinDeferred->fail(new ProcessException("The process was killed"));
} }
$this->free($handle); self::free($handle);
} }
/** @inheritdoc */ /** @inheritdoc */
@ -189,33 +226,6 @@ final class Runner implements ProcessRunner
} }
} }
$this->free($handle); self::free($handle);
}
private function free(Handle $handle)
{
/** @var Handle $handle */
if ($handle->extraDataPipeWatcher !== null) {
Loop::cancel($handle->extraDataPipeWatcher);
$handle->extraDataPipeWatcher = null;
}
/** @var Handle $handle */
if ($handle->extraDataPipeStartWatcher !== null) {
Loop::cancel($handle->extraDataPipeStartWatcher);
$handle->extraDataPipeStartWatcher = null;
}
if (\is_resource($handle->extraDataPipe)) {
\fclose($handle->extraDataPipe);
}
$handle->stdin->close();
$handle->stdout->close();
$handle->stderr->close();
if (\is_resource($handle->proc)) {
\proc_close($handle->proc);
}
} }
} }

View File

@ -28,6 +28,9 @@ class ProcessInputStream implements InputStream
/** @var StreamException|null */ /** @var StreamException|null */
private $error; private $error;
/** @var string|null */
private $buffer;
public function __construct(Promise $resourceStreamPromise) public function __construct(Promise $resourceStreamPromise)
{ {
$resourceStreamPromise->onResolve(function ($error, $resourceStream) { $resourceStreamPromise->onResolve(function ($error, $resourceStream) {
@ -48,14 +51,25 @@ class ProcessInputStream implements InputStream
} }
if ($this->shouldClose) { if ($this->shouldClose) {
if ($this->resourceStream->getResource()) {
$this->buffer .= \stream_get_contents($this->resourceStream->getResource());
}
$this->resourceStream->close(); $this->resourceStream->close();
} }
if ($this->initialRead) { if ($this->initialRead) {
$initialRead = $this->initialRead; $initialRead = $this->initialRead;
$this->initialRead = null; $this->initialRead = null;
if ($this->buffer !== null) {
$buffer = $this->buffer;
$this->buffer = null;
$initialRead->resolve($buffer);
} else {
$initialRead->resolve($this->shouldClose ? null : $this->resourceStream->read()); $initialRead->resolve($this->shouldClose ? null : $this->resourceStream->read());
} }
}
}); });
} }
@ -66,6 +80,12 @@ class ProcessInputStream implements InputStream
throw new PendingReadError; throw new PendingReadError;
} }
if ($this->buffer !== null) {
$buffer = $this->buffer;
$this->buffer = null;
return $buffer;
}
if ($this->error) { if ($this->error) {
throw $this->error; throw $this->error;
} }
@ -105,10 +125,21 @@ class ProcessInputStream implements InputStream
{ {
$this->shouldClose = true; $this->shouldClose = true;
if ($this->resourceStream->getResource()) {
$this->buffer .= \stream_get_contents($this->resourceStream->getResource());
}
if ($this->initialRead) { if ($this->initialRead) {
$initialRead = $this->initialRead; $initialRead = $this->initialRead;
$this->initialRead = null; $this->initialRead = null;
$initialRead->resolve();
if ($this->buffer !== null) {
$buffer = $this->buffer;
$this->buffer = null;
$initialRead->resolve($buffer);
} else {
$initialRead->resolve(null);
}
} }
if ($this->resourceStream) { if ($this->resourceStream) {