[Process] Implement IteratorAggregate to stream output
This commit is contained in:
parent
dc189f0793
commit
5947f5d8b1
@ -27,7 +27,7 @@ use Symfony\Component\Process\Pipes\WindowsPipes;
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Romain Neutron <imprec@gmail.com>
|
||||
*/
|
||||
class Process
|
||||
class Process implements \IteratorAggregate
|
||||
{
|
||||
const ERR = 'err';
|
||||
const OUT = 'out';
|
||||
@ -498,6 +498,54 @@ class Process
|
||||
return $latest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
|
||||
*
|
||||
* @param bool $blocking Whether to use a blocking read call.
|
||||
* @param bool $clearOutput Whether to clear or keep output in memory.
|
||||
*
|
||||
* @throws LogicException in case the output has been disabled
|
||||
* @throws LogicException In case the process is not started
|
||||
*
|
||||
* @return \Generator
|
||||
*/
|
||||
public function getIterator($blocking = true, $clearOutput = true)
|
||||
{
|
||||
$this->readPipesForOutput(__FUNCTION__, false);
|
||||
|
||||
while (null !== $this->callback) {
|
||||
$out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
|
||||
|
||||
if (isset($out[0])) {
|
||||
if ($clearOutput) {
|
||||
$this->clearOutput();
|
||||
} else {
|
||||
$this->incrementalOutputOffset = ftell($this->stdout);
|
||||
}
|
||||
|
||||
yield self::OUT => $out;
|
||||
}
|
||||
|
||||
$err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
|
||||
|
||||
if (isset($err[0])) {
|
||||
if ($clearOutput) {
|
||||
$this->clearErrorOutput();
|
||||
} else {
|
||||
$this->incrementalErrorOutputOffset = ftell($this->stderr);
|
||||
}
|
||||
|
||||
yield self::ERR => $err;
|
||||
}
|
||||
|
||||
if (!$blocking && !isset($out[0]) && !isset($err[0])) {
|
||||
yield self::OUT => '';
|
||||
}
|
||||
|
||||
$this->readPipesForOutput(__FUNCTION__, $blocking);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the process output.
|
||||
*
|
||||
@ -1296,11 +1344,12 @@ class Process
|
||||
/**
|
||||
* Reads pipes for the freshest output.
|
||||
*
|
||||
* @param $caller The name of the method that needs fresh outputs
|
||||
* @param string $caller The name of the method that needs fresh outputs
|
||||
* @param bool $blocking Whether to use blocking calls or not.
|
||||
*
|
||||
* @throws LogicException in case output has been disabled or process is not started
|
||||
*/
|
||||
private function readPipesForOutput($caller)
|
||||
private function readPipesForOutput($caller, $blocking = false)
|
||||
{
|
||||
if ($this->outputDisabled) {
|
||||
throw new LogicException('Output has been disabled.');
|
||||
@ -1308,7 +1357,7 @@ class Process
|
||||
|
||||
$this->requireProcessIsStarted($caller);
|
||||
|
||||
$this->updateStatus(false);
|
||||
$this->updateStatus($blocking);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1270,6 +1270,42 @@ class ProcessTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('123456', $process->getOutput());
|
||||
}
|
||||
|
||||
public function testIteratorOutput()
|
||||
{
|
||||
$input = new InputStream();
|
||||
|
||||
$process = new Process(self::$phpBin.' -r '.escapeshellarg('fwrite(STDOUT, 123); fwrite(STDERR, 234); fwrite(STDOUT, fread(STDIN, 3)); fwrite(STDERR, 456);'));
|
||||
$process->setInput($input);
|
||||
$process->start();
|
||||
$output = array();
|
||||
|
||||
foreach ($process as $type => $data) {
|
||||
$output[] = array($type, $data);
|
||||
break;
|
||||
}
|
||||
$expectedOutput = array(
|
||||
array($process::OUT, '123'),
|
||||
);
|
||||
$this->assertSame($expectedOutput, $output);
|
||||
|
||||
$input->write(345);
|
||||
|
||||
foreach ($process as $type => $data) {
|
||||
$output[] = array($type, $data);
|
||||
}
|
||||
|
||||
$this->assertSame('', $process->getOutput());
|
||||
$this->assertFalse($process->isRunning());
|
||||
|
||||
$expectedOutput = array(
|
||||
array($process::OUT, '123'),
|
||||
array($process::ERR, '234'),
|
||||
array($process::OUT, '345'),
|
||||
array($process::ERR, '456'),
|
||||
);
|
||||
$this->assertSame($expectedOutput, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $commandline
|
||||
* @param null|string $cwd
|
||||
|
Reference in New Issue
Block a user