update v 1.0.7.5
This commit is contained in:
@@ -28,10 +28,11 @@ class ProcessFailedException extends RuntimeException
|
||||
throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
|
||||
}
|
||||
|
||||
$error = sprintf('The command "%s" failed.'."\nExit Code: %s(%s)",
|
||||
$error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
|
||||
$process->getCommandLine(),
|
||||
$process->getExitCode(),
|
||||
$process->getExitCodeText()
|
||||
$process->getExitCodeText(),
|
||||
$process->getWorkingDirectory()
|
||||
);
|
||||
|
||||
if (!$process->isOutputDisabled()) {
|
@@ -56,7 +56,8 @@ class ExecutableFinder
|
||||
$searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir'));
|
||||
$dirs = array();
|
||||
foreach ($searchPath as $path) {
|
||||
if (is_dir($path)) {
|
||||
// Silencing against https://bugs.php.net/69240
|
||||
if (@is_dir($path)) {
|
||||
$dirs[] = $path;
|
||||
} else {
|
||||
if (basename($path) == $name && is_executable($path)) {
|
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2015 Fabien Potencier
|
||||
Copyright (c) 2004-2016 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
@@ -35,14 +35,17 @@ class PhpExecutableFinder
|
||||
*/
|
||||
public function find($includeArgs = true)
|
||||
{
|
||||
$args = $this->findArguments();
|
||||
$args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
|
||||
|
||||
// HHVM support
|
||||
if (defined('HHVM_VERSION')) {
|
||||
return (getenv('PHP_BINARY') ?: PHP_BINARY).($includeArgs ? ' '.implode(' ', $this->findArguments()) : '');
|
||||
return (getenv('PHP_BINARY') ?: PHP_BINARY).$args;
|
||||
}
|
||||
|
||||
// PHP_BINARY return the current sapi executable
|
||||
if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server')) && is_file(PHP_BINARY)) {
|
||||
return PHP_BINARY;
|
||||
if (PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg')) && is_file(PHP_BINARY)) {
|
||||
return PHP_BINARY.$args;
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PATH')) {
|
||||
@@ -76,9 +79,10 @@ class PhpExecutableFinder
|
||||
{
|
||||
$arguments = array();
|
||||
|
||||
// HHVM support
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$arguments[] = '--php';
|
||||
} elseif ('phpdbg' === PHP_SAPI) {
|
||||
$arguments[] = '-qrr';
|
||||
}
|
||||
|
||||
return $arguments;
|
@@ -21,36 +21,43 @@ use Symfony\Component\Process\Exception\RuntimeException;
|
||||
* print $p->getOutput()."\n";
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class PhpProcess extends Process
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $script The PHP script to run (as a string)
|
||||
* @param string $cwd The working directory
|
||||
* @param array $env The environment variables
|
||||
* @param int $timeout The timeout in seconds
|
||||
* @param array $options An array of options for proc_open
|
||||
*
|
||||
* @api
|
||||
* @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 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 array $options An array of options for proc_open
|
||||
*/
|
||||
public function __construct($script, $cwd = null, array $env = array(), $timeout = 60, array $options = array())
|
||||
public function __construct($script, $cwd = null, array $env = null, $timeout = 60, array $options = array())
|
||||
{
|
||||
$executableFinder = new PhpExecutableFinder();
|
||||
if (false === $php = $executableFinder->find()) {
|
||||
$php = null;
|
||||
}
|
||||
if ('phpdbg' === PHP_SAPI) {
|
||||
$file = tempnam(sys_get_temp_dir(), 'dbg');
|
||||
file_put_contents($file, $script);
|
||||
register_shutdown_function('unlink', $file);
|
||||
$php .= ' '.ProcessUtils::escapeArgument($file);
|
||||
$script = null;
|
||||
}
|
||||
if ('\\' !== DIRECTORY_SEPARATOR && null !== $php) {
|
||||
// exec is mandatory to deal with sending a signal to the process
|
||||
// see https://github.com/symfony/symfony/issues/5030 about prepending
|
||||
// command with exec
|
||||
$php = 'exec '.$php;
|
||||
}
|
||||
|
||||
parent::__construct($php, $cwd, $env, $script, $timeout, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path to the PHP binary to use.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setPhpBinary($php)
|
||||
{
|
||||
@@ -60,7 +67,7 @@ class PhpProcess extends Process
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function start($callback = null)
|
||||
public function start(callable $callback = null)
|
||||
{
|
||||
if (null === $this->getCommandLine()) {
|
||||
throw new RuntimeException('Unable to find the PHP executable.');
|
143
vendor/symfony/process/Pipes/AbstractPipes.php
vendored
Normal file
143
vendor/symfony/process/Pipes/AbstractPipes.php
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Pipes;
|
||||
|
||||
/**
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractPipes implements PipesInterface
|
||||
{
|
||||
/** @var array */
|
||||
public $pipes = array();
|
||||
|
||||
/** @var string */
|
||||
private $inputBuffer = '';
|
||||
/** @var resource|null */
|
||||
private $input;
|
||||
/** @var bool */
|
||||
private $blocked = true;
|
||||
|
||||
public function __construct($input)
|
||||
{
|
||||
if (is_resource($input)) {
|
||||
$this->input = $input;
|
||||
} elseif (is_string($input)) {
|
||||
$this->inputBuffer = $input;
|
||||
} else {
|
||||
$this->inputBuffer = (string) $input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
foreach ($this->pipes as $pipe) {
|
||||
fclose($pipe);
|
||||
}
|
||||
$this->pipes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a system call has been interrupted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasSystemCallBeenInterrupted()
|
||||
{
|
||||
$lastError = error_get_last();
|
||||
|
||||
// stream_select returns false when the `select` system call is interrupted by an incoming signal
|
||||
return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks streams.
|
||||
*/
|
||||
protected function unblock()
|
||||
{
|
||||
if (!$this->blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->pipes as $pipe) {
|
||||
stream_set_blocking($pipe, 0);
|
||||
}
|
||||
if (null !== $this->input) {
|
||||
stream_set_blocking($this->input, 0);
|
||||
}
|
||||
|
||||
$this->blocked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes input to stdin.
|
||||
*/
|
||||
protected function write()
|
||||
{
|
||||
if (!isset($this->pipes[0])) {
|
||||
return;
|
||||
}
|
||||
$input = $this->input;
|
||||
$r = $e = array();
|
||||
$w = array($this->pipes[0]);
|
||||
|
||||
// let's have a look if something changed in streams
|
||||
if (false === $n = @stream_select($r, $w, $e, 0, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($w as $stdin) {
|
||||
if (isset($this->inputBuffer[0])) {
|
||||
$written = fwrite($stdin, $this->inputBuffer);
|
||||
$this->inputBuffer = substr($this->inputBuffer, $written);
|
||||
if (isset($this->inputBuffer[0])) {
|
||||
return array($this->pipes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($input) {
|
||||
for (;;) {
|
||||
$data = fread($input, self::CHUNK_SIZE);
|
||||
if (!isset($data[0])) {
|
||||
break;
|
||||
}
|
||||
$written = fwrite($stdin, $data);
|
||||
$data = substr($data, $written);
|
||||
if (isset($data[0])) {
|
||||
$this->inputBuffer = $data;
|
||||
|
||||
return array($this->pipes[0]);
|
||||
}
|
||||
}
|
||||
if (feof($input)) {
|
||||
// no more data to read on input resource
|
||||
// use an empty buffer in the next reads
|
||||
$this->input = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no input to read on resource, buffer is empty
|
||||
if (null === $this->input && !isset($this->inputBuffer[0])) {
|
||||
fclose($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
}
|
||||
|
||||
if (!$w) {
|
||||
return array($this->pipes[0]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,11 +35,7 @@ class UnixPipes extends AbstractPipes
|
||||
$this->ptyMode = (bool) $ptyMode;
|
||||
$this->disableOutput = (bool) $disableOutput;
|
||||
|
||||
if (is_resource($input)) {
|
||||
$this->input = $input;
|
||||
} else {
|
||||
$this->inputBuffer = (string) $input;
|
||||
}
|
||||
parent::__construct($input);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
@@ -98,36 +94,15 @@ class UnixPipes extends AbstractPipes
|
||||
*/
|
||||
public function readAndWrite($blocking, $close = false)
|
||||
{
|
||||
// only stdin is left open, job has been done !
|
||||
// we can now close it
|
||||
if (1 === count($this->pipes) && array(0) === array_keys($this->pipes)) {
|
||||
fclose($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
}
|
||||
|
||||
if (empty($this->pipes)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$this->unblock();
|
||||
$w = $this->write();
|
||||
|
||||
$read = array();
|
||||
|
||||
if (null !== $this->input) {
|
||||
// if input is a resource, let's add it to stream_select argument to
|
||||
// fill a buffer
|
||||
$r = array_merge($this->pipes, array('input' => $this->input));
|
||||
} else {
|
||||
$r = $this->pipes;
|
||||
}
|
||||
// discard read on stdin
|
||||
$read = $e = array();
|
||||
$r = $this->pipes;
|
||||
unset($r[0]);
|
||||
|
||||
$w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
|
||||
$e = null;
|
||||
|
||||
// let's have a look if something changed in streams
|
||||
if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
|
||||
if (($r || $w) && false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
|
||||
// if a system call has been interrupted, forget about it, let's try again
|
||||
// otherwise, an error occurred, let's reset pipes
|
||||
if (!$this->hasSystemCallBeenInterrupted()) {
|
||||
@@ -137,55 +112,24 @@ class UnixPipes extends AbstractPipes
|
||||
return $read;
|
||||
}
|
||||
|
||||
// nothing has changed
|
||||
if (0 === $n) {
|
||||
return $read;
|
||||
}
|
||||
|
||||
foreach ($r as $pipe) {
|
||||
// prior PHP 5.4 the array passed to stream_select is modified and
|
||||
// lose key association, we have to find back the key
|
||||
$type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input';
|
||||
$data = '';
|
||||
while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {
|
||||
$data .= $dataread;
|
||||
$read[$type = array_search($pipe, $this->pipes, true)] = '';
|
||||
|
||||
do {
|
||||
$data = fread($pipe, self::CHUNK_SIZE);
|
||||
$read[$type] .= $data;
|
||||
} while (isset($data[0]));
|
||||
|
||||
if (!isset($read[$type][0])) {
|
||||
unset($read[$type]);
|
||||
}
|
||||
|
||||
if ('' !== $data) {
|
||||
if ($type === 'input') {
|
||||
$this->inputBuffer .= $data;
|
||||
} else {
|
||||
$read[$type] = $data;
|
||||
}
|
||||
if ($close && feof($pipe)) {
|
||||
fclose($pipe);
|
||||
unset($this->pipes[$type]);
|
||||
}
|
||||
|
||||
if (false === $data || (true === $close && feof($pipe) && '' === $data)) {
|
||||
if ($type === 'input') {
|
||||
// no more data to read on input resource
|
||||
// use an empty buffer in the next reads
|
||||
$this->input = null;
|
||||
} else {
|
||||
fclose($this->pipes[$type]);
|
||||
unset($this->pipes[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $w && 0 < count($w)) {
|
||||
while (strlen($this->inputBuffer)) {
|
||||
$written = fwrite($w[0], $this->inputBuffer, 2 << 18); // write 512k
|
||||
if ($written > 0) {
|
||||
$this->inputBuffer = (string) substr($this->inputBuffer, $written);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no input to read on resource, buffer is empty and stdin still open
|
||||
if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
|
||||
fclose($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
}
|
||||
|
||||
return $read;
|
||||
@@ -200,7 +144,7 @@ class UnixPipes extends AbstractPipes
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UnixPipes instance
|
||||
* Creates a new UnixPipes instance.
|
||||
*
|
||||
* @param Process $process
|
||||
* @param string|resource $input
|
@@ -48,22 +48,17 @@ class WindowsPipes extends AbstractPipes
|
||||
//
|
||||
// @see https://bugs.php.net/bug.php?id=51800
|
||||
$this->files = array(
|
||||
Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'),
|
||||
Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'),
|
||||
Process::STDOUT => tempnam(sys_get_temp_dir(), 'out_sf_proc'),
|
||||
Process::STDERR => tempnam(sys_get_temp_dir(), 'err_sf_proc'),
|
||||
);
|
||||
foreach ($this->files as $offset => $file) {
|
||||
$this->fileHandles[$offset] = fopen($this->files[$offset], 'rb');
|
||||
if (false === $this->fileHandles[$offset]) {
|
||||
if (false === $file || false === $this->fileHandles[$offset] = @fopen($file, 'rb')) {
|
||||
throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_resource($input)) {
|
||||
$this->input = $input;
|
||||
} else {
|
||||
$this->inputBuffer = $input;
|
||||
}
|
||||
parent::__construct($input);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
@@ -110,28 +105,26 @@ class WindowsPipes extends AbstractPipes
|
||||
*/
|
||||
public function readAndWrite($blocking, $close = false)
|
||||
{
|
||||
$this->write($blocking, $close);
|
||||
$this->unblock();
|
||||
$w = $this->write();
|
||||
$read = $r = $e = array();
|
||||
|
||||
$read = array();
|
||||
$fh = $this->fileHandles;
|
||||
foreach ($fh as $type => $fileHandle) {
|
||||
if (0 !== fseek($fileHandle, $this->readBytes[$type])) {
|
||||
continue;
|
||||
if ($blocking) {
|
||||
if ($w) {
|
||||
@stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
|
||||
} elseif ($this->fileHandles) {
|
||||
usleep(Process::TIMEOUT_PRECISION * 1E6);
|
||||
}
|
||||
$data = '';
|
||||
$dataread = null;
|
||||
while (!feof($fileHandle)) {
|
||||
if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) {
|
||||
$data .= $dataread;
|
||||
}
|
||||
}
|
||||
if (0 < $length = strlen($data)) {
|
||||
$this->readBytes[$type] += $length;
|
||||
}
|
||||
foreach ($this->fileHandles as $type => $fileHandle) {
|
||||
$data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
|
||||
|
||||
if (isset($data[0])) {
|
||||
$this->readBytes[$type] += strlen($data);
|
||||
$read[$type] = $data;
|
||||
}
|
||||
|
||||
if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) {
|
||||
fclose($this->fileHandles[$type]);
|
||||
if ($close) {
|
||||
fclose($fileHandle);
|
||||
unset($this->fileHandles[$type]);
|
||||
}
|
||||
}
|
||||
@@ -144,7 +137,7 @@ class WindowsPipes extends AbstractPipes
|
||||
*/
|
||||
public function areOpen()
|
||||
{
|
||||
return (bool) $this->pipes && (bool) $this->fileHandles;
|
||||
return $this->pipes && $this->fileHandles;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +166,7 @@ class WindowsPipes extends AbstractPipes
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes temporary files
|
||||
* Removes temporary files.
|
||||
*/
|
||||
private function removeFiles()
|
||||
{
|
||||
@@ -184,71 +177,4 @@ class WindowsPipes extends AbstractPipes
|
||||
}
|
||||
$this->files = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes input to stdin
|
||||
*
|
||||
* @param bool $blocking
|
||||
* @param bool $close
|
||||
*/
|
||||
private function write($blocking, $close)
|
||||
{
|
||||
if (empty($this->pipes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->unblock();
|
||||
|
||||
$r = null !== $this->input ? array('input' => $this->input) : null;
|
||||
$w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
|
||||
$e = null;
|
||||
|
||||
// let's have a look if something changed in streams
|
||||
if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
|
||||
// if a system call has been interrupted, forget about it, let's try again
|
||||
// otherwise, an error occurred, let's reset pipes
|
||||
if (!$this->hasSystemCallBeenInterrupted()) {
|
||||
$this->pipes = array();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// nothing has changed
|
||||
if (0 === $n) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $w && 0 < count($r)) {
|
||||
$data = '';
|
||||
while ($dataread = fread($r['input'], self::CHUNK_SIZE)) {
|
||||
$data .= $dataread;
|
||||
}
|
||||
|
||||
$this->inputBuffer .= $data;
|
||||
|
||||
if (false === $data || (true === $close && feof($r['input']) && '' === $data)) {
|
||||
// no more data to read on input resource
|
||||
// use an empty buffer in the next reads
|
||||
$this->input = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $w && 0 < count($w)) {
|
||||
while (strlen($this->inputBuffer)) {
|
||||
$written = fwrite($w[0], $this->inputBuffer, 2 << 18);
|
||||
if ($written > 0) {
|
||||
$this->inputBuffer = (string) substr($this->inputBuffer, $written);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no input to read on resource, buffer is empty and stdin still open
|
||||
if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
|
||||
fclose($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -26,8 +26,6 @@ use Symfony\Component\Process\Pipes\WindowsPipes;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Process
|
||||
{
|
||||
@@ -56,7 +54,7 @@ class Process
|
||||
private $idleTimeout;
|
||||
private $options;
|
||||
private $exitcode;
|
||||
private $fallbackExitcode;
|
||||
private $fallbackStatus = array();
|
||||
private $processInformation;
|
||||
private $outputDisabled = false;
|
||||
private $stdout;
|
||||
@@ -133,14 +131,12 @@ class Process
|
||||
*
|
||||
* @param string $commandline The command line to run
|
||||
* @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 inherit
|
||||
* @param array|null $env The environment variables or null to use the same environment as the current PHP process
|
||||
* @param string|null $input The input
|
||||
* @param int|float|null $timeout The timeout in seconds or null to disable
|
||||
* @param array $options An array of options for proc_open
|
||||
*
|
||||
* @throws RuntimeException When proc_open is not installed
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
|
||||
{
|
||||
@@ -162,7 +158,7 @@ class Process
|
||||
$this->setEnv($env);
|
||||
}
|
||||
|
||||
$this->input = $input;
|
||||
$this->setInput($input);
|
||||
$this->setTimeout($timeout);
|
||||
$this->useFileHandles = '\\' === DIRECTORY_SEPARATOR;
|
||||
$this->pty = false;
|
||||
@@ -173,8 +169,7 @@ class Process
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// stop() will check if we have a process running.
|
||||
$this->stop();
|
||||
$this->stop(0);
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
@@ -200,8 +195,6 @@ class Process
|
||||
* @throws RuntimeException When process can't be launched
|
||||
* @throws RuntimeException When process stopped after receiving signal
|
||||
* @throws LogicException In case a callback is provided and output has been disabled
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function run($callback = null)
|
||||
{
|
||||
@@ -223,9 +216,9 @@ class Process
|
||||
* @throws RuntimeException if PHP was compiled with --enable-sigchild and the enhanced sigchild compatibility mode is not enabled
|
||||
* @throws ProcessFailedException if the process didn't terminate successfully
|
||||
*/
|
||||
public function mustRun($callback = null)
|
||||
public function mustRun(callable $callback = null)
|
||||
{
|
||||
if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {
|
||||
if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
|
||||
}
|
||||
|
||||
@@ -247,9 +240,6 @@ class Process
|
||||
* 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.
|
||||
* It allows to have feedback from the independent process during execution.
|
||||
* If there is no callback passed, the wait() method can be called
|
||||
* with true as a second parameter then the callback will get all data occurred
|
||||
* in (and since) the start call.
|
||||
*
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
@@ -258,7 +248,7 @@ class Process
|
||||
* @throws RuntimeException When process is already running
|
||||
* @throws LogicException In case a callback is provided and output has been disabled
|
||||
*/
|
||||
public function start($callback = null)
|
||||
public function start(callable $callback = null)
|
||||
{
|
||||
if ($this->isRunning()) {
|
||||
throw new RuntimeException('Process is already running');
|
||||
@@ -275,7 +265,7 @@ class Process
|
||||
$commandline = $this->commandline;
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
|
||||
$commandline = 'cmd /V:ON /E:ON /C "('.$commandline.')';
|
||||
$commandline = 'cmd /V:ON /E:ON /D /C "('.$commandline.')';
|
||||
foreach ($this->processPipes->getFiles() as $offset => $filename) {
|
||||
$commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
|
||||
}
|
||||
@@ -284,6 +274,17 @@ class Process
|
||||
if (!isset($this->options['bypass_shell'])) {
|
||||
$this->options['bypass_shell'] = true;
|
||||
}
|
||||
} elseif (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
|
||||
$descriptors[3] = array('pipe', 'w');
|
||||
|
||||
// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
|
||||
$commandline = '{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
|
||||
$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
|
||||
|
||||
// Workaround for the bug, when PTS functionality is enabled.
|
||||
// @see : https://bugs.php.net/69442
|
||||
$ptsWorkaround = fopen(__FILE__, 'r');
|
||||
}
|
||||
|
||||
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
|
||||
@@ -293,6 +294,10 @@ class Process
|
||||
}
|
||||
$this->status = self::STATUS_STARTED;
|
||||
|
||||
if (isset($descriptors[3])) {
|
||||
$this->fallbackStatus['pid'] = (int) fgets($this->processPipes->pipes[3]);
|
||||
}
|
||||
|
||||
if ($this->tty) {
|
||||
return;
|
||||
}
|
||||
@@ -316,7 +321,7 @@ class Process
|
||||
*
|
||||
* @see start()
|
||||
*/
|
||||
public function restart($callback = null)
|
||||
public function restart(callable $callback = null)
|
||||
{
|
||||
if ($this->isRunning()) {
|
||||
throw new RuntimeException('Process is already running');
|
||||
@@ -343,7 +348,7 @@ class Process
|
||||
* @throws RuntimeException When process stopped after receiving signal
|
||||
* @throws LogicException When process is not yet started
|
||||
*/
|
||||
public function wait($callback = null)
|
||||
public function wait(callable $callback = null)
|
||||
{
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
@@ -355,8 +360,7 @@ class Process
|
||||
do {
|
||||
$this->checkTimeout();
|
||||
$running = '\\' === DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
|
||||
$close = '\\' !== DIRECTORY_SEPARATOR || !$running;
|
||||
$this->readPipes(true, $close);
|
||||
$this->readPipes($running, '\\' !== DIRECTORY_SEPARATOR || !$running);
|
||||
} while ($running);
|
||||
|
||||
while ($this->isRunning()) {
|
||||
@@ -374,17 +378,9 @@ class Process
|
||||
* Returns the Pid (process identifier), if applicable.
|
||||
*
|
||||
* @return int|null The process id if running, null otherwise
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
*/
|
||||
public function getPid()
|
||||
{
|
||||
if ($this->isSigchildEnabled()) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.');
|
||||
}
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->isRunning() ? $this->processInformation['pid'] : null;
|
||||
}
|
||||
|
||||
@@ -396,7 +392,7 @@ class Process
|
||||
* @return Process
|
||||
*
|
||||
* @throws LogicException In case the process is not running
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
* @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
|
||||
* @throws RuntimeException In case of failure
|
||||
*/
|
||||
public function signal($signal)
|
||||
@@ -463,20 +459,16 @@ class Process
|
||||
*
|
||||
* @throws LogicException in case the output has been disabled
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
if ($this->outputDisabled) {
|
||||
throw new LogicException('Output has been disabled.');
|
||||
$this->readPipesForOutput(__FUNCTION__);
|
||||
|
||||
if (false === $ret = stream_get_contents($this->stdout, -1, 0)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true);
|
||||
|
||||
return $this->stdout;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,25 +477,22 @@ class Process
|
||||
* In comparison with the getOutput method which always return the whole
|
||||
* output, this one returns the new output since the last call.
|
||||
*
|
||||
* @return string The process output since the last call
|
||||
*
|
||||
* @throws LogicException in case the output has been disabled
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @return string The process output since the last call
|
||||
*/
|
||||
public function getIncrementalOutput()
|
||||
{
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
$this->readPipesForOutput(__FUNCTION__);
|
||||
|
||||
$data = $this->getOutput();
|
||||
|
||||
$latest = substr($data, $this->incrementalOutputOffset);
|
||||
$latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
|
||||
$this->incrementalOutputOffset = ftell($this->stdout);
|
||||
|
||||
if (false === $latest) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->incrementalOutputOffset = strlen($data);
|
||||
|
||||
return $latest;
|
||||
}
|
||||
|
||||
@@ -514,7 +503,8 @@ class Process
|
||||
*/
|
||||
public function clearOutput()
|
||||
{
|
||||
$this->stdout = '';
|
||||
ftruncate($this->stdout, 0);
|
||||
fseek($this->stdout, 0);
|
||||
$this->incrementalOutputOffset = 0;
|
||||
|
||||
return $this;
|
||||
@@ -527,20 +517,16 @@ class Process
|
||||
*
|
||||
* @throws LogicException in case the output has been disabled
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getErrorOutput()
|
||||
{
|
||||
if ($this->outputDisabled) {
|
||||
throw new LogicException('Output has been disabled.');
|
||||
$this->readPipesForOutput(__FUNCTION__);
|
||||
|
||||
if (false === $ret = stream_get_contents($this->stderr, -1, 0)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
|
||||
$this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true);
|
||||
|
||||
return $this->stderr;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -550,25 +536,22 @@ class Process
|
||||
* whole error output, this one returns the new error output since the last
|
||||
* call.
|
||||
*
|
||||
* @return string The process error output since the last call
|
||||
*
|
||||
* @throws LogicException in case the output has been disabled
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @return string The process error output since the last call
|
||||
*/
|
||||
public function getIncrementalErrorOutput()
|
||||
{
|
||||
$this->requireProcessIsStarted(__FUNCTION__);
|
||||
$this->readPipesForOutput(__FUNCTION__);
|
||||
|
||||
$data = $this->getErrorOutput();
|
||||
|
||||
$latest = substr($data, $this->incrementalErrorOutputOffset);
|
||||
$latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
|
||||
$this->incrementalErrorOutputOffset = ftell($this->stderr);
|
||||
|
||||
if (false === $latest) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$this->incrementalErrorOutputOffset = strlen($data);
|
||||
|
||||
return $latest;
|
||||
}
|
||||
|
||||
@@ -579,7 +562,8 @@ class Process
|
||||
*/
|
||||
public function clearErrorOutput()
|
||||
{
|
||||
$this->stderr = '';
|
||||
ftruncate($this->stderr, 0);
|
||||
fseek($this->stderr, 0);
|
||||
$this->incrementalErrorOutputOffset = 0;
|
||||
|
||||
return $this;
|
||||
@@ -591,12 +575,10 @@ class Process
|
||||
* @return null|int The exit status code, null if the Process is not terminated
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getExitCode()
|
||||
{
|
||||
if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {
|
||||
if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
|
||||
}
|
||||
|
||||
@@ -613,8 +595,6 @@ class Process
|
||||
*
|
||||
* @return null|string A string representation for the exit status code, null if the Process is not terminated.
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated and the sigchild compatibility mode is disabled
|
||||
*
|
||||
* @see http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
* @see http://en.wikipedia.org/wiki/Unix_signal
|
||||
*/
|
||||
@@ -631,8 +611,6 @@ class Process
|
||||
* Checks if the process ended successfully.
|
||||
*
|
||||
* @return bool true if the process ended successfully, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isSuccessful()
|
||||
{
|
||||
@@ -648,19 +626,15 @@ class Process
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
* @throws LogicException In case the process is not terminated
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasBeenSignaled()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
if ($this->isSigchildEnabled()) {
|
||||
if (!$this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
|
||||
}
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->processInformation['signaled'];
|
||||
}
|
||||
|
||||
@@ -673,19 +647,15 @@ class Process
|
||||
*
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
* @throws LogicException In case the process is not terminated
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getTermSignal()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
if ($this->isSigchildEnabled()) {
|
||||
if ($this->isSigchildEnabled() && (!$this->enhanceSigchildCompatibility || -1 === $this->processInformation['termsig'])) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
|
||||
}
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->processInformation['termsig'];
|
||||
}
|
||||
|
||||
@@ -697,15 +667,11 @@ class Process
|
||||
* @return bool
|
||||
*
|
||||
* @throws LogicException In case the process is not terminated
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasBeenStopped()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->processInformation['stopped'];
|
||||
}
|
||||
|
||||
@@ -717,15 +683,11 @@ class Process
|
||||
* @return int
|
||||
*
|
||||
* @throws LogicException In case the process is not terminated
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getStopSignal()
|
||||
{
|
||||
$this->requireProcessIsTerminated(__FUNCTION__);
|
||||
|
||||
$this->updateStatus(false);
|
||||
|
||||
return $this->processInformation['stopsig'];
|
||||
}
|
||||
|
||||
@@ -785,41 +747,33 @@ class Process
|
||||
* Stops the process.
|
||||
*
|
||||
* @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
|
||||
* @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9)
|
||||
*
|
||||
* @return int The exit-code of the process
|
||||
*
|
||||
* @throws RuntimeException if the process got signaled
|
||||
*/
|
||||
public function stop($timeout = 10, $signal = null)
|
||||
{
|
||||
$timeoutMicro = microtime(true) + $timeout;
|
||||
if ($this->isRunning()) {
|
||||
if ('\\' === DIRECTORY_SEPARATOR && !$this->isSigchildEnabled()) {
|
||||
exec(sprintf('taskkill /F /T /PID %d 2>&1', $this->getPid()), $output, $exitCode);
|
||||
if ($exitCode > 0) {
|
||||
throw new RuntimeException('Unable to kill the process');
|
||||
}
|
||||
}
|
||||
// given `SIGTERM` may not be defined and that `proc_terminate` uses the constant value and not the constant itself, we use the same here
|
||||
$this->doSignal(15, false);
|
||||
do {
|
||||
usleep(1000);
|
||||
} while ($this->isRunning() && microtime(true) < $timeoutMicro);
|
||||
|
||||
if ($this->isRunning() && !$this->isSigchildEnabled()) {
|
||||
if (null !== $signal || defined('SIGKILL')) {
|
||||
// avoid exception here :
|
||||
// process is supposed to be running, but it might have stop
|
||||
// just after this line.
|
||||
// in any case, let's silently discard the error, we can not do anything
|
||||
$this->doSignal($signal ?: SIGKILL, false);
|
||||
}
|
||||
if ($this->isRunning()) {
|
||||
// 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.
|
||||
$this->doSignal($signal ?: 9, false);
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateStatus(false);
|
||||
if ($this->processInformation['running']) {
|
||||
if ($this->isRunning()) {
|
||||
if (isset($this->fallbackStatus['pid'])) {
|
||||
unset($this->fallbackStatus['pid']);
|
||||
|
||||
return $this->stop(0, $signal);
|
||||
}
|
||||
$this->close();
|
||||
}
|
||||
|
||||
@@ -829,23 +783,33 @@ class Process
|
||||
/**
|
||||
* Adds a line to the STDOUT stream.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $line The line to append
|
||||
*/
|
||||
public function addOutput($line)
|
||||
{
|
||||
$this->lastOutputTime = microtime(true);
|
||||
$this->stdout .= $line;
|
||||
|
||||
fseek($this->stdout, 0, SEEK_END);
|
||||
fwrite($this->stdout, $line);
|
||||
fseek($this->stdout, $this->incrementalOutputOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a line to the STDERR stream.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $line The line to append
|
||||
*/
|
||||
public function addErrorOutput($line)
|
||||
{
|
||||
$this->lastOutputTime = microtime(true);
|
||||
$this->stderr .= $line;
|
||||
|
||||
fseek($this->stderr, 0, SEEK_END);
|
||||
fwrite($this->stderr, $line);
|
||||
fseek($this->stderr, $this->incrementalErrorOutputOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1052,25 +1016,12 @@ class Process
|
||||
|
||||
$this->env = array();
|
||||
foreach ($env as $key => $value) {
|
||||
$this->env[(binary) $key] = (binary) $value;
|
||||
$this->env[$key] = (string) $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contents of STDIN.
|
||||
*
|
||||
* @return string|null The current contents
|
||||
*
|
||||
* @deprecated Deprecated since version 2.5, to be removed in 3.0.
|
||||
* This method is deprecated in favor of getInput.
|
||||
*/
|
||||
public function getStdin()
|
||||
{
|
||||
return $this->getInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Process input.
|
||||
*
|
||||
@@ -1081,30 +1032,12 @@ class Process
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the contents of STDIN.
|
||||
*
|
||||
* @param string|null $stdin The new contents
|
||||
*
|
||||
* @return self The current Process instance
|
||||
*
|
||||
* @deprecated Deprecated since version 2.5, to be removed in 3.0.
|
||||
* This method is deprecated in favor of setInput.
|
||||
*
|
||||
* @throws LogicException In case the process is running
|
||||
* @throws InvalidArgumentException In case the argument is invalid
|
||||
*/
|
||||
public function setStdin($stdin)
|
||||
{
|
||||
return $this->setInput($stdin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input.
|
||||
*
|
||||
* This content will be passed to the underlying process standard input.
|
||||
*
|
||||
* @param string|null $input The content
|
||||
* @param mixed $input The content
|
||||
*
|
||||
* @return self The current Process instance
|
||||
*
|
||||
@@ -1116,7 +1049,7 @@ class Process
|
||||
throw new LogicException('Input can not be set while the process is running.');
|
||||
}
|
||||
|
||||
$this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
|
||||
$this->input = ProcessUtils::validateInput(__METHOD__, $input);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -1243,14 +1176,7 @@ class Process
|
||||
return $result = false;
|
||||
}
|
||||
|
||||
$proc = @proc_open('echo 1', array(array('pty'), array('pty'), array('pty')), $pipes);
|
||||
if (is_resource($proc)) {
|
||||
proc_close($proc);
|
||||
|
||||
return $result = true;
|
||||
}
|
||||
|
||||
return $result = false;
|
||||
return $result = (bool) @proc_open('echo 1', array(array('pty'), array('pty'), array('pty')), $pipes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1265,16 +1191,8 @@ class Process
|
||||
} else {
|
||||
$this->processPipes = UnixPipes::create($this, $this->input);
|
||||
}
|
||||
$descriptors = $this->processPipes->getDescriptors($this->outputDisabled);
|
||||
|
||||
if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
|
||||
$descriptors = array_merge($descriptors, array(array('pipe', 'w')));
|
||||
|
||||
$this->commandline = '('.$this->commandline.') 3>/dev/null; code=$?; echo $code >&3; exit $code';
|
||||
}
|
||||
|
||||
return $descriptors;
|
||||
return $this->processPipes->getDescriptors();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1285,17 +1203,16 @@ class Process
|
||||
*
|
||||
* @param callable|null $callback The user defined PHP callback
|
||||
*
|
||||
* @return callable A PHP callable
|
||||
* @return \Closure A PHP closure
|
||||
*/
|
||||
protected function buildCallback($callback)
|
||||
{
|
||||
$that = $this;
|
||||
$out = self::OUT;
|
||||
$callback = function ($type, $data) use ($that, $callback, $out) {
|
||||
$callback = function ($type, $data) use ($callback, $out) {
|
||||
if ($out == $type) {
|
||||
$that->addOutput($data);
|
||||
$this->addOutput($data);
|
||||
} else {
|
||||
$that->addErrorOutput($data);
|
||||
$this->addErrorOutput($data);
|
||||
}
|
||||
|
||||
if (null !== $callback) {
|
||||
@@ -1318,11 +1235,15 @@ class Process
|
||||
}
|
||||
|
||||
$this->processInformation = proc_get_status($this->process);
|
||||
$this->captureExitCode();
|
||||
$running = $this->processInformation['running'];
|
||||
|
||||
$this->readPipes($blocking, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true);
|
||||
$this->readPipes($running && $blocking, '\\' !== DIRECTORY_SEPARATOR || !$running);
|
||||
|
||||
if (!$this->processInformation['running']) {
|
||||
if ($this->fallbackStatus && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
$this->processInformation = $this->fallbackStatus + $this->processInformation;
|
||||
}
|
||||
|
||||
if (!$running) {
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
@@ -1338,7 +1259,7 @@ class Process
|
||||
return self::$sigchild;
|
||||
}
|
||||
|
||||
if (!function_exists('phpinfo')) {
|
||||
if (!function_exists('phpinfo') || defined('HHVM_VERSION')) {
|
||||
return self::$sigchild = false;
|
||||
}
|
||||
|
||||
@@ -1348,6 +1269,24 @@ class Process
|
||||
return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads pipes for the freshest output.
|
||||
*
|
||||
* @param $caller The name of the method that needs fresh outputs
|
||||
*
|
||||
* @throws LogicException in case output has been disabled or process is not started
|
||||
*/
|
||||
private function readPipesForOutput($caller)
|
||||
{
|
||||
if ($this->outputDisabled) {
|
||||
throw new LogicException('Output has been disabled.');
|
||||
}
|
||||
|
||||
$this->requireProcessIsStarted($caller);
|
||||
|
||||
$this->updateStatus(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and returns the filtered timeout.
|
||||
*
|
||||
@@ -1382,24 +1321,14 @@ class Process
|
||||
|
||||
$callback = $this->callback;
|
||||
foreach ($result as $type => $data) {
|
||||
if (3 == $type) {
|
||||
$this->fallbackExitcode = (int) $data;
|
||||
} else {
|
||||
if (3 !== $type) {
|
||||
$callback($type === self::STDOUT ? self::OUT : self::ERR, $data);
|
||||
} elseif (!isset($this->fallbackStatus['signaled'])) {
|
||||
$this->fallbackStatus['exitcode'] = (int) $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the exitcode if mentioned in the process information.
|
||||
*/
|
||||
private function captureExitCode()
|
||||
{
|
||||
if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) {
|
||||
$this->exitcode = $this->processInformation['exitcode'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes process resource, closes file handles, sets the exitcode.
|
||||
*
|
||||
@@ -1409,21 +1338,26 @@ class Process
|
||||
{
|
||||
$this->processPipes->close();
|
||||
if (is_resource($this->process)) {
|
||||
$exitcode = proc_close($this->process);
|
||||
} else {
|
||||
$exitcode = -1;
|
||||
proc_close($this->process);
|
||||
}
|
||||
|
||||
$this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1);
|
||||
$this->exitcode = $this->processInformation['exitcode'];
|
||||
$this->status = self::STATUS_TERMINATED;
|
||||
|
||||
if (-1 === $this->exitcode && null !== $this->fallbackExitcode) {
|
||||
$this->exitcode = $this->fallbackExitcode;
|
||||
} elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
|
||||
// if process has been signaled, no exitcode but a valid termsig, apply Unix convention
|
||||
$this->exitcode = 128 + $this->processInformation['termsig'];
|
||||
if (-1 === $this->exitcode) {
|
||||
if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
|
||||
// if process has been signaled, no exitcode but a valid termsig, apply Unix convention
|
||||
$this->exitcode = 128 + $this->processInformation['termsig'];
|
||||
} elseif ($this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
|
||||
$this->processInformation['signaled'] = true;
|
||||
$this->processInformation['termsig'] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory from self-reference callback created by buildCallback
|
||||
// Doing so in other contexts like __destruct or by garbage collector is ineffective
|
||||
// Now pipes are closed, so the callback is no longer necessary
|
||||
$this->callback = null;
|
||||
|
||||
return $this->exitcode;
|
||||
}
|
||||
|
||||
@@ -1435,10 +1369,10 @@ class Process
|
||||
$this->starttime = null;
|
||||
$this->callback = null;
|
||||
$this->exitcode = null;
|
||||
$this->fallbackExitcode = null;
|
||||
$this->fallbackStatus = array();
|
||||
$this->processInformation = null;
|
||||
$this->stdout = null;
|
||||
$this->stderr = null;
|
||||
$this->stdout = fopen('php://temp/maxmemory:'.(1024 * 1024), 'wb+');
|
||||
$this->stderr = fopen('php://temp/maxmemory:'.(1024 * 1024), 'wb+');
|
||||
$this->process = null;
|
||||
$this->latestSignal = null;
|
||||
$this->status = self::STATUS_READY;
|
||||
@@ -1455,12 +1389,12 @@ class Process
|
||||
* @return bool True if the signal was sent successfully, false otherwise
|
||||
*
|
||||
* @throws LogicException In case the process is not running
|
||||
* @throws RuntimeException In case --enable-sigchild is activated
|
||||
* @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed
|
||||
* @throws RuntimeException In case of failure
|
||||
*/
|
||||
private function doSignal($signal, $throwException)
|
||||
{
|
||||
if (!$this->isRunning()) {
|
||||
if (null === $pid = $this->getPid()) {
|
||||
if ($throwException) {
|
||||
throw new LogicException('Can not send signal on a non running process.');
|
||||
}
|
||||
@@ -1468,23 +1402,36 @@ class Process
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isSigchildEnabled()) {
|
||||
if ($throwException) {
|
||||
throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
}
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
exec(sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode);
|
||||
if ($exitCode && $this->isRunning()) {
|
||||
if ($throwException) {
|
||||
throw new RuntimeException(sprintf('Unable to kill the process (%s).', implode(' ', $output)));
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!$this->enhanceSigchildCompatibility || !$this->isSigchildEnabled()) {
|
||||
$ok = @proc_terminate($this->process, $signal);
|
||||
} elseif (function_exists('posix_kill')) {
|
||||
$ok = @posix_kill($pid, $signal);
|
||||
} elseif ($ok = proc_open(sprintf('kill -%d %d', $signal, $pid), array(2 => array('pipe', 'w')), $pipes)) {
|
||||
$ok = false === fgets($pipes[2]);
|
||||
}
|
||||
if (!$ok) {
|
||||
if ($throwException) {
|
||||
throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (true !== @proc_terminate($this->process, $signal)) {
|
||||
if ($throwException) {
|
||||
throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->latestSignal = $signal;
|
||||
$this->latestSignal = (int) $signal;
|
||||
$this->fallbackStatus['signaled'] = true;
|
||||
$this->fallbackStatus['exitcode'] = -1;
|
||||
$this->fallbackStatus['termsig'] = $this->latestSignal;
|
||||
|
||||
return true;
|
||||
}
|
@@ -167,7 +167,7 @@ class ProcessBuilder
|
||||
/**
|
||||
* Sets the input of the process.
|
||||
*
|
||||
* @param string|null $input The input as a string
|
||||
* @param mixed $input The input as a string
|
||||
*
|
||||
* @return ProcessBuilder
|
||||
*
|
||||
@@ -175,7 +175,7 @@ class ProcessBuilder
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
$this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
|
||||
$this->input = ProcessUtils::validateInput(__METHOD__, $input);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -268,7 +268,6 @@ class ProcessBuilder
|
||||
$script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
|
||||
|
||||
if ($this->inheritEnv) {
|
||||
// include $_ENV for BC purposes
|
||||
$env = array_replace($_ENV, $_SERVER, $this->env);
|
||||
} else {
|
||||
$env = $this->env;
|
@@ -80,7 +80,7 @@ class ProcessUtils
|
||||
* @param string $caller The name of method call that validates the input
|
||||
* @param mixed $input The input to validate
|
||||
*
|
||||
* @return string The validated input
|
||||
* @return mixed The validated input
|
||||
*
|
||||
* @throws InvalidArgumentException In case the input is not valid
|
||||
*/
|
||||
@@ -90,11 +90,10 @@ class ProcessUtils
|
||||
if (is_resource($input)) {
|
||||
return $input;
|
||||
}
|
||||
if (is_scalar($input)) {
|
||||
return (string) $input;
|
||||
if (is_string($input)) {
|
||||
return $input;
|
||||
}
|
||||
// deprecated as of Symfony 2.5, to be removed in 3.0
|
||||
if (is_object($input) && method_exists($input, '__toString')) {
|
||||
if (is_scalar($input)) {
|
||||
return (string) $input;
|
||||
}
|
||||
|
13
vendor/symfony/process/README.md
vendored
Normal file
13
vendor/symfony/process/README.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
Process Component
|
||||
=================
|
||||
|
||||
The Process component executes commands in sub-processes.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/components/process.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Pipes;
|
||||
|
||||
/**
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractPipes implements PipesInterface
|
||||
{
|
||||
/** @var array */
|
||||
public $pipes = array();
|
||||
|
||||
/** @var string */
|
||||
protected $inputBuffer = '';
|
||||
/** @var resource|null */
|
||||
protected $input;
|
||||
|
||||
/** @var bool */
|
||||
private $blocked = true;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
foreach ($this->pipes as $pipe) {
|
||||
fclose($pipe);
|
||||
}
|
||||
$this->pipes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a system call has been interrupted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasSystemCallBeenInterrupted()
|
||||
{
|
||||
$lastError = error_get_last();
|
||||
|
||||
// stream_select returns false when the `select` system call is interrupted by an incoming signal
|
||||
return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks streams
|
||||
*/
|
||||
protected function unblock()
|
||||
{
|
||||
if (!$this->blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->pipes as $pipe) {
|
||||
stream_set_blocking($pipe, 0);
|
||||
}
|
||||
if (null !== $this->input) {
|
||||
stream_set_blocking($this->input, 0);
|
||||
}
|
||||
|
||||
$this->blocked = false;
|
||||
}
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
Process Component
|
||||
=================
|
||||
|
||||
Process executes commands in sub-processes.
|
||||
|
||||
In this example, we run a simple directory listing and get the result back:
|
||||
|
||||
```php
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
$process = new Process('ls -lsa');
|
||||
$process->setTimeout(3600);
|
||||
$process->run();
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new RuntimeException($process->getErrorOutput());
|
||||
}
|
||||
|
||||
print $process->getOutput();
|
||||
```
|
||||
|
||||
You can think that this is easy to achieve with plain PHP but it's not especially
|
||||
if you want to take care of the subtle differences between the different platforms.
|
||||
|
||||
And if you want to be able to get some feedback in real-time, just pass an
|
||||
anonymous function to the ``run()`` method and you will get the output buffer
|
||||
as it becomes available:
|
||||
|
||||
```php
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
$process = new Process('ls -lsa');
|
||||
$process->run(function ($type, $buffer) {
|
||||
if (Process::ERR === $type) {
|
||||
echo 'ERR > '.$buffer;
|
||||
} else {
|
||||
echo 'OUT > '.$buffer;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
That's great if you want to execute a long running command (like rsync-ing files to a
|
||||
remote server) and give feedback to the user in real-time.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Process/
|
||||
$ composer install
|
||||
$ phpunit
|
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
*/
|
||||
class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* tests find() with the env var PHP_PATH.
|
||||
*/
|
||||
public function testFindWithPhpPath()
|
||||
{
|
||||
if (defined('PHP_BINARY')) {
|
||||
$this->markTestSkipped('The PHP binary is easily available as of PHP 5.4');
|
||||
}
|
||||
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
$current = $f->find();
|
||||
|
||||
//not executable PHP_PATH
|
||||
putenv('PHP_PATH=/not/executable/php');
|
||||
$this->assertFalse($f->find(), '::find() returns false for not executable PHP');
|
||||
$this->assertFalse($f->find(false), '::find() returns false for not executable PHP');
|
||||
|
||||
//executable PHP_PATH
|
||||
putenv('PHP_PATH='.$current);
|
||||
$this->assertEquals($f->find(), $current, '::find() returns the executable PHP');
|
||||
$this->assertEquals($f->find(false), $current, '::find() returns the executable PHP');
|
||||
}
|
||||
|
||||
/**
|
||||
* tests find() with the env var PHP_PATH.
|
||||
*/
|
||||
public function testFindWithHHVM()
|
||||
{
|
||||
if (!defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('Should be executed in HHVM context.');
|
||||
}
|
||||
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
$current = getenv('PHP_BINARY') ?: PHP_BINARY;
|
||||
|
||||
$this->assertEquals($current.' --php', $f->find(), '::find() returns the executable PHP');
|
||||
$this->assertEquals($current, $f->find(false), '::find() returns the executable PHP');
|
||||
}
|
||||
|
||||
/**
|
||||
* tests find() with the env var PHP_PATH.
|
||||
*/
|
||||
public function testFindArguments()
|
||||
{
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->assertEquals($f->findArguments(), array('--php'), '::findArguments() returns HHVM arguments');
|
||||
} else {
|
||||
$this->assertEquals($f->findArguments(), array(), '::findArguments() returns no arguments');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tests find() with default executable.
|
||||
*/
|
||||
public function testFindWithSuffix()
|
||||
{
|
||||
if (defined('PHP_BINARY')) {
|
||||
$this->markTestSkipped('The PHP binary is easily available as of PHP 5.4');
|
||||
}
|
||||
|
||||
putenv('PHP_PATH=');
|
||||
putenv('PHP_PEAR_PHP_BIN=');
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
$current = $f->find();
|
||||
|
||||
//TODO maybe php executable is custom or even Windows
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
$this->assertTrue(is_executable($current));
|
||||
$this->assertTrue((bool) preg_match('/'.addslashes(DIRECTORY_SEPARATOR).'php\.(exe|bat|cmd|com)$/i', $current), '::find() returns the executable PHP with suffixes');
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,263 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
|
||||
class SigchildDisabledProcessTest extends AbstractProcessTest
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testGetExitCode()
|
||||
{
|
||||
parent::testGetExitCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testGetExitCodeIsNullOnStart()
|
||||
{
|
||||
parent::testGetExitCodeIsNullOnStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testGetExitCodeIsNullOnWhenStartingAgain()
|
||||
{
|
||||
parent::testGetExitCodeIsNullOnWhenStartingAgain();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testExitCodeCommandFailed()
|
||||
{
|
||||
parent::testExitCodeCommandFailed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testMustRun()
|
||||
{
|
||||
parent::testMustRun();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testSuccessfulMustRunHasCorrectExitCode()
|
||||
{
|
||||
parent::testSuccessfulMustRunHasCorrectExitCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
*/
|
||||
public function testMustRunThrowsException()
|
||||
{
|
||||
parent::testMustRunThrowsException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
*/
|
||||
public function testProcessIsSignaledIfStopped()
|
||||
{
|
||||
parent::testProcessIsSignaledIfStopped();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessWithTermSignal()
|
||||
{
|
||||
parent::testProcessWithTermSignal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessIsNotSignaled()
|
||||
{
|
||||
parent::testProcessIsNotSignaled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessWithoutTermSignal()
|
||||
{
|
||||
parent::testProcessWithoutTermSignal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testCheckTimeoutOnStartedProcess()
|
||||
{
|
||||
parent::testCheckTimeoutOnStartedProcess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
|
||||
*/
|
||||
public function testGetPid()
|
||||
{
|
||||
parent::testGetPid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
|
||||
*/
|
||||
public function testGetPidIsNullBeforeStart()
|
||||
{
|
||||
parent::testGetPidIsNullBeforeStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
|
||||
*/
|
||||
public function testGetPidIsNullAfterRun()
|
||||
{
|
||||
parent::testGetPidIsNullAfterRun();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testExitCodeText()
|
||||
{
|
||||
$process = $this->getProcess('qdfsmfkqsdfmqmsd');
|
||||
$process->run();
|
||||
|
||||
$process->getExitCodeText();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testExitCodeTextIsNullWhenExitCodeIsNull()
|
||||
{
|
||||
parent::testExitCodeTextIsNullWhenExitCodeIsNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testIsSuccessful()
|
||||
{
|
||||
parent::testIsSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testIsSuccessfulOnlyAfterTerminated()
|
||||
{
|
||||
parent::testIsSuccessfulOnlyAfterTerminated();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testIsNotSuccessful()
|
||||
{
|
||||
parent::testIsNotSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.
|
||||
*/
|
||||
public function testTTYCommandExitCode()
|
||||
{
|
||||
parent::testTTYCommandExitCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process can not be signaled.
|
||||
*/
|
||||
public function testSignal()
|
||||
{
|
||||
parent::testSignal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessWithoutTermSignalIsNotSignaled()
|
||||
{
|
||||
parent::testProcessWithoutTermSignalIsNotSignaled();
|
||||
}
|
||||
|
||||
public function testStopWithTimeoutIsActuallyWorking()
|
||||
{
|
||||
$this->markTestSkipped('Stopping with signal is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testProcessThrowsExceptionWhenExternallySignaled()
|
||||
{
|
||||
$this->markTestSkipped('Retrieving Pid is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testExitCodeIsAvailableAfterSignal()
|
||||
{
|
||||
$this->markTestSkipped('Signal is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testRunProcessWithTimeout()
|
||||
{
|
||||
$this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function provideStartMethods()
|
||||
{
|
||||
return array(
|
||||
array('start', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
|
||||
array('run', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
|
||||
array('mustRun', 'Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
|
||||
{
|
||||
$process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $input, $timeout, $options);
|
||||
$process->setEnhanceSigchildCompatibility(false);
|
||||
|
||||
return $process;
|
||||
}
|
||||
}
|
@@ -1,148 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
|
||||
class SigchildEnabledProcessTest extends AbstractProcessTest
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessIsSignaledIfStopped()
|
||||
{
|
||||
parent::testProcessIsSignaledIfStopped();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessWithTermSignal()
|
||||
{
|
||||
parent::testProcessWithTermSignal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessIsNotSignaled()
|
||||
{
|
||||
parent::testProcessIsNotSignaled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessWithoutTermSignal()
|
||||
{
|
||||
parent::testProcessWithoutTermSignal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
|
||||
*/
|
||||
public function testGetPid()
|
||||
{
|
||||
parent::testGetPid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
|
||||
*/
|
||||
public function testGetPidIsNullBeforeStart()
|
||||
{
|
||||
parent::testGetPidIsNullBeforeStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.
|
||||
*/
|
||||
public function testGetPidIsNullAfterRun()
|
||||
{
|
||||
parent::testGetPidIsNullAfterRun();
|
||||
}
|
||||
|
||||
public function testExitCodeText()
|
||||
{
|
||||
$process = $this->getProcess('qdfsmfkqsdfmqmsd');
|
||||
$process->run();
|
||||
|
||||
$this->assertInternalType('string', $process->getExitCodeText());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. The process can not be signaled.
|
||||
*/
|
||||
public function testSignal()
|
||||
{
|
||||
parent::testSignal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
|
||||
* @expectedExceptionMessage This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.
|
||||
*/
|
||||
public function testProcessWithoutTermSignalIsNotSignaled()
|
||||
{
|
||||
parent::testProcessWithoutTermSignalIsNotSignaled();
|
||||
}
|
||||
|
||||
public function testProcessThrowsExceptionWhenExternallySignaled()
|
||||
{
|
||||
$this->markTestSkipped('Retrieving Pid is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testExitCodeIsAvailableAfterSignal()
|
||||
{
|
||||
$this->markTestSkipped('Signal is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testStartAfterATimeout()
|
||||
{
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
$this->markTestSkipped('Restarting a timed-out process on Windows is not supported in sigchild environment');
|
||||
}
|
||||
parent::testStartAfterATimeout();
|
||||
}
|
||||
|
||||
public function testStopWithTimeoutIsActuallyWorking()
|
||||
{
|
||||
$this->markTestSkipped('Stopping with signal is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testRunProcessWithTimeout()
|
||||
{
|
||||
$this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
public function testCheckTimeoutOnStartedProcess()
|
||||
{
|
||||
$this->markTestSkipped('Signal (required for timeout) is not supported in sigchild environment');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
|
||||
{
|
||||
$process = new ProcessInSigchildEnvironment($commandline, $cwd, $env, $input, $timeout, $options);
|
||||
$process->setEnhanceSigchildCompatibility(true);
|
||||
|
||||
return $process;
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
// required for signal handling
|
||||
declare (ticks = 1);
|
||||
|
||||
pcntl_signal(SIGUSR1, function () {echo 'Caught SIGUSR1'; exit;});
|
||||
|
||||
$n = 0;
|
||||
|
||||
// ticks require activity to work - sleep(4); does not work
|
||||
while ($n < 400) {
|
||||
usleep(10000);
|
||||
++$n;
|
||||
}
|
||||
|
||||
return;
|
@@ -1,222 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class SimpleProcessTest extends AbstractProcessTest
|
||||
{
|
||||
private $enabledSigchild = false;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
ob_start();
|
||||
phpinfo(INFO_GENERAL);
|
||||
|
||||
$this->enabledSigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
|
||||
}
|
||||
|
||||
public function testGetExitCode()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case
|
||||
parent::testGetExitCode();
|
||||
}
|
||||
|
||||
public function testExitCodeCommandFailed()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case
|
||||
parent::testExitCodeCommandFailed();
|
||||
}
|
||||
|
||||
public function testProcessIsSignaledIfStopped()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
|
||||
parent::testProcessIsSignaledIfStopped();
|
||||
}
|
||||
|
||||
public function testProcessWithTermSignal()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
|
||||
parent::testProcessWithTermSignal();
|
||||
}
|
||||
|
||||
public function testProcessIsNotSignaled()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
|
||||
parent::testProcessIsNotSignaled();
|
||||
}
|
||||
|
||||
public function testProcessWithoutTermSignal()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
|
||||
parent::testProcessWithoutTermSignal();
|
||||
}
|
||||
|
||||
public function testExitCodeText()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use exitcode that is not available in this case
|
||||
parent::testExitCodeText();
|
||||
}
|
||||
|
||||
public function testIsSuccessful()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use PID that is not available in this case
|
||||
parent::testIsSuccessful();
|
||||
}
|
||||
|
||||
public function testIsNotSuccessful()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use PID that is not available in this case
|
||||
parent::testIsNotSuccessful();
|
||||
}
|
||||
|
||||
public function testGetPid()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use PID that is not available in this case
|
||||
parent::testGetPid();
|
||||
}
|
||||
|
||||
public function testGetPidIsNullBeforeStart()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use PID that is not available in this case
|
||||
parent::testGetPidIsNullBeforeStart();
|
||||
}
|
||||
|
||||
public function testGetPidIsNullAfterRun()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use PID that is not available in this case
|
||||
parent::testGetPidIsNullAfterRun();
|
||||
}
|
||||
|
||||
public function testSignal()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
parent::testSignal();
|
||||
}
|
||||
|
||||
public function testProcessWithoutTermSignalIsNotSignaled()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved');
|
||||
parent::testProcessWithoutTermSignalIsNotSignaled();
|
||||
}
|
||||
|
||||
public function testProcessThrowsExceptionWhenExternallySignaled()
|
||||
{
|
||||
$this->skipIfPHPSigchild(); // This test use PID that is not available in this case
|
||||
parent::testProcessThrowsExceptionWhenExternallySignaled();
|
||||
}
|
||||
|
||||
public function testExitCodeIsAvailableAfterSignal()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
parent::testExitCodeIsAvailableAfterSignal();
|
||||
}
|
||||
|
||||
public function testSignalProcessNotRunning()
|
||||
{
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Can not send signal on a non running process.');
|
||||
parent::testSignalProcessNotRunning();
|
||||
}
|
||||
|
||||
public function testSignalWithWrongIntSignal()
|
||||
{
|
||||
if ($this->enabledSigchild) {
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
} else {
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Error while sending signal `-4`.');
|
||||
}
|
||||
parent::testSignalWithWrongIntSignal();
|
||||
}
|
||||
|
||||
public function testSignalWithWrongNonIntSignal()
|
||||
{
|
||||
if ($this->enabledSigchild) {
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
} else {
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Error while sending signal `Céphalopodes`.');
|
||||
}
|
||||
parent::testSignalWithWrongNonIntSignal();
|
||||
}
|
||||
|
||||
public function testStopTerminatesProcessCleanly()
|
||||
{
|
||||
try {
|
||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process->run(function () use ($process) {
|
||||
$process->stop();
|
||||
});
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->fail('A call to stop() is not expected to cause wait() to throw a RuntimeException');
|
||||
}
|
||||
}
|
||||
|
||||
public function testKillSignalTerminatesProcessCleanly()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
|
||||
try {
|
||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process->run(function () use ($process) {
|
||||
if ($process->isRunning()) {
|
||||
$process->signal(defined('SIGKILL') ? SIGKILL : 9);
|
||||
}
|
||||
});
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException');
|
||||
}
|
||||
}
|
||||
|
||||
public function testTermSignalTerminatesProcessCleanly()
|
||||
{
|
||||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
|
||||
try {
|
||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process->run(function () use ($process) {
|
||||
if ($process->isRunning()) {
|
||||
$process->signal(defined('SIGTERM') ? SIGTERM : 15);
|
||||
}
|
||||
});
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->fail('A call to signal() is not expected to cause wait() to throw a RuntimeException');
|
||||
}
|
||||
}
|
||||
|
||||
public function testStopWithTimeoutIsActuallyWorking()
|
||||
{
|
||||
$this->skipIfPHPSigchild();
|
||||
|
||||
parent::testStopWithTimeoutIsActuallyWorking();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
|
||||
{
|
||||
return new Process($commandline, $cwd, $env, $input, $timeout, $options);
|
||||
}
|
||||
|
||||
private function skipIfPHPSigchild()
|
||||
{
|
||||
if ($this->enabledSigchild) {
|
||||
$this->markTestSkipped('Your PHP has been compiled with --enable-sigchild, this test can not be executed');
|
||||
}
|
||||
}
|
||||
|
||||
private function expectExceptionIfPHPSigchild($classname, $message)
|
||||
{
|
||||
if ($this->enabledSigchild) {
|
||||
$this->setExpectedException($classname, $message);
|
||||
}
|
||||
}
|
||||
}
|
@@ -36,10 +36,6 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFind()
|
||||
{
|
||||
if (!defined('PHP_BINARY')) {
|
||||
$this->markTestSkipped('Requires the PHP_BINARY constant');
|
||||
}
|
||||
|
||||
if (ini_get('open_basedir')) {
|
||||
$this->markTestSkipped('Cannot test when open_basedir is set');
|
||||
}
|
||||
@@ -70,10 +66,6 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFindWithExtraDirs()
|
||||
{
|
||||
if (!defined('PHP_BINARY')) {
|
||||
$this->markTestSkipped('Requires the PHP_BINARY constant');
|
||||
}
|
||||
|
||||
if (ini_get('open_basedir')) {
|
||||
$this->markTestSkipped('Cannot test when open_basedir is set');
|
||||
}
|
||||
@@ -90,10 +82,6 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFindWithOpenBaseDir()
|
||||
{
|
||||
if (!defined('PHP_BINARY')) {
|
||||
$this->markTestSkipped('Requires the PHP_BINARY constant');
|
||||
}
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
$this->markTestSkipped('Cannot run test on windows');
|
||||
}
|
||||
@@ -102,7 +90,7 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->markTestSkipped('Cannot test when open_basedir is set');
|
||||
}
|
||||
|
||||
$this->iniSet('open_basedir', dirname(PHP_BINARY).(!defined('HHVM_VERSION') ? PATH_SEPARATOR.'/' : ''));
|
||||
$this->iniSet('open_basedir', dirname(PHP_BINARY).(!defined('HHVM_VERSION') || HHVM_VERSION_ID >= 30800 ? PATH_SEPARATOR.'/' : ''));
|
||||
|
||||
$finder = new ExecutableFinder();
|
||||
$result = $finder->find($this->getPhpBinaryName());
|
||||
@@ -115,17 +103,12 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
if (ini_get('open_basedir')) {
|
||||
$this->markTestSkipped('Cannot test when open_basedir is set');
|
||||
}
|
||||
|
||||
if (!defined('PHP_BINARY')) {
|
||||
$this->markTestSkipped('Requires the PHP_BINARY constant');
|
||||
}
|
||||
|
||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||
$this->markTestSkipped('Cannot run test on windows');
|
||||
}
|
||||
|
||||
$this->setPath('');
|
||||
$this->iniSet('open_basedir', PHP_BINARY.(!defined('HHVM_VERSION') ? PATH_SEPARATOR.'/' : ''));
|
||||
$this->iniSet('open_basedir', PHP_BINARY.(!defined('HHVM_VERSION') || HHVM_VERSION_ID >= 30800 ? PATH_SEPARATOR.'/' : ''));
|
||||
|
||||
$finder = new ExecutableFinder();
|
||||
$result = $finder->find($this->getPhpBinaryName(), false);
|
@@ -1,5 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runs a PHP script that can be stopped only with a SIGKILL (9) signal for 3 seconds.
|
||||
*
|
||||
@@ -21,16 +30,18 @@ function handleSignal($signal)
|
||||
break;
|
||||
}
|
||||
|
||||
echo "received signal $name\n";
|
||||
echo "signal $name\n";
|
||||
}
|
||||
|
||||
declare (ticks = 1);
|
||||
pcntl_signal(SIGTERM, 'handleSignal');
|
||||
pcntl_signal(SIGINT, 'handleSignal');
|
||||
|
||||
echo 'received ';
|
||||
|
||||
$duration = isset($argv[1]) ? (int) $argv[1] : 3;
|
||||
$start = microtime(true);
|
||||
|
||||
while ($duration > (microtime(true) - $start)) {
|
||||
usleep(1000);
|
||||
usleep(10000);
|
||||
pcntl_signal_dispatch();
|
||||
}
|
71
vendor/symfony/process/Tests/PhpExecutableFinderTest.php
vendored
Normal file
71
vendor/symfony/process/Tests/PhpExecutableFinderTest.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
*/
|
||||
class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* tests find() with the constant PHP_BINARY.
|
||||
*/
|
||||
public function testFind()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('Should not be executed in HHVM context.');
|
||||
}
|
||||
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
$current = PHP_BINARY;
|
||||
$args = 'phpdbg' === PHP_SAPI ? ' -qrr' : '';
|
||||
|
||||
$this->assertEquals($current.$args, $f->find(), '::find() returns the executable PHP');
|
||||
$this->assertEquals($current, $f->find(false), '::find() returns the executable PHP');
|
||||
}
|
||||
|
||||
/**
|
||||
* tests find() with the env var / constant PHP_BINARY with HHVM.
|
||||
*/
|
||||
public function testFindWithHHVM()
|
||||
{
|
||||
if (!defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('Should be executed in HHVM context.');
|
||||
}
|
||||
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
$current = getenv('PHP_BINARY') ?: PHP_BINARY;
|
||||
|
||||
$this->assertEquals($current.' --php', $f->find(), '::find() returns the executable PHP');
|
||||
$this->assertEquals($current, $f->find(false), '::find() returns the executable PHP');
|
||||
}
|
||||
|
||||
/**
|
||||
* tests find() with the env var PHP_PATH.
|
||||
*/
|
||||
public function testFindArguments()
|
||||
{
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->assertEquals($f->findArguments(), array('--php'), '::findArguments() returns HHVM arguments');
|
||||
} elseif ('phpdbg' === PHP_SAPI) {
|
||||
$this->assertEquals($f->findArguments(), array('-qrr'), '::findArguments() returns phpdbg arguments');
|
||||
} else {
|
||||
$this->assertEquals($f->findArguments(), array(), '::findArguments() returns no arguments');
|
||||
}
|
||||
}
|
||||
}
|
@@ -30,20 +30,20 @@ PHP
|
||||
|
||||
public function testCommandLine()
|
||||
{
|
||||
$process = new PhpProcess(<<<PHP
|
||||
$process = new PhpProcess(<<<'PHP'
|
||||
<?php echo 'foobar';
|
||||
PHP
|
||||
);
|
||||
|
||||
$f = new PhpExecutableFinder();
|
||||
$commandLine = $f->find();
|
||||
$commandLine = $process->getCommandLine();
|
||||
|
||||
$this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP before start');
|
||||
$f = new PhpExecutableFinder();
|
||||
$this->assertContains($f->find(), $commandLine, '::getCommandLine() returns the command line of PHP before start');
|
||||
|
||||
$process->start();
|
||||
$this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start');
|
||||
$this->assertContains($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start');
|
||||
|
||||
$process->wait();
|
||||
$this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait');
|
||||
$this->assertContains($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait');
|
||||
}
|
||||
}
|
@@ -1,5 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
define('ERR_SELECT_FAILED', 1);
|
||||
define('ERR_TIMEOUT', 2);
|
||||
define('ERR_READ_FAILED', 3);
|
@@ -51,10 +51,11 @@ class ProcessFailedExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
$exitText = 'General error';
|
||||
$output = 'Command output';
|
||||
$errorOutput = 'FATAL: Unexpected error';
|
||||
$workingDirectory = getcwd();
|
||||
|
||||
$process = $this->getMock(
|
||||
'Symfony\Component\Process\Process',
|
||||
array('isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText', 'isOutputDisabled'),
|
||||
array('isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText', 'isOutputDisabled', 'getWorkingDirectory'),
|
||||
array($cmd)
|
||||
);
|
||||
$process->expects($this->once())
|
||||
@@ -81,27 +82,32 @@ class ProcessFailedExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
->method('isOutputDisabled')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$process->expects($this->once())
|
||||
->method('getWorkingDirectory')
|
||||
->will($this->returnValue($workingDirectory));
|
||||
|
||||
$exception = new ProcessFailedException($process);
|
||||
|
||||
$this->assertEquals(
|
||||
"The command \"$cmd\" failed.\nExit Code: $exitCode($exitText)\n\nOutput:\n================\n{$output}\n\nError Output:\n================\n{$errorOutput}",
|
||||
"The command \"$cmd\" failed.\n\nExit Code: $exitCode($exitText)\n\nWorking directory: {$workingDirectory}\n\nOutput:\n================\n{$output}\n\nError Output:\n================\n{$errorOutput}",
|
||||
$exception->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that ProcessFailedException does not extract information from
|
||||
* process output if it was previously disabled
|
||||
* process output if it was previously disabled.
|
||||
*/
|
||||
public function testDisabledOutputInFailedExceptionDoesNotPopulateOutput()
|
||||
{
|
||||
$cmd = 'php';
|
||||
$exitCode = 1;
|
||||
$exitText = 'General error';
|
||||
$workingDirectory = getcwd();
|
||||
|
||||
$process = $this->getMock(
|
||||
'Symfony\Component\Process\Process',
|
||||
array('isSuccessful', 'isOutputDisabled', 'getExitCode', 'getExitCodeText', 'getOutput', 'getErrorOutput'),
|
||||
array('isSuccessful', 'isOutputDisabled', 'getExitCode', 'getExitCodeText', 'getOutput', 'getErrorOutput', 'getWorkingDirectory'),
|
||||
array($cmd)
|
||||
);
|
||||
$process->expects($this->once())
|
||||
@@ -126,10 +132,14 @@ class ProcessFailedExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
->method('isOutputDisabled')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$process->expects($this->once())
|
||||
->method('getWorkingDirectory')
|
||||
->will($this->returnValue($workingDirectory));
|
||||
|
||||
$exception = new ProcessFailedException($process);
|
||||
|
||||
$this->assertEquals(
|
||||
"The command \"$cmd\" failed.\nExit Code: $exitCode($exitText)",
|
||||
"The command \"$cmd\" failed.\n\nExit Code: $exitCode($exitText)\n\nWorking directory: {$workingDirectory}",
|
||||
$exception->getMessage()
|
||||
);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -9,14 +9,13 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
pcntl_signal(SIGUSR1, function () {echo 'SIGUSR1'; exit;});
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
echo 'Caught ';
|
||||
|
||||
class ProcessInSigchildEnvironment extends Process
|
||||
{
|
||||
protected function isSigchildEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
$n = 0;
|
||||
|
||||
while ($n++ < 400) {
|
||||
usleep(10000);
|
||||
pcntl_signal_dispatch();
|
||||
}
|
@@ -16,19 +16,18 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Symfony\\Component\\Process\\": "" }
|
||||
"psr-4": { "Symfony\\Component\\Process\\": "" },
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"target-dir": "Symfony/Component/Process",
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.6-dev"
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,6 +9,7 @@
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Symfony Process Component Test Suite">
|
||||
<directory>./Tests/</directory>
|
||||
@@ -20,6 +21,7 @@
|
||||
<directory>./</directory>
|
||||
<exclude>
|
||||
<directory>./Tests</directory>
|
||||
<directory>./vendor</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
Reference in New Issue
Block a user