merged branch Seldaek/process-win-fix (PR #4400)
Commits -------bcf8cf9
[Process] Refactor the windows handling so it is always executed0c5aa8b
[Process] Add failing test for callbacks on windows Discussion ---------- [Process] Windows callback handling fix --------------------------------------------------------------------------- by travisbot at 2012-05-24T18:10:56Z This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1424957) (mergedbcf8cf91
intoe2c36c54
).
This commit is contained in:
commit
48ccdaa31b
@ -206,6 +206,9 @@ class Process
|
||||
$this->fileHandles = array(
|
||||
self::STDOUT => tmpfile(),
|
||||
);
|
||||
$this->readBytes = array(
|
||||
self::STDOUT => 0,
|
||||
);
|
||||
$descriptors = array(array('pipe', 'r'), $this->fileHandles[self::STDOUT], array('pipe', 'w'));
|
||||
} else {
|
||||
$descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
|
||||
@ -236,14 +239,18 @@ class Process
|
||||
unset($this->pipes[0]);
|
||||
|
||||
return;
|
||||
} else {
|
||||
$writePipes = array($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
$stdinLen = strlen($this->stdin);
|
||||
$stdinOffset = 0;
|
||||
}
|
||||
|
||||
$writePipes = array($this->pipes[0]);
|
||||
unset($this->pipes[0]);
|
||||
$stdinLen = strlen($this->stdin);
|
||||
$stdinOffset = 0;
|
||||
|
||||
while ($writePipes) {
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$this->processFileHandles($callback);
|
||||
}
|
||||
|
||||
$r = $this->pipes;
|
||||
$w = $writePipes;
|
||||
$e = null;
|
||||
@ -252,7 +259,8 @@ class Process
|
||||
|
||||
if (false === $n) {
|
||||
break;
|
||||
} elseif ($n === 0) {
|
||||
}
|
||||
if ($n === 0) {
|
||||
proc_terminate($this->process);
|
||||
|
||||
throw new \RuntimeException('The process timed out.');
|
||||
@ -269,22 +277,6 @@ class Process
|
||||
}
|
||||
}
|
||||
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$fh = $this->fileHandles;
|
||||
foreach ($fh as $type => $fileHandle) {
|
||||
fseek($fileHandle, 0);
|
||||
$data = fread($fileHandle, 8192);
|
||||
$this->readBytes[$type] = strlen($data);
|
||||
if (strlen($data) > 0) {
|
||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
||||
}
|
||||
if (false === $data) {
|
||||
fclose($fileHandle);
|
||||
unset($this->fileHandles[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($r as $pipe) {
|
||||
$type = array_search($pipe, $this->pipes);
|
||||
$data = fread($pipe, 8192);
|
||||
@ -319,53 +311,40 @@ class Process
|
||||
$this->processInformation = proc_get_status($this->process);
|
||||
$callback = $this->buildCallback($callback);
|
||||
while ($this->pipes || (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles)) {
|
||||
$r = $this->pipes;
|
||||
$w = null;
|
||||
$e = null;
|
||||
|
||||
$n = @stream_select($r, $w, $e, $this->timeout);
|
||||
|
||||
if (false === $n) {
|
||||
break;
|
||||
}
|
||||
if (0 === $n) {
|
||||
proc_terminate($this->process);
|
||||
|
||||
throw new \RuntimeException('The process timed out.');
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
|
||||
$this->processFileHandles($callback, !$this->pipes);
|
||||
}
|
||||
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$fh = $this->fileHandles;
|
||||
foreach ($fh as $type => $fileHandle) {
|
||||
fseek($fileHandle, $this->readBytes[$type]);
|
||||
$data = fread($fileHandle, 8192);
|
||||
if (isset($this->readBytes)) {
|
||||
$this->readBytes[$type] += strlen($data);
|
||||
} else {
|
||||
$this->readBytes[$type] = strlen($data);
|
||||
}
|
||||
if ($this->pipes) {
|
||||
$r = $this->pipes;
|
||||
$w = null;
|
||||
$e = null;
|
||||
|
||||
$n = @stream_select($r, $w, $e, $this->timeout);
|
||||
|
||||
if (false === $n) {
|
||||
$this->pipes = array();
|
||||
|
||||
continue;
|
||||
}
|
||||
if (0 === $n) {
|
||||
proc_terminate($this->process);
|
||||
|
||||
throw new \RuntimeException('The process timed out.');
|
||||
}
|
||||
|
||||
foreach ($r as $pipe) {
|
||||
$type = array_search($pipe, $this->pipes);
|
||||
$data = fread($pipe, 8192);
|
||||
if (strlen($data) > 0) {
|
||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
||||
}
|
||||
if (false === $data) {
|
||||
fclose($fileHandle);
|
||||
unset($this->fileHandles[$type]);
|
||||
if (false === $data || feof($pipe)) {
|
||||
fclose($pipe);
|
||||
unset($this->pipes[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($r as $pipe) {
|
||||
$type = array_search($pipe, $this->pipes);
|
||||
$data = fread($pipe, 8192);
|
||||
if (strlen($data) > 0) {
|
||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
||||
}
|
||||
if (false === $data || feof($pipe)) {
|
||||
fclose($pipe);
|
||||
unset($this->pipes[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->updateStatus();
|
||||
if ($this->processInformation['signaled']) {
|
||||
@ -725,4 +704,27 @@ class Process
|
||||
$this->addOutput(stream_get_contents($this->pipes[self::STDOUT]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the windows file handles fallbacks
|
||||
*
|
||||
* @param mixed $callback A valid PHP callback
|
||||
* @param Boolean $closeEmptyHandles if true, handles that are empty will be assumed closed
|
||||
*/
|
||||
private function processFileHandles($callback, $closeEmptyHandles = false)
|
||||
{
|
||||
$fh = $this->fileHandles;
|
||||
foreach ($fh as $type => $fileHandle) {
|
||||
fseek($fileHandle, $this->readBytes[$type]);
|
||||
$data = fread($fileHandle, 8192);
|
||||
if (strlen($data) > 0) {
|
||||
$this->readBytes[$type] += strlen($data);
|
||||
call_user_func($callback, $type == 1 ? self::OUT : self::ERR, $data);
|
||||
}
|
||||
if (false === $data || ($closeEmptyHandles && '' === $data && feof($fileHandle))) {
|
||||
fclose($fileHandle);
|
||||
unset($this->fileHandles[$type]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,18 @@ class ProcessTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame(0, $p->getExitCode());
|
||||
}
|
||||
|
||||
public function testCallbackIsExecutedForOutput()
|
||||
{
|
||||
$p = new Process(sprintf('php -r %s', escapeshellarg('echo \'foo\';')));
|
||||
|
||||
$called = false;
|
||||
$p->run(function ($type, $buffer) use (&$called) {
|
||||
$called = $buffer === 'foo';
|
||||
});
|
||||
|
||||
$this->assertTrue($called, 'The callback should be executed with the output');
|
||||
}
|
||||
|
||||
public function testExitCodeText()
|
||||
{
|
||||
$process = new Process('');
|
||||
|
Reference in New Issue
Block a user