in src/shipit/ShipItShellCommand.php [112:228]
private async function genRunOnce(): Awaitable<ShipItShellCommandResult> {
$fds = dict[
0 => vec['pipe', 'r'],
1 => vec['pipe', 'w'],
2 => vec['pipe', 'w'],
];
$stdin = $this->stdin;
if ($stdin === null) {
unset($fds[0]);
}
$env_vars = Dict\merge(ShipItEnv::getAll(), $this->environmentVariables);
$command = $this->getCommandAsString();
if ($this->showShellExecs) {
(new ShipItVerboseLogger(true))->out(
"Shell command: %s; cwd: %s",
$command,
$this->path ?? ".",
);
}
$pipes = vec[];
/* HH_IGNORE_ERROR[2049] __PHPStdLib */
/* HH_IGNORE_ERROR[4107] __PHPStdLib */
$fp = \proc_open($command, $fds, inout $pipes, $this->path, $env_vars);
if (!$fp || !\HH\is_any_array($pipes)) {
throw new \Exception("Failed executing $command");
}
if ($stdin !== null) {
while (Str\length($stdin)) {
$written = PHP\fwrite($pipes[0], $stdin);
if ($written === 0) {
$status = PHP\proc_get_status($fp);
if ($status['running']) {
continue;
}
$exitcode = $status['exitcode'];
invariant(
$exitcode is int && $exitcode > 0,
'Expected non-zero exit from process, got %s',
\var_export($exitcode, true),
);
break;
}
$stdin = Str\slice($stdin, $written);
}
PHP\fclose($pipes[0]);
}
$stdout_stream = $pipes[1];
$stderr_stream = $pipes[2];
PHP\stream_set_blocking($stdout_stream, false);
PHP\stream_set_blocking($stderr_stream, false);
$stdout = '';
$stderr = '';
while (true) {
$ready_streams = vec[$stdout_stream, $stderr_stream];
$null_byref = null;
do {
$result = PHP\stream_select(
inout $ready_streams,
/* write streams = */ inout $null_byref,
/* exception streams = */ inout $null_byref,
/* timeout = */ null,
);
} while (
$result === false &&
/* This **MUST NOT** be a PHP\ wrapper because `errno` is extremely volatile */
/* HH_IGNORE_ERROR[2049] __PHPStdLib */
/* HH_IGNORE_ERROR[4107] __PHPStdLib */
\posix_get_last_error() === 4 // \HH\Lib\OS\__Private\Errno::EINTR
);
if ($result === false) {
break;
}
$all_empty = true;
foreach (($ready_streams as Container<_>) as $stream) {
$out = PHP\fread($stream as resource, 1024) as string;
if (Str\length($out) === 0) {
continue;
}
$all_empty = false;
if ($stream === $stdout_stream) {
$stdout .= $out;
$this->maybeOut($out);
continue;
}
if ($stream === $stderr_stream) {
$stderr .= $out;
$this->maybeErr($out);
continue;
}
invariant_violation('Unhandled stream!');
}
if ($all_empty) {
break;
}
}
$exitcode = PHP\proc_close($fp);
$result = new ShipItShellCommandResult($exitcode, $stdout, $stderr);
if ($exitcode !== 0) {
$handler = $this->failureHandler;
if ($handler) {
await $handler($result);
}
if ($this->throwForNonZeroExit) {
throw new ShipItShellCommandException($command, $result);
}
}
return $result;
}