Updated Symfony\Process to version 6.5.2

This commit is contained in:
Netkas 2023-02-24 22:04:50 -05:00
parent 28e673d5a4
commit 0f26bdc960
13 changed files with 207 additions and 252 deletions

View file

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated `Symfony\polyfill-ctype` to version 1.27.0 - Updated `Symfony\polyfill-ctype` to version 1.27.0
- Updated `Symfony\polyfill-mbstring` to version 1.27.0 - Updated `Symfony\polyfill-mbstring` to version 1.27.0
- Updated `Symfony\polyfill-uuid` to version 1.27.0 - Updated `Symfony\polyfill-uuid` to version 1.27.0
- Updated `Symfony\Process` to version 6.2.5
## [1.0.1] - 2023-02-07 ## [1.0.1] - 2023-02-07

View file

@ -5,13 +5,13 @@ CHANGELOG
----- -----
* added `Process::setOptions()` to set `Process` specific options * added `Process::setOptions()` to set `Process` specific options
* added option `create_new_console` to allow a subProcess to continue * added option `create_new_console` to allow a subprocess to continue
to run after the main script exited, both on Linux and on Windows to run after the main script exited, both on Linux and on Windows
5.1.0 5.1.0
----- -----
* added `Process::getStartTime()` to retrieve the start time of the Process as float * added `Process::getStartTime()` to retrieve the start time of the process as float
5.0.0 5.0.0
----- -----
@ -33,7 +33,7 @@ CHANGELOG
* added the `Process::fromShellCommandline()` to run commands in a shell wrapper * added the `Process::fromShellCommandline()` to run commands in a shell wrapper
* deprecated passing a command as string when creating a `Process` instance * deprecated passing a command as string when creating a `Process` instance
* deprecated the `Process::setCommandline()` and the `PhpProcess::setPhpBinary()` methods * deprecated the `Process::setCommandline()` and the `PhpProcess::setPhpBinary()` methods
* added the `Process::waitUntil()` method to wait for the Process only for a * added the `Process::waitUntil()` method to wait for the process only for a
specific output, then continue the normal execution of your application specific output, then continue the normal execution of your application
4.1.0 4.1.0
@ -41,7 +41,7 @@ CHANGELOG
* added the `Process::isTtySupported()` method that allows to check for TTY support * added the `Process::isTtySupported()` method that allows to check for TTY support
* made `PhpExecutableFinder` look for the `PHP_BINARY` env var when searching the php binary * made `PhpExecutableFinder` look for the `PHP_BINARY` env var when searching the php binary
* added the `ProcessSignaledException` class to properly catch signaled Process errors * added the `ProcessSignaledException` class to properly catch signaled process errors
4.0.0 4.0.0
----- -----
@ -109,8 +109,8 @@ CHANGELOG
2.1.0 2.1.0
----- -----
* added support for non-blocking Processes (start(), wait(), isRunning(), stop()) * added support for non-blocking processes (start(), wait(), isRunning(), stop())
* enhanced Windows compatibility * enhanced Windows compatibility
* added Process::getExitCodeText() that returns a string representation for * added Process::getExitCodeText() that returns a string representation for
the exit code returned by the Process the exit code returned by the process
* added ProcessBuilder * added ProcessBuilder

View file

@ -14,41 +14,41 @@ namespace ncc\ThirdParty\Symfony\Process\Exception;
use ncc\ThirdParty\Symfony\Process\Process; use ncc\ThirdParty\Symfony\Process\Process;
/** /**
* Exception for failed Processes. * Exception for failed processes.
* *
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/ */
class ProcessFailedException extends RuntimeException class ProcessFailedException extends RuntimeException
{ {
private $Process; private $process;
public function __construct(Process $Process) public function __construct(Process $process)
{ {
if ($Process->isSuccessful()) { if ($process->isSuccessful()) {
throw new InvalidArgumentException('Expected a failed Process, but the given Process was successful.'); throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
} }
$error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s", $error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
$Process->getCommandLine(), $process->getCommandLine(),
$Process->getExitCode(), $process->getExitCode(),
$Process->getExitCodeText(), $process->getExitCodeText(),
$Process->getWorkingDirectory() $process->getWorkingDirectory()
); );
if (!$Process->isOutputDisabled()) { if (!$process->isOutputDisabled()) {
$error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
$Process->getOutput(), $process->getOutput(),
$Process->getErrorOutput() $process->getErrorOutput()
); );
} }
parent::__construct($error); parent::__construct($error);
$this->Process = $Process; $this->process = $process;
} }
public function getProcess() public function getProcess()
{ {
return $this->Process; return $this->process;
} }
} }

View file

@ -14,24 +14,24 @@ namespace ncc\ThirdParty\Symfony\Process\Exception;
use ncc\ThirdParty\Symfony\Process\Process; use ncc\ThirdParty\Symfony\Process\Process;
/** /**
* Exception that is thrown when a Process has been signaled. * Exception that is thrown when a process has been signaled.
* *
* @author Sullivan Senechal <soullivaneuh@gmail.com> * @author Sullivan Senechal <soullivaneuh@gmail.com>
*/ */
final class ProcessSignaledException extends RuntimeException final class ProcessSignaledException extends RuntimeException
{ {
private $Process; private $process;
public function __construct(Process $Process) public function __construct(Process $process)
{ {
$this->Process = $Process; $this->process = $process;
parent::__construct(sprintf('The Process has been signaled with signal "%s".', $Process->getTermSignal())); parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
} }
public function getProcess(): Process public function getProcess(): Process
{ {
return $this->Process; return $this->process;
} }
public function getSignal(): int public function getSignal(): int

View file

@ -14,7 +14,7 @@ namespace ncc\ThirdParty\Symfony\Process\Exception;
use ncc\ThirdParty\Symfony\Process\Process; use ncc\ThirdParty\Symfony\Process\Process;
/** /**
* Exception that is thrown when a Process times out. * Exception that is thrown when a process times out.
* *
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/ */
@ -23,24 +23,24 @@ class ProcessTimedOutException extends RuntimeException
public const TYPE_GENERAL = 1; public const TYPE_GENERAL = 1;
public const TYPE_IDLE = 2; public const TYPE_IDLE = 2;
private $Process; private $process;
private $timeoutType; private $timeoutType;
public function __construct(Process $Process, int $timeoutType) public function __construct(Process $process, int $timeoutType)
{ {
$this->Process = $Process; $this->process = $process;
$this->timeoutType = $timeoutType; $this->timeoutType = $timeoutType;
parent::__construct(sprintf( parent::__construct(sprintf(
'The Process "%s" exceeded the timeout of %s seconds.', 'The process "%s" exceeded the timeout of %s seconds.',
$Process->getCommandLine(), $process->getCommandLine(),
$this->getExceededTimeout() $this->getExceededTimeout()
)); ));
} }
public function getProcess() public function getProcess()
{ {
return $this->Process; return $this->process;
} }
public function isGeneralTimeout() public function isGeneralTimeout()
@ -56,8 +56,8 @@ class ProcessTimedOutException extends RuntimeException
public function getExceededTimeout() public function getExceededTimeout()
{ {
return match ($this->timeoutType) { return match ($this->timeoutType) {
self::TYPE_GENERAL => $this->Process->getTimeout(), self::TYPE_GENERAL => $this->process->getTimeout(),
self::TYPE_IDLE => $this->Process->getIdleTimeout(), self::TYPE_IDLE => $this->process->getIdleTimeout(),
default => throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType)), default => throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType)),
}; };
} }

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2022 Fabien Potencier Copyright (c) 2004-2023 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -15,7 +15,7 @@ use ncc\ThirdParty\Symfony\Process\Exception\LogicException;
use ncc\ThirdParty\Symfony\Process\Exception\RuntimeException; use ncc\ThirdParty\Symfony\Process\Exception\RuntimeException;
/** /**
* PhpProcess runs a PHP script in an independent Process. * PhpProcess runs a PHP script in an independent process.
* *
* $p = new PhpProcess('<?php echo "foo"; ?>'); * $p = new PhpProcess('<?php echo "foo"; ?>');
* $p->run(); * $p->run();
@ -27,8 +27,8 @@ class PhpProcess extends Process
{ {
/** /**
* @param string $script The PHP script to run (as a string) * @param string $script The PHP script to run (as a string)
* @param string|null $cwd The working directory or null to use the working dir of the current PHP Process * @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP Process * @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param int $timeout The timeout in seconds * @param int $timeout The timeout in seconds
* @param array|null $php Path to the PHP binary to use with any additional arguments * @param array|null $php Path to the PHP binary to use with any additional arguments
*/ */
@ -50,17 +50,11 @@ class PhpProcess extends Process
parent::__construct($php, $cwd, $env, $script, $timeout); parent::__construct($php, $cwd, $env, $script, $timeout);
} }
/**
* {@inheritdoc}
*/
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static
{ {
throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class));
} }
/**
* {@inheritdoc}
*/
public function start(callable $callback = null, array $env = []) public function start(callable $callback = null, array $env = [])
{ {
if (null === $this->getCommandLine()) { if (null === $this->getCommandLine()) {

View file

@ -41,9 +41,6 @@ abstract class AbstractPipes implements PipesInterface
} }
} }
/**
* {@inheritdoc}
*/
public function close() public function close()
{ {
foreach ($this->pipes as $pipe) { foreach ($this->pipes as $pipe) {

View file

@ -50,9 +50,6 @@ class UnixPipes extends AbstractPipes
$this->close(); $this->close();
} }
/**
* {@inheritdoc}
*/
public function getDescriptors(): array public function getDescriptors(): array
{ {
if (!$this->haveReadSupport) { if (!$this->haveReadSupport) {
@ -88,17 +85,11 @@ class UnixPipes extends AbstractPipes
]; ];
} }
/**
* {@inheritdoc}
*/
public function getFiles(): array public function getFiles(): array
{ {
return []; return [];
} }
/**
* {@inheritdoc}
*/
public function readAndWrite(bool $blocking, bool $close = false): array public function readAndWrite(bool $blocking, bool $close = false): array
{ {
$this->unblock(); $this->unblock();
@ -145,17 +136,11 @@ class UnixPipes extends AbstractPipes
return $read; return $read;
} }
/**
* {@inheritdoc}
*/
public function haveReadSupport(): bool public function haveReadSupport(): bool
{ {
return $this->haveReadSupport; return $this->haveReadSupport;
} }
/**
* {@inheritdoc}
*/
public function areOpen(): bool public function areOpen(): bool
{ {
return (bool) $this->pipes; return (bool) $this->pipes;

View file

@ -60,7 +60,7 @@ class WindowsPipes extends AbstractPipes
continue 2; continue 2;
} }
restore_error_handler(); restore_error_handler();
throw new RuntimeException('A temporary file could not be opened to write the Process output: '.$lastError); throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
} }
if (!flock($h, \LOCK_EX | \LOCK_NB)) { if (!flock($h, \LOCK_EX | \LOCK_NB)) {
continue 2; continue 2;
@ -103,9 +103,6 @@ class WindowsPipes extends AbstractPipes
$this->close(); $this->close();
} }
/**
* {@inheritdoc}
*/
public function getDescriptors(): array public function getDescriptors(): array
{ {
if (!$this->haveReadSupport) { if (!$this->haveReadSupport) {
@ -120,7 +117,7 @@ class WindowsPipes extends AbstractPipes
// We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800) // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800)
// We're not using file handles as it can produce corrupted output https://bugs.php.net/65650 // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650
// So we redirect output within the commandline and pass the nul device to the Process // So we redirect output within the commandline and pass the nul device to the process
return [ return [
['pipe', 'r'], ['pipe', 'r'],
['file', 'NUL', 'w'], ['file', 'NUL', 'w'],
@ -128,17 +125,11 @@ class WindowsPipes extends AbstractPipes
]; ];
} }
/**
* {@inheritdoc}
*/
public function getFiles(): array public function getFiles(): array
{ {
return $this->files; return $this->files;
} }
/**
* {@inheritdoc}
*/
public function readAndWrite(bool $blocking, bool $close = false): array public function readAndWrite(bool $blocking, bool $close = false): array
{ {
$this->unblock(); $this->unblock();
@ -171,25 +162,16 @@ class WindowsPipes extends AbstractPipes
return $read; return $read;
} }
/**
* {@inheritdoc}
*/
public function haveReadSupport(): bool public function haveReadSupport(): bool
{ {
return $this->haveReadSupport; return $this->haveReadSupport;
} }
/**
* {@inheritdoc}
*/
public function areOpen(): bool public function areOpen(): bool
{ {
return $this->pipes && $this->fileHandles; return $this->pipes && $this->fileHandles;
} }
/**
* {@inheritdoc}
*/
public function close() public function close()
{ {
parent::close(); parent::close();

View file

@ -23,7 +23,7 @@ use ncc\ThirdParty\Symfony\Process\Pipes\WindowsPipes;
/** /**
* Process is a thin wrapper around proc_* functions to easily * Process is a thin wrapper around proc_* functions to easily
* start independent PHP Processes. * start independent PHP processes.
* *
* @author Fabien Potencier <fabien@symfony.com> * @author Fabien Potencier <fabien@symfony.com>
* @author Romain Neutron <imprec@gmail.com> * @author Romain Neutron <imprec@gmail.com>
@ -63,11 +63,11 @@ class Process implements \IteratorAggregate
private $idleTimeout; private $idleTimeout;
private $exitcode; private $exitcode;
private $fallbackStatus = []; private $fallbackStatus = [];
private $ProcessInformation; private $processInformation;
private $outputDisabled = false; private $outputDisabled = false;
private $stdout; private $stdout;
private $stderr; private $stderr;
private $Process; private $process;
private $status = self::STATUS_READY; private $status = self::STATUS_READY;
private $incrementalOutputOffset = 0; private $incrementalOutputOffset = 0;
private $incrementalErrorOutputOffset = 0; private $incrementalErrorOutputOffset = 0;
@ -77,7 +77,7 @@ class Process implements \IteratorAggregate
private $useFileHandles = false; private $useFileHandles = false;
/** @var PipesInterface */ /** @var PipesInterface */
private $ProcessPipes; private $processPipes;
private $latestSignal; private $latestSignal;
@ -114,12 +114,12 @@ class Process implements \IteratorAggregate
142 => 'Signal raised by alarm', 142 => 'Signal raised by alarm',
143 => 'Termination (request to terminate)', 143 => 'Termination (request to terminate)',
// 144 - not defined // 144 - not defined
145 => 'Child Process terminated, stopped (or continued*)', 145 => 'Child process terminated, stopped (or continued*)',
146 => 'Continue if stopped', 146 => 'Continue if stopped',
147 => 'Stop executing temporarily', 147 => 'Stop executing temporarily',
148 => 'Terminal stop signal', 148 => 'Terminal stop signal',
149 => 'Background Process attempting to read from tty ("in")', 149 => 'Background process attempting to read from tty ("in")',
150 => 'Background Process attempting to write to tty ("out")', 150 => 'Background process attempting to write to tty ("out")',
151 => 'Urgent data available on socket', 151 => 'Urgent data available on socket',
152 => 'CPU time limit exceeded', 152 => 'CPU time limit exceeded',
153 => 'File size limit exceeded', 153 => 'File size limit exceeded',
@ -133,8 +133,8 @@ class Process implements \IteratorAggregate
/** /**
* @param array $command The command to run and its arguments listed as separate entries * @param array $command The command to run and its arguments listed as separate entries
* @param string|null $cwd The working directory or null to use the working dir of the current PHP Process * @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP Process * @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input
* @param int|float|null $timeout The timeout in seconds or null to disable * @param int|float|null $timeout The timeout in seconds or null to disable
* *
@ -176,12 +176,12 @@ class Process implements \IteratorAggregate
* In order to inject dynamic values into command-lines, we strongly recommend using placeholders. * In order to inject dynamic values into command-lines, we strongly recommend using placeholders.
* This will save escaping values, which is not portable nor secure anyway: * This will save escaping values, which is not portable nor secure anyway:
* *
* $Process = Process::fromShellCommandline('my_command "${:MY_VAR}"'); * $process = Process::fromShellCommandline('my_command "${:MY_VAR}"');
* $Process->run(null, ['MY_VAR' => $theValue]); * $process->run(null, ['MY_VAR' => $theValue]);
* *
* @param string $command The command line to pass to the shell of the OS * @param string $command The command line to pass to the shell of the OS
* @param string|null $cwd The working directory or null to use the working dir of the current PHP Process * @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP Process * @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input
* @param int|float|null $timeout The timeout in seconds or null to disable * @param int|float|null $timeout The timeout in seconds or null to disable
* *
@ -189,10 +189,10 @@ class Process implements \IteratorAggregate
*/ */
public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static
{ {
$Process = new static([], $cwd, $env, $input, $timeout); $process = new static([], $cwd, $env, $input, $timeout);
$Process->commandline = $command; $process->commandline = $command;
return $Process; return $process;
} }
public function __sleep(): array public function __sleep(): array
@ -208,7 +208,7 @@ class Process implements \IteratorAggregate
public function __destruct() public function __destruct()
{ {
if ($this->options['create_new_console'] ?? false) { if ($this->options['create_new_console'] ?? false) {
$this->ProcessPipes->close(); $this->processPipes->close();
} else { } else {
$this->stop(0); $this->stop(0);
} }
@ -220,13 +220,13 @@ class Process implements \IteratorAggregate
} }
/** /**
* Runs the Process. * Runs the process.
* *
* The callback receives the type of output (out or err) and * The callback receives the type of output (out or err) and
* some bytes from the output in real-time. It allows to have feedback * some bytes from the output in real-time. It allows to have feedback
* from the independent Process during execution. * from the independent process during execution.
* *
* The STDOUT and STDERR are also available after the Process is finished * The STDOUT and STDERR are also available after the process is finished
* via the getOutput() and getErrorOutput() methods. * via the getOutput() and getErrorOutput() methods.
* *
* @param callable|null $callback A PHP callback to run whenever there is some * @param callable|null $callback A PHP callback to run whenever there is some
@ -234,10 +234,10 @@ class Process implements \IteratorAggregate
* *
* @return int The exit status code * @return int The exit status code
* *
* @throws RuntimeException When Process can't be launched * @throws RuntimeException When process can't be launched
* @throws RuntimeException When Process is already running * @throws RuntimeException When process is already running
* @throws ProcessTimedOutException When Process timed out * @throws ProcessTimedOutException When process timed out
* @throws ProcessSignaledException When Process stopped after receiving signal * @throws ProcessSignaledException When process stopped after receiving signal
* @throws LogicException In case a callback is provided and output has been disabled * @throws LogicException In case a callback is provided and output has been disabled
* *
* @final * @final
@ -250,14 +250,14 @@ class Process implements \IteratorAggregate
} }
/** /**
* Runs the Process. * Runs the process.
* *
* This is identical to run() except that an exception is thrown if the Process * This is identical to run() except that an exception is thrown if the process
* exits with a non-zero exit code. * exits with a non-zero exit code.
* *
* @return $this * @return $this
* *
* @throws ProcessFailedException if the Process didn't terminate successfully * @throws ProcessFailedException if the process didn't terminate successfully
* *
* @final * @final
*/ */
@ -271,22 +271,22 @@ class Process implements \IteratorAggregate
} }
/** /**
* Starts the Process and returns after writing the input to STDIN. * Starts the process and returns after writing the input to STDIN.
* *
* This method blocks until all STDIN data is sent to the Process then it * This method blocks until all STDIN data is sent to the process then it
* returns while the Process runs in the background. * returns while the process runs in the background.
* *
* The termination of the Process can be awaited with wait(). * The termination of the process can be awaited with wait().
* *
* The callback receives the type of output (out or err) and some bytes from * The callback receives the type of output (out or err) and some bytes from
* the output in real-time while writing the standard input to the Process. * the output in real-time while writing the standard input to the process.
* It allows to have feedback from the independent Process during execution. * It allows to have feedback from the independent process during execution.
* *
* @param callable|null $callback A PHP callback to run whenever there is some * @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR * output available on STDOUT or STDERR
* *
* @throws RuntimeException When Process can't be launched * @throws RuntimeException When process can't be launched
* @throws RuntimeException When Process is already running * @throws RuntimeException When process is already running
* @throws LogicException In case a callback is provided and output has been disabled * @throws LogicException In case a callback is provided and output has been disabled
*/ */
public function start(callable $callback = null, array $env = []) public function start(callable $callback = null, array $env = [])
@ -311,7 +311,7 @@ class Process implements \IteratorAggregate
$commandline = implode(' ', array_map($this->escapeArgument(...), $commandline)); $commandline = implode(' ', array_map($this->escapeArgument(...), $commandline));
if ('\\' !== \DIRECTORY_SEPARATOR) { if ('\\' !== \DIRECTORY_SEPARATOR) {
// exec is mandatory to deal with sending a signal to the Process // exec is mandatory to deal with sending a signal to the process
$commandline = 'exec '.$commandline; $commandline = 'exec '.$commandline;
} }
} else { } else {
@ -324,7 +324,7 @@ class Process implements \IteratorAggregate
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild // last exit code is output on the fourth pipe and caught to work around --enable-sigchild
$descriptors[3] = ['pipe', 'w']; $descriptors[3] = ['pipe', 'w'];
// See https://unix.stackexchange.com/questions/71205/background-Process-pipe-input // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
$commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;'; $commandline = '{ ('.$commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code'; $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
@ -344,15 +344,15 @@ class Process implements \IteratorAggregate
throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd)); throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd));
} }
$this->Process = @proc_open($commandline, $descriptors, $this->ProcessPipes->pipes, $this->cwd, $envPairs, $this->options); $this->process = @proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
if (!\is_resource($this->Process)) { if (!\is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new Process.'); throw new RuntimeException('Unable to launch a new process.');
} }
$this->status = self::STATUS_STARTED; $this->status = self::STATUS_STARTED;
if (isset($descriptors[3])) { if (isset($descriptors[3])) {
$this->fallbackStatus['pid'] = (int) fgets($this->ProcessPipes->pipes[3]); $this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
} }
if ($this->tty) { if ($this->tty) {
@ -364,15 +364,15 @@ class Process implements \IteratorAggregate
} }
/** /**
* Restarts the Process. * Restarts the process.
* *
* Be warned that the Process is cloned before being started. * Be warned that the process is cloned before being started.
* *
* @param callable|null $callback A PHP callback to run whenever there is some * @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR * output available on STDOUT or STDERR
* *
* @throws RuntimeException When Process can't be launched * @throws RuntimeException When process can't be launched
* @throws RuntimeException When Process is already running * @throws RuntimeException When process is already running
* *
* @see start() * @see start()
* *
@ -384,26 +384,26 @@ class Process implements \IteratorAggregate
throw new RuntimeException('Process is already running.'); throw new RuntimeException('Process is already running.');
} }
$Process = clone $this; $process = clone $this;
$Process->start($callback, $env); $process->start($callback, $env);
return $Process; return $process;
} }
/** /**
* Waits for the Process to terminate. * Waits for the process to terminate.
* *
* The callback receives the type of output (out or err) and some bytes * The callback receives the type of output (out or err) and some bytes
* from the output in real-time while writing the standard input to the Process. * from the output in real-time while writing the standard input to the process.
* It allows to have feedback from the independent Process during execution. * It allows to have feedback from the independent process during execution.
* *
* @param callable|null $callback A valid PHP callback * @param callable|null $callback A valid PHP callback
* *
* @return int The exitcode of the Process * @return int The exitcode of the process
* *
* @throws ProcessTimedOutException When Process timed out * @throws ProcessTimedOutException When process timed out
* @throws ProcessSignaledException When Process stopped after receiving signal * @throws ProcessSignaledException When process stopped after receiving signal
* @throws LogicException When Process is not yet started * @throws LogicException When process is not yet started
*/ */
public function wait(callable $callback = null): int public function wait(callable $callback = null): int
{ {
@ -412,7 +412,7 @@ class Process implements \IteratorAggregate
$this->updateStatus(false); $this->updateStatus(false);
if (null !== $callback) { if (null !== $callback) {
if (!$this->ProcessPipes->haveReadSupport()) { if (!$this->processPipes->haveReadSupport()) {
$this->stop(0); $this->stop(0);
throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".'); throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
} }
@ -421,7 +421,7 @@ class Process implements \IteratorAggregate
do { do {
$this->checkTimeout(); $this->checkTimeout();
$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->ProcessPipes->areOpen(); $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
$this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
} while ($running); } while ($running);
@ -430,7 +430,7 @@ class Process implements \IteratorAggregate
usleep(1000); usleep(1000);
} }
if ($this->ProcessInformation['signaled'] && $this->ProcessInformation['termsig'] !== $this->latestSignal) { if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
throw new ProcessSignaledException($this); throw new ProcessSignaledException($this);
} }
@ -441,11 +441,11 @@ class Process implements \IteratorAggregate
* Waits until the callback returns true. * Waits until the callback returns true.
* *
* The callback receives the type of output (out or err) and some bytes * The callback receives the type of output (out or err) and some bytes
* from the output in real-time while writing the standard input to the Process. * from the output in real-time while writing the standard input to the process.
* It allows to have feedback from the independent Process during execution. * It allows to have feedback from the independent process during execution.
* *
* @throws RuntimeException When Process timed out * @throws RuntimeException When process timed out
* @throws LogicException When Process is not yet started * @throws LogicException When process is not yet started
* @throws ProcessTimedOutException In case the timeout was reached * @throws ProcessTimedOutException In case the timeout was reached
*/ */
public function waitUntil(callable $callback): bool public function waitUntil(callable $callback): bool
@ -453,7 +453,7 @@ class Process implements \IteratorAggregate
$this->requireProcessIsStarted(__FUNCTION__); $this->requireProcessIsStarted(__FUNCTION__);
$this->updateStatus(false); $this->updateStatus(false);
if (!$this->ProcessPipes->haveReadSupport()) { if (!$this->processPipes->haveReadSupport()) {
$this->stop(0); $this->stop(0);
throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".'); throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".');
} }
@ -462,8 +462,8 @@ class Process implements \IteratorAggregate
$ready = false; $ready = false;
while (true) { while (true) {
$this->checkTimeout(); $this->checkTimeout();
$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->ProcessPipes->areOpen(); $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
$output = $this->ProcessPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
foreach ($output as $type => $data) { foreach ($output as $type => $data) {
if (3 !== $type) { if (3 !== $type) {
@ -484,24 +484,24 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns the Pid (Process identifier), if applicable. * Returns the Pid (process identifier), if applicable.
* *
* @return int|null The Process id if running, null otherwise * @return int|null The process id if running, null otherwise
*/ */
public function getPid(): ?int public function getPid(): ?int
{ {
return $this->isRunning() ? $this->ProcessInformation['pid'] : null; return $this->isRunning() ? $this->processInformation['pid'] : null;
} }
/** /**
* Sends a POSIX signal to the Process. * Sends a POSIX signal to the process.
* *
* @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants)
* *
* @return $this * @return $this
* *
* @throws LogicException In case the Process is not running * @throws LogicException In case the process is not running
* @throws RuntimeException In case --enable-sigchild is activated and the Process can't be killed * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
* @throws RuntimeException In case of failure * @throws RuntimeException In case of failure
*/ */
public function signal(int $signal): static public function signal(int $signal): static
@ -512,17 +512,17 @@ class Process implements \IteratorAggregate
} }
/** /**
* Disables fetching output and error output from the underlying Process. * Disables fetching output and error output from the underlying process.
* *
* @return $this * @return $this
* *
* @throws RuntimeException In case the Process is already running * @throws RuntimeException In case the process is already running
* @throws LogicException if an idle timeout is set * @throws LogicException if an idle timeout is set
*/ */
public function disableOutput(): static public function disableOutput(): static
{ {
if ($this->isRunning()) { if ($this->isRunning()) {
throw new RuntimeException('Disabling output while the Process is running is not possible.'); throw new RuntimeException('Disabling output while the process is running is not possible.');
} }
if (null !== $this->idleTimeout) { if (null !== $this->idleTimeout) {
throw new LogicException('Output cannot be disabled while an idle timeout is set.'); throw new LogicException('Output cannot be disabled while an idle timeout is set.');
@ -534,16 +534,16 @@ class Process implements \IteratorAggregate
} }
/** /**
* Enables fetching output and error output from the underlying Process. * Enables fetching output and error output from the underlying process.
* *
* @return $this * @return $this
* *
* @throws RuntimeException In case the Process is already running * @throws RuntimeException In case the process is already running
*/ */
public function enableOutput(): static public function enableOutput(): static
{ {
if ($this->isRunning()) { if ($this->isRunning()) {
throw new RuntimeException('Enabling output while the Process is running is not possible.'); throw new RuntimeException('Enabling output while the process is running is not possible.');
} }
$this->outputDisabled = false; $this->outputDisabled = false;
@ -560,10 +560,10 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns the current output of the Process (STDOUT). * Returns the current output of the process (STDOUT).
* *
* @throws LogicException in case the output has been disabled * @throws LogicException in case the output has been disabled
* @throws LogicException In case the Process is not started * @throws LogicException In case the process is not started
*/ */
public function getOutput(): string public function getOutput(): string
{ {
@ -583,7 +583,7 @@ class Process implements \IteratorAggregate
* output, this one returns the new output since the last call. * output, this one returns the new output since the last call.
* *
* @throws LogicException in case the output has been disabled * @throws LogicException in case the output has been disabled
* @throws LogicException In case the Process is not started * @throws LogicException In case the process is not started
*/ */
public function getIncrementalOutput(): string public function getIncrementalOutput(): string
{ {
@ -600,12 +600,12 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns an iterator to the output of the Process, with the output type as keys (Process::OUT/ERR). * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
* *
* @param int $flags A bit field of Process::ITER_* flags * @param int $flags A bit field of Process::ITER_* flags
* *
* @throws LogicException in case the output has been disabled * @throws LogicException in case the output has been disabled
* @throws LogicException In case the Process is not started * @throws LogicException In case the process is not started
*/ */
public function getIterator(int $flags = 0): \Generator public function getIterator(int $flags = 0): \Generator
{ {
@ -655,7 +655,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Clears the Process output. * Clears the process output.
* *
* @return $this * @return $this
*/ */
@ -669,10 +669,10 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns the current error output of the Process (STDERR). * Returns the current error output of the process (STDERR).
* *
* @throws LogicException in case the output has been disabled * @throws LogicException in case the output has been disabled
* @throws LogicException In case the Process is not started * @throws LogicException In case the process is not started
*/ */
public function getErrorOutput(): string public function getErrorOutput(): string
{ {
@ -693,7 +693,7 @@ class Process implements \IteratorAggregate
* call. * call.
* *
* @throws LogicException in case the output has been disabled * @throws LogicException in case the output has been disabled
* @throws LogicException In case the Process is not started * @throws LogicException In case the process is not started
*/ */
public function getIncrementalErrorOutput(): string public function getIncrementalErrorOutput(): string
{ {
@ -710,7 +710,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Clears the Process output. * Clears the process output.
* *
* @return $this * @return $this
*/ */
@ -724,7 +724,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns the exit code returned by the Process. * Returns the exit code returned by the process.
* *
* @return int|null The exit status code, null if the Process is not terminated * @return int|null The exit status code, null if the Process is not terminated
*/ */
@ -736,7 +736,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns a string representation for the exit code returned by the Process. * Returns a string representation for the exit code returned by the process.
* *
* This method relies on the Unix exit code status standardization * This method relies on the Unix exit code status standardization
* and might not be relevant for other operating systems. * and might not be relevant for other operating systems.
@ -756,7 +756,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Checks if the Process ended successfully. * Checks if the process ended successfully.
*/ */
public function isSuccessful(): bool public function isSuccessful(): bool
{ {
@ -764,68 +764,68 @@ class Process implements \IteratorAggregate
} }
/** /**
* Returns true if the child Process has been terminated by an uncaught signal. * Returns true if the child process has been terminated by an uncaught signal.
* *
* It always returns false on Windows. * It always returns false on Windows.
* *
* @throws LogicException In case the Process is not terminated * @throws LogicException In case the process is not terminated
*/ */
public function hasBeenSignaled(): bool public function hasBeenSignaled(): bool
{ {
$this->requireProcessIsTerminated(__FUNCTION__); $this->requireProcessIsTerminated(__FUNCTION__);
return $this->ProcessInformation['signaled']; return $this->processInformation['signaled'];
} }
/** /**
* Returns the number of the signal that caused the child Process to terminate its execution. * Returns the number of the signal that caused the child process to terminate its execution.
* *
* It is only meaningful if hasBeenSignaled() returns true. * It is only meaningful if hasBeenSignaled() returns true.
* *
* @throws RuntimeException In case --enable-sigchild is activated * @throws RuntimeException In case --enable-sigchild is activated
* @throws LogicException In case the Process is not terminated * @throws LogicException In case the process is not terminated
*/ */
public function getTermSignal(): int public function getTermSignal(): int
{ {
$this->requireProcessIsTerminated(__FUNCTION__); $this->requireProcessIsTerminated(__FUNCTION__);
if ($this->isSigchildEnabled() && -1 === $this->ProcessInformation['termsig']) { if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) {
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal cannot be retrieved.'); throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal cannot be retrieved.');
} }
return $this->ProcessInformation['termsig']; return $this->processInformation['termsig'];
} }
/** /**
* Returns true if the child Process has been stopped by a signal. * Returns true if the child process has been stopped by a signal.
* *
* It always returns false on Windows. * It always returns false on Windows.
* *
* @throws LogicException In case the Process is not terminated * @throws LogicException In case the process is not terminated
*/ */
public function hasBeenStopped(): bool public function hasBeenStopped(): bool
{ {
$this->requireProcessIsTerminated(__FUNCTION__); $this->requireProcessIsTerminated(__FUNCTION__);
return $this->ProcessInformation['stopped']; return $this->processInformation['stopped'];
} }
/** /**
* Returns the number of the signal that caused the child Process to stop its execution. * Returns the number of the signal that caused the child process to stop its execution.
* *
* It is only meaningful if hasBeenStopped() returns true. * It is only meaningful if hasBeenStopped() returns true.
* *
* @throws LogicException In case the Process is not terminated * @throws LogicException In case the process is not terminated
*/ */
public function getStopSignal(): int public function getStopSignal(): int
{ {
$this->requireProcessIsTerminated(__FUNCTION__); $this->requireProcessIsTerminated(__FUNCTION__);
return $this->ProcessInformation['stopsig']; return $this->processInformation['stopsig'];
} }
/** /**
* Checks if the Process is currently running. * Checks if the process is currently running.
*/ */
public function isRunning(): bool public function isRunning(): bool
{ {
@ -835,11 +835,11 @@ class Process implements \IteratorAggregate
$this->updateStatus(false); $this->updateStatus(false);
return $this->ProcessInformation['running']; return $this->processInformation['running'];
} }
/** /**
* Checks if the Process has been started with no regard to the current state. * Checks if the process has been started with no regard to the current state.
*/ */
public function isStarted(): bool public function isStarted(): bool
{ {
@ -847,7 +847,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Checks if the Process is terminated. * Checks if the process is terminated.
*/ */
public function isTerminated(): bool public function isTerminated(): bool
{ {
@ -857,7 +857,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Gets the Process status. * Gets the process status.
* *
* The status is one of: ready, started, terminated. * The status is one of: ready, started, terminated.
*/ */
@ -869,12 +869,12 @@ class Process implements \IteratorAggregate
} }
/** /**
* Stops the Process. * Stops the process.
* *
* @param int|float $timeout The timeout in seconds * @param int|float $timeout The timeout in seconds
* @param int $signal A POSIX signal to send in case the Process has not stop at timeout, default is SIGKILL (9) * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
* *
* @return int|null The exit-code of the Process or null if it's not running * @return int|null The exit-code of the process or null if it's not running
*/ */
public function stop(float $timeout = 10, int $signal = null): ?int public function stop(float $timeout = 10, int $signal = null): ?int
{ {
@ -887,7 +887,7 @@ class Process implements \IteratorAggregate
} while ($this->isRunning() && microtime(true) < $timeoutMicro); } while ($this->isRunning() && microtime(true) < $timeoutMicro);
if ($this->isRunning()) { if ($this->isRunning()) {
// Avoid exception here: Process is supposed to be running, but it might have stopped just // Avoid exception here: process is supposed to be running, but it might have stopped just
// after this line. In any case, let's silently discard the error, we cannot do anything. // after this line. In any case, let's silently discard the error, we cannot do anything.
$this->doSignal($signal ?: 9, false); $this->doSignal($signal ?: 9, false);
} }
@ -950,7 +950,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Gets the Process timeout in seconds (max. runtime). * Gets the process timeout in seconds (max. runtime).
*/ */
public function getTimeout(): ?float public function getTimeout(): ?float
{ {
@ -958,7 +958,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Gets the Process idle timeout in seconds (max. time since last output). * Gets the process idle timeout in seconds (max. time since last output).
*/ */
public function getIdleTimeout(): ?float public function getIdleTimeout(): ?float
{ {
@ -966,7 +966,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Sets the Process timeout (max. runtime) in seconds. * Sets the process timeout (max. runtime) in seconds.
* *
* To disable the timeout, set this value to null. * To disable the timeout, set this value to null.
* *
@ -982,7 +982,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Sets the Process idle timeout (max. time since last output) in seconds. * Sets the process idle timeout (max. time since last output) in seconds.
* *
* To disable the timeout, set this value to null. * To disable the timeout, set this value to null.
* *
@ -1113,18 +1113,18 @@ class Process implements \IteratorAggregate
/** /**
* Sets the input. * Sets the input.
* *
* This content will be passed to the underlying Process standard input. * This content will be passed to the underlying process standard input.
* *
* @param string|int|float|bool|resource|\Traversable|null $input The content * @param string|int|float|bool|resource|\Traversable|null $input The content
* *
* @return $this * @return $this
* *
* @throws LogicException In case the Process is running * @throws LogicException In case the process is running
*/ */
public function setInput(mixed $input): static public function setInput(mixed $input): static
{ {
if ($this->isRunning()) { if ($this->isRunning()) {
throw new LogicException('Input cannot be set while the Process is running.'); throw new LogicException('Input cannot be set while the process is running.');
} }
$this->input = ProcessUtils::validateInput(__METHOD__, $input); $this->input = ProcessUtils::validateInput(__METHOD__, $input);
@ -1133,10 +1133,10 @@ class Process implements \IteratorAggregate
} }
/** /**
* Performs a check between the timeout definition and the time the Process started. * Performs a check between the timeout definition and the time the process started.
* *
* In case you run a background Process (with the start method), you should * In case you run a background process (with the start method), you should
* trigger this method regularly to ensure the Process timeout * trigger this method regularly to ensure the process timeout
* *
* @throws ProcessTimedOutException In case the timeout was reached * @throws ProcessTimedOutException In case the timeout was reached
*/ */
@ -1160,12 +1160,12 @@ class Process implements \IteratorAggregate
} }
/** /**
* @throws LogicException in case Process is not started * @throws LogicException in case process is not started
*/ */
public function getStartTime(): float public function getStartTime(): float
{ {
if (!$this->isStarted()) { if (!$this->isStarted()) {
throw new LogicException('Start time is only available after Process start.'); throw new LogicException('Start time is only available after process start.');
} }
return $this->starttime; return $this->starttime;
@ -1176,17 +1176,17 @@ class Process implements \IteratorAggregate
* *
* @see https://php.net/proc_open for the options supported by PHP. * @see https://php.net/proc_open for the options supported by PHP.
* *
* Enabling the "create_new_console" option allows a subProcess to continue * Enabling the "create_new_console" option allows a subprocess to continue
* to run after the main Process exited, on both Windows and *nix * to run after the main process exited, on both Windows and *nix
*/ */
public function setOptions(array $options) public function setOptions(array $options)
{ {
if ($this->isRunning()) { if ($this->isRunning()) {
throw new RuntimeException('Setting options while the Process is running is not possible.'); throw new RuntimeException('Setting options while the process is running is not possible.');
} }
$defaultOptions = $this->options; $defaultOptions = $this->options;
$existingOptions = ['blocking_pipes', 'create_Process_group', 'create_new_console']; $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console'];
foreach ($options as $key => $value) { foreach ($options as $key => $value) {
if (!\in_array($key, $existingOptions)) { if (!\in_array($key, $existingOptions)) {
@ -1204,11 +1204,7 @@ class Process implements \IteratorAggregate
{ {
static $isTtySupported; static $isTtySupported;
if (null === $isTtySupported) { return $isTtySupported ??= ('/' === \DIRECTORY_SEPARATOR && stream_isatty(\STDOUT));
$isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
}
return $isTtySupported;
} }
/** /**
@ -1238,12 +1234,12 @@ class Process implements \IteratorAggregate
$this->input->rewind(); $this->input->rewind();
} }
if ('\\' === \DIRECTORY_SEPARATOR) { if ('\\' === \DIRECTORY_SEPARATOR) {
$this->ProcessPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback); $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback);
} else { } else {
$this->ProcessPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback); $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback);
} }
return $this->ProcessPipes->getDescriptors(); return $this->processPipes->getDescriptors();
} }
/** /**
@ -1276,7 +1272,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Updates the status of the Process, reads pipes. * Updates the status of the process, reads pipes.
* *
* @param bool $blocking Whether to use a blocking read call * @param bool $blocking Whether to use a blocking read call
*/ */
@ -1286,13 +1282,13 @@ class Process implements \IteratorAggregate
return; return;
} }
$this->ProcessInformation = proc_get_status($this->Process); $this->processInformation = proc_get_status($this->process);
$running = $this->ProcessInformation['running']; $running = $this->processInformation['running'];
$this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running);
if ($this->fallbackStatus && $this->isSigchildEnabled()) { if ($this->fallbackStatus && $this->isSigchildEnabled()) {
$this->ProcessInformation = $this->fallbackStatus + $this->ProcessInformation; $this->processInformation = $this->fallbackStatus + $this->processInformation;
} }
if (!$running) { if (!$running) {
@ -1325,7 +1321,7 @@ class Process implements \IteratorAggregate
* @param string $caller The name of the method that needs fresh outputs * @param string $caller The name of the method that needs fresh outputs
* @param bool $blocking Whether to use blocking calls or not * @param bool $blocking Whether to use blocking calls or not
* *
* @throws LogicException in case output has been disabled or Process is not started * @throws LogicException in case output has been disabled or process is not started
*/ */
private function readPipesForOutput(string $caller, bool $blocking = false) private function readPipesForOutput(string $caller, bool $blocking = false)
{ {
@ -1364,7 +1360,7 @@ class Process implements \IteratorAggregate
*/ */
private function readPipes(bool $blocking, bool $close) private function readPipes(bool $blocking, bool $close)
{ {
$result = $this->ProcessPipes->readAndWrite($blocking, $close); $result = $this->processPipes->readAndWrite($blocking, $close);
$callback = $this->callback; $callback = $this->callback;
foreach ($result as $type => $data) { foreach ($result as $type => $data) {
@ -1377,26 +1373,26 @@ class Process implements \IteratorAggregate
} }
/** /**
* Closes Process resource, closes file handles, sets the exitcode. * Closes process resource, closes file handles, sets the exitcode.
* *
* @return int The exitcode * @return int The exitcode
*/ */
private function close(): int private function close(): int
{ {
$this->ProcessPipes->close(); $this->processPipes->close();
if (\is_resource($this->Process)) { if (\is_resource($this->process)) {
proc_close($this->Process); proc_close($this->process);
} }
$this->exitcode = $this->ProcessInformation['exitcode']; $this->exitcode = $this->processInformation['exitcode'];
$this->status = self::STATUS_TERMINATED; $this->status = self::STATUS_TERMINATED;
if (-1 === $this->exitcode) { if (-1 === $this->exitcode) {
if ($this->ProcessInformation['signaled'] && 0 < $this->ProcessInformation['termsig']) { if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
// if Process has been signaled, no exitcode but a valid termsig, apply Unix convention // if process has been signaled, no exitcode but a valid termsig, apply Unix convention
$this->exitcode = 128 + $this->ProcessInformation['termsig']; $this->exitcode = 128 + $this->processInformation['termsig'];
} elseif ($this->isSigchildEnabled()) { } elseif ($this->isSigchildEnabled()) {
$this->ProcessInformation['signaled'] = true; $this->processInformation['signaled'] = true;
$this->ProcessInformation['termsig'] = -1; $this->processInformation['termsig'] = -1;
} }
} }
@ -1409,7 +1405,7 @@ class Process implements \IteratorAggregate
} }
/** /**
* Resets data related to the latest run of the Process. * Resets data related to the latest run of the process.
*/ */
private function resetProcessData() private function resetProcessData()
{ {
@ -1417,10 +1413,10 @@ class Process implements \IteratorAggregate
$this->callback = null; $this->callback = null;
$this->exitcode = null; $this->exitcode = null;
$this->fallbackStatus = []; $this->fallbackStatus = [];
$this->ProcessInformation = null; $this->processInformation = null;
$this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+'); $this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
$this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+'); $this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'w+');
$this->Process = null; $this->process = null;
$this->latestSignal = null; $this->latestSignal = null;
$this->status = self::STATUS_READY; $this->status = self::STATUS_READY;
$this->incrementalOutputOffset = 0; $this->incrementalOutputOffset = 0;
@ -1428,20 +1424,20 @@ class Process implements \IteratorAggregate
} }
/** /**
* Sends a POSIX signal to the Process. * Sends a POSIX signal to the process.
* *
* @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants)
* @param bool $throwException Whether to throw exception in case signal failed * @param bool $throwException Whether to throw exception in case signal failed
* *
* @throws LogicException In case the Process is not running * @throws LogicException In case the process is not running
* @throws RuntimeException In case --enable-sigchild is activated and the Process can't be killed * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
* @throws RuntimeException In case of failure * @throws RuntimeException In case of failure
*/ */
private function doSignal(int $signal, bool $throwException): bool private function doSignal(int $signal, bool $throwException): bool
{ {
if (null === $pid = $this->getPid()) { if (null === $pid = $this->getPid()) {
if ($throwException) { if ($throwException) {
throw new LogicException('Cannot send signal on a non running Process.'); throw new LogicException('Cannot send signal on a non running process.');
} }
return false; return false;
@ -1451,14 +1447,14 @@ class Process implements \IteratorAggregate
exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
if ($exitCode && $this->isRunning()) { if ($exitCode && $this->isRunning()) {
if ($throwException) { if ($throwException) {
throw new RuntimeException(sprintf('Unable to kill the Process (%s).', implode(' ', $output))); throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
} }
return false; return false;
} }
} else { } else {
if (!$this->isSigchildEnabled()) { if (!$this->isSigchildEnabled()) {
$ok = @proc_terminate($this->Process, $signal); $ok = @proc_terminate($this->process, $signal);
} elseif (\function_exists('posix_kill')) { } elseif (\function_exists('posix_kill')) {
$ok = @posix_kill($pid, $signal); $ok = @posix_kill($pid, $signal);
} elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { } elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) {
@ -1520,7 +1516,7 @@ class Process implements \IteratorAggregate
); );
$cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; $cmd = 'cmd /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')';
foreach ($this->ProcessPipes->getFiles() as $offset => $filename) { foreach ($this->processPipes->getFiles() as $offset => $filename) {
$cmd .= ' '.$offset.'>"'.$filename.'"'; $cmd .= ' '.$offset.'>"'.$filename.'"';
} }
@ -1528,9 +1524,9 @@ class Process implements \IteratorAggregate
} }
/** /**
* Ensures the Process is running or terminated, throws a LogicException if the Process has a not started. * Ensures the process is running or terminated, throws a LogicException if the process has a not started.
* *
* @throws LogicException if the Process has not run * @throws LogicException if the process has not run
*/ */
private function requireProcessIsStarted(string $functionName) private function requireProcessIsStarted(string $functionName)
{ {
@ -1540,9 +1536,9 @@ class Process implements \IteratorAggregate
} }
/** /**
* Ensures the Process is terminated, throws a LogicException if the Process has a status different than "terminated". * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated".
* *
* @throws LogicException if the Process is not yet terminated * @throws LogicException if the process is not yet terminated
*/ */
private function requireProcessIsTerminated(string $functionName) private function requireProcessIsTerminated(string $functionName)
{ {

View file

@ -1,7 +1,7 @@
Process Component Process Component
================= =================
The Process component executes commands in sub-Processes. The Process component executes commands in sub-processes.
Sponsor Sponsor
------- -------
@ -17,7 +17,7 @@ Help Symfony by [sponsoring][3] its development!
Resources Resources
--------- ---------
* [Documentation](https://symfony.com/doc/current/components/Process.html) * [Documentation](https://symfony.com/doc/current/components/process.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and * [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls) [send Pull Requests](https://github.com/symfony/symfony/pulls)

View file

@ -1 +1 @@
6.1.3 6.2.5