Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2f6a96e

Browse files
committed
Add feature "wait until callback" to process class
A feature for waiting the process to complete is already present, but in some cases you may want to just wait for the process to be ready. This kind of process generaly output things when they are ready. With this feature you will be able to (for example) wait until the process is ready.
1 parent 5a0cad2 commit 2f6a96e

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

src/Symfony/Component/Process/Process.php

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,45 @@ public function wait(callable $callback = null)
429429
return $this->exitcode;
430430
}
431431

432+
/**
433+
* Waits until the callback return true.
434+
*
435+
* The callback receives the type of output (out or err) and some bytes
436+
* from the output in real-time while writing the standard input to the process.
437+
* It allows to have feedback from the independent process during execution.
438+
*
439+
* @param callable $callback
440+
*
441+
* @throws RuntimeException When process timed out
442+
* @throws LogicException When process is not yet started
443+
*/
444+
public function waitUntil(callable $callback)
445+
{
446+
$this->requireProcessIsStarted(__FUNCTION__);
447+
$this->updateStatus(false);
448+
449+
if (!$this->processPipes->haveReadSupport()) {
450+
$this->stop(0);
451+
throw new \LogicException('Pass the callback to the Process::start method or enableOutput to use a callback with Process::waitUntil');
452+
}
453+
$callback = $this->buildCallback($callback);
454+
455+
$wait = true;
456+
do {
457+
$this->checkTimeout();
458+
$running = '\\' === DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
459+
$output = $this->processPipes->readAndWrite($running, '\\' !== DIRECTORY_SEPARATOR || !$running);
460+
461+
foreach ($output as $type => $data) {
462+
if (3 !== $type) {
463+
$wait = !$callback(self::STDOUT === $type ? self::OUT : self::ERR, $data);
464+
} elseif (!isset($this->fallbackStatus['signaled'])) {
465+
$this->fallbackStatus['exitcode'] = (int) $data;
466+
}
467+
}
468+
} while ($wait);
469+
}
470+
432471
/**
433472
* Returns the Pid (process identifier), if applicable.
434473
*
@@ -1264,7 +1303,7 @@ protected function buildCallback(callable $callback = null)
12641303
if ($this->outputDisabled) {
12651304
return function ($type, $data) use ($callback) {
12661305
if (null !== $callback) {
1267-
\call_user_func($callback, $type, $data);
1306+
return $callback($type, $data);
12681307
}
12691308
};
12701309
}
@@ -1279,7 +1318,7 @@ protected function buildCallback(callable $callback = null)
12791318
}
12801319

12811320
if (null !== $callback) {
1282-
\call_user_func($callback, $type, $data);
1321+
return $callback($type, $data);
12831322
}
12841323
};
12851324
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
$outputs = array(
13+
'First iteration output',
14+
'Second iteration output',
15+
'One more iteration output',
16+
'This took more time',
17+
'This one was sooooo slow',
18+
);
19+
20+
$iterationTime = 10000;
21+
22+
foreach ($outputs as $output) {
23+
usleep($iterationTime);
24+
$iterationTime *= 10;
25+
echo $output."\n";
26+
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,28 @@ public function testStopWithTimeoutIsActuallyWorking()
133133
$this->assertLessThan(15, microtime(true) - $start);
134134
}
135135

136+
public function testWaitUntilSpecificOutput()
137+
{
138+
$p = $this->getProcess(array(self::$phpBin, __DIR__.'/KillableProcessWithOutput.php'));
139+
$p->start();
140+
141+
$start = microtime(true);
142+
143+
$completeOutput = '';
144+
$p->waitUntil(function ($type, $output) use (&$completeOutput) {
145+
$completeOutput .= $output;
146+
if (false !== strpos($output, 'One more')) {
147+
return true;
148+
}
149+
150+
return false;
151+
});
152+
$p->stop();
153+
154+
$this->assertEquals("First iteration output\nSecond iteration output\nOne more iteration output\n", $completeOutput);
155+
$this->assertLessThan(2, microtime(true) - $start);
156+
}
157+
136158
public function testAllOutputIsActuallyReadOnTermination()
137159
{
138160
// this code will result in a maximum of 2 reads of 8192 bytes by calling

0 commit comments

Comments
 (0)