8000 feature #18513 [Process] Turn getIterator() args to flags & add ITER_… · symfony/symfony@cb0fe14 · GitHub
[go: up one dir, main page]

Skip to content

Commit cb0fe14

Browse files
feature #18513 [Process] Turn getIterator() args to flags & add ITER_SKIP_OUT/ERR modes (nicolas-grekas)
This PR was merged into the 3.1-dev branch. Discussion ---------- [Process] Turn getIterator() args to flags & add ITER_SKIP_OUT/ERR modes | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #8454 | License | MIT | Doc PR | - Targeted at 3.1 Commits ------- 428f12e [Process] Turn getIterator() args to flags & add ITER_SKIP_OUT/ERR modes
2 parents f1d12a1 + 428f12e commit cb0fe14

File tree

3 files changed

+61
-30
lines changed

3 files changed

+61
-30
lines changed

src/Symfony/Component/Process/Process.php

Lines changed: 33 additions & 20 deletions
< 9E88 td data-grid-cell-id="diff-edd51b05bf438c7cdca442e25d68f41dd0a51952a69fa0c5fa912dc31d833ef4-538-546-2" data-line-anchor="diff-edd51b05bf438c7cdca442e25d68f41dd0a51952a69fa0c5fa912dc31d833ef4R546" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionLine-bgColor, var(--diffBlob-addition-bgColor-line));padding-right:24px" tabindex="-1" valign="top" class="focusable-grid-cell diff-text-cell right-side-diff-cell left-side">+
if ($clearOutput) {
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ class Process implements \IteratorAggregate
4343
// Timeout Precision in seconds.
4444
const TIMEOUT_PRECISION = 0.2;
4545

46+
const ITER_NON_BLOCKING = 1; // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking
47+
const ITER_KEEP_OUTPUT = 2; // By default, outputs are cleared while iterating, use this flag to keep them in memory
48+
const ITER_SKIP_OUT = 4; // Use this flag to skip STDOUT while iterating
49+
const ITER_SKIP_ERR = 8; // Use this flag to skip STDERR while iterating
50+
4651
private $callback;
4752
private $hasCallback = false;
4853
private $commandline;
@@ -503,41 +508,49 @@ public function getIncrementalOutput()
503508
/**
504509
* Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR).
505510
*
506-
* @param bool $blocking Whether to use a blocking read call.
507-
* @param bool $clearOutput Whether to clear or keep output in memory.
511+
* @param int $flags A bit field of Process::ITER_* flags.
508512
*
509513
* @throws LogicException in case the output has been disabled
510514
* @throws LogicException In case the process is not started
511515
*
512516
* @return \Generator
513517
*/
514-
public function getIterator($blocking = true, $clearOutput = true)
518+
public function getIterator($flags = 0)
515519
{
516520
$this->readPipesForOutput(__FUNCTION__, false);
517521

518-
while (null !== $this->callback || !feof($this->stdout) || !feof($this->stderr)) {
519-
$out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
522+
$clearOutput = !(self::ITER_KEEP_OUTPUT & $flags);
523+
$blocking = !(self::ITER_NON_BLOCKING & $flags);
524+
$yieldOut = !(self::ITER_SKIP_OUT & $flags);
525+
$yieldErr = !(self::ITER_SKIP_ERR & $flags);
520526

521-
if (isset($out[0])) {
522-
if ($clearOutput) {
523-
$this->clearOutput();
524-
} else {
525-
$this->incrementalOutputOffset = ftell($this->stdout);
526-
}
527+
while (null !== $this->callback || ($yieldOut && !feof($this->stdout)) || ($yieldErr && !feof($this->stderr))) {
528+
if ($yieldOut) {
529+
$out = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset);
530+
531+
if (isset($out[0])) {
532+
if ($clearOutput) {
533+
$this->clearOutput();
534+
} else {
535+
$this->incrementalOutputOffset = ftell($this->stdout);
536+
}
527537

528-
yield self::OUT => $out;
538+
yield self::OUT => $out;
539+
}
529540
}
530541

531-
$err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
542+
if ($yieldErr) {
543+
$err = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset);
532544

533-
if (isset($err[0])) {
534-
if ($clearOutput) {
535-
$this->clearErrorOutput();
536-
} else {
537-
$this->incrementalErrorOutputOffset = ftell($this->stderr);
538-
}
545+
if (isset($err[0])) {
546
547+
$this->clearErrorOutput();
548+
} else {
549+
$this->incrementalErrorOutputOffset = ftell($this->stderr);
550+
}
539551

540-
yield self::ERR => $err;
552+
yield self::ERR => $err;
553+
}
541554
}
542555

543556
if (!$blocking && !isset($out[0]) && !isset($err[0])) {

src/Symfony/Component/Process/ProcessUtils.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ public static function validateInput($caller, $input)
9696
if (is_scalar($input)) {
9797
return (string) $input;
9898
}
99+
if ($input instanceof Process) {
100+
return $input->getIterator($input::ITER_SKIP_ERR);
101+
}
99102
if ($input instanceof \Iterator) {
100103
return $input;
101104
}

src/Symfony/Component/Process/Tests/ProcessTest.php

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,7 @@ public function pipesCodeProvider()
11541154
* @dataProvider provideVariousIncrementals
11551155
*/
11561156
public function testIncrementalOutputDoesNotRequireAnotherCall($stream, $method) {
1157-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\''.$stream.'\', $n, 1); $n++; usleep(1000); }'), null, null, null, null);
1157+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\''.$stream.'\', $n, 1); $n++; usleep(1000); }'), null, null, null, null);
11581158
$process->start();
11591159
$result = '';
11601160
$limit = microtime(true) + 3;
@@ -1182,7 +1182,7 @@ public function testIteratorInput()
11821182
yield 'pong';
11831183
};
11841184

1185-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);'), null, null, $input());
1185+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);'), null, null, $input());
11861186
$process->run();
11871187
$this->assertSame('pingpong', $process->getOutput());
11881188
}
@@ -1191,7 +1191,7 @@ public function testSimpleInputStream()
11911191
{
11921192
$input = new InputStream();
11931193

1194-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('echo \'ping\'; stream_copy_to_stream(STDIN, STDOUT);'));
1194+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo \'ping\'; stream_copy_to_stream(STDIN, STDOUT);'));
11951195
$process->setInput($input);
11961196

11971197
$process->start(function ($type, $data) use ($input) {
@@ -1225,7 +1225,7 @@ public function testInputStreamWithCallable()
12251225
$input->onEmpty($stream);
12261226
$input->write($stream());
12271227

1228-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);'));
1228+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo fread(STDIN, 3);'));
12291229
$process->setInput($input);
12301230
$process->start(function ($type, $data) use ($input) {
12311231
$input->close();
@@ -1243,7 +1243,7 @@ public function testInputStreamWithGenerator()
12431243
$input->close();
12441244
});
12451245

1246-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);'));
1246+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);'));
12471247
$process->setInput($input);
12481248
$process->start();
12491249
$input->write('ping');
@@ -1257,7 +1257,7 @@ public function testInputStreamOnEmpty()
12571257
$input = new InputStream();
12581258
$input->onEmpty(function () use (&$i) {++$i;});
12591259

1260-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('echo 123; echo fread(STDIN, 1); echo 456;'));
1260+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo 123; echo fread(STDIN, 1); echo 456;'));
12611261
$process->setInput($input);
12621262
$process->start(function ($type, $data) use ($input) {
12631263
if ('123' === $data) {
@@ -1274,7 +1274,7 @@ public function testIteratorOutput()
12741274
{
12751275
$input = new InputStream();
12761276

1277-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('fwrite(STDOUT, 123); fwrite(STDERR, 234); fwrite(STDOUT, fread(STDIN, 3)); fwrite(STDERR, 456);'));
1277+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('fwrite(STDOUT, 123); fwrite(STDERR, 234); flush(); usleep(10000); fwrite(STDOUT, fread(STDIN, 3)); fwrite(STDERR, 456);'));
12781278
$process->setInput($input);
12791279
$process->start();
12801280
$output = array();
@@ -1310,12 +1310,12 @@ public function testNonBlockingNorClearingIteratorOutput()
13101310
{
13111311
$input = new InputStream();
13121312

1313-
$process = new Process(self::$phpBin.' -r '.escapeshellarg('fwrite(STDOUT, fread(STDIN, 3));'));
1313+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('fwrite(STDOUT, fread(STDIN, 3));'));
13141314
$process->setInput($input);
13151315
$process->start();
13161316
$output = array();
13171317

1318-
foreach ($process->getIterator(false, false) as $type => $data) {
1318+
foreach ($process->getIterator($process::ITER_NON_BLOCKING | $process::ITER_KEEP_OUTPUT) as $type => $data) {
13191319
$output[] = array($type, $data);
13201320
break;
13211321
}
@@ -1326,7 +1326,7 @@ public function testNonBlockingNorClearingIteratorOutput()
13261326

13271327
$input->write(123);
13281328

1329-
foreach ($process->getIterator(false, false) as $type => $data) {
1329+
foreach ($process->getIterator($process::ITER_NON_BLOCKING | $process::ITER_KEEP_OUTPUT) as $type => $data) {
13301330
if ('' !== $data) {
13311331
$output[] = array($type, $data);
13321332
}
@@ -1342,6 +1342,21 @@ public function testNonBlockingNorClearingIteratorOutput()
13421342
$this->assertSame($expectedOutput, $output);
13431343
}
13441344

1345+
public function testChainedProcesses()
1346+
{
1347+
$p1 = new Process(self::$phpBin.' -r '.escapeshellarg('fwrite(STDERR, 123); fwrite(STDOUT, 456);'));
1348+
$p2 = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('stream_copy_to_stream(STDIN, STDOUT);')));
1349+
$p2->setInput($p1);
1350+
1351+
$p1->start();
1352+
$p2->run();
1353+
1354+
$this->assertSame('123', $p1->getErrorOutput());
1355+
$this->assertSame('', $p1->getOutput());
1356+
$this->assertSame('', $p2->getErrorOutput());
1357+
$this->assertSame('456', $p2->getOutput());
1358+
}
1359+
13451360
/**
13461361
* @param string $commandline
13471362
* @param null|string $cwd

0 commit comments

Comments
 (0)
0