Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 49fa263

Browse filesBrowse files
committed
[Process] Allow a callback whenever the output is disabled
1 parent caae21c commit 49fa263
Copy full SHA for 49fa263

File tree

5 files changed

+77
-41
lines changed
Filter options

5 files changed

+77
-41
lines changed

‎src/Symfony/Component/Process/Pipes/PipesInterface.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Process/Pipes/PipesInterface.php
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ public function readAndWrite($blocking, $close = false);
5353
*/
5454
public function areOpen();
5555

56+
/**
57+
* Returns if pipes are able to read output.
58+
*
59+
* @return bool
60+
*/
61+
public function haveReadSupport();
62+
5663
/**
5764
* Closes file handles and pipes.
5865
*/

‎src/Symfony/Component/Process/Pipes/UnixPipes.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Process/Pipes/UnixPipes.php
+13-5Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ class UnixPipes extends AbstractPipes
2727
/** @var bool */
2828
private $ptyMode;
2929
/** @var bool */
30-
private $disableOutput;
30+
private $haveReadSupport;
3131

32-
public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
32+
public function __construct($ttyMode, $ptyMode, $input, $haveReadSupport)
3333
{
3434
$this->ttyMode = (bool) $ttyMode;
3535
$this->ptyMode = (bool) $ptyMode;
36-
$this->disableOutput = (bool) $disableOutput;
36+
$this->haveReadSupport = (bool) $haveReadSupport;
3737

3838
if (is_resource($input)) {
3939
$this->input = $input;
@@ -52,7 +52,7 @@ public function __destruct()
5252
*/
5353
public function getDescriptors()
5454
{
55-
if ($this->disableOutput) {
55+
if (!$this->haveReadSupport) {
5656
$nullstream = fopen('/dev/null', 'c');
5757

5858
return array(
@@ -191,6 +191,14 @@ public function readAndWrite($blocking, $close = false)
191191
return $read;
192192
}
193193

194+
/**
195+
* {@inheritdoc}
196+
*/
197+
public function haveReadSupport()
198+
{
199+
return $this->haveReadSupport;
200+
}
201+
194202
/**
195203
* {@inheritdoc}
196204
*/
@@ -209,6 +217,6 @@ public function areOpen()
209217
*/
210218
public static function create(Process $process, $input)
211219
{
212-
return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
220+
return new static($process->isTty(), $process->isPty(), $input, !$process->isOutputDisabled() || $process->hasCallback());
213221
}
214222
}

‎src/Symfony/Component/Process/Pipes/WindowsPipes.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Process/Pipes/WindowsPipes.php
+14-6Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ class WindowsPipes extends AbstractPipes
3636
Process::STDERR => 0,
3737
);
3838
/** @var bool */
39-
private $disableOutput;
39+
private $haveReadSupport;
4040

41-
public function __construct($disableOutput, $input)
41+
public function __construct($haveReadSupport, $input)
4242
{
43-
$this->disableOutput = (bool) $disableOutput;
43+
$this->haveReadSupport = (bool) $haveReadSupport;
4444

45-
if (!$this->disableOutput) {
45+
if ($this->haveReadSupport) {
4646
// Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
4747
// Workaround for this problem is to use temporary files instead of pipes on Windows platform.
4848
//
@@ -76,7 +76,7 @@ public function __destruct()
7676
*/
7777
public function getDescriptors()
7878
{
79-
if ($this->disableOutput) {
79+
if (!$this->haveReadSupport) {
8080
$nullstream = fopen('NUL', 'c');
8181

8282
return array(
@@ -138,6 +138,14 @@ public function readAndWrite($blocking, $close = false)
138138
return $read;
139139
}
140140

141+
/**
142+
* {@inheritdoc}
143+
*/
144+
public function haveReadSupport()
145+
{
146+
return $this->haveReadSupport;
147+
}
148+
141149
/**
142150
* {@inheritdoc}
143151
*/
@@ -168,7 +176,7 @@ public function close()
168176
*/
169177
public static function create(Process $process, $input)
170178
{
171-
return new static($process->isOutputDisabled(), $input);
179+
return new static(!$process->isOutputDisabled() || $process->hasCallback(), $input);
172180
}
173181

174182
/**

‎src/Symfony/Component/Process/Process.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Process/Process.php
+30-7Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,11 @@ public function start(callable $callback = null)
256256
if ($this->isRunning()) {
257257
throw new RuntimeException('Process is already running');
258258
}
259-
if ($this->outputDisabled && null !== $callback) {
260-
throw new LogicException('Output has been disabled, enable it to allow the use of a callback.');
261-
}
262259

263260
$this->resetProcessData();
264261
$this->starttime = $this->lastOutputTime = microtime(true);
265262
$this->callback = $this->buildCallback($callback);
266-
$descriptors = $this->getDescriptors();
263+
$descriptors = $this->getDescriptors($callback);
267264

268265
$commandline = $this->commandline;
269266

@@ -356,7 +353,12 @@ public function wait(callable $callback = null)
356353
$this->requireProcessIsStarted(__FUNCTION__);
357354

358355
$this->updateStatus(false);
356+
359357
if (null !== $callback) {
358+
if (!$this->processPipes->haveReadSupport()) {
359+
$this->stop(0);
360+
throw new \LogicException('Pass the callback to the Process:start method or enableOutput to use a callback with Process::wait');
361+
}
360362
$this->callback = $this->buildCallback($callback);
361363
}
362364

@@ -1181,12 +1183,24 @@ public static function isPtySupported()
11811183
return $result = (bool) @proc_open('echo 1', array(array('pty'), array('pty'), array('pty')), $pipes);
11821184
}
11831185

1186+
/**
1187+
* Returns whether a callback is used on underlying process output.
1188+
*
1189+
* @internal
1190+
*
1191+
* @return bool
1192+
*/
1193+
public function hasCallback()
1194+
{
1195+
return (bool) $this->callback;
1196+
}
1197+
11841198
/**
11851199
* Creates the descriptors needed by the proc_open.
11861200
*
11871201
* @return array
11881202
*/
1189-
private function getDescriptors()
1203+
private function getDescriptors(callable $callback = null)
11901204
{
11911205
if ('\\' === DIRECTORY_SEPARATOR) {
11921206
$this->processPipes = WindowsPipes::create($this, $this->input);
@@ -1207,10 +1221,19 @@ private function getDescriptors()
12071221
*
12081222
* @return \Closure A PHP closure
12091223
*/
1210-
protected function buildCallback($callback)
1224+
protected function buildCallback(callable $callback = null)
12111225
{
1226+
if ($this->outputDisabled) {
1227+
return function ($type, $data) use ($callback) {
1228+
if (null !== $callback) {
1229+
call_user_func($callback, $type, $data);
1230+
}
1231+
};
1232+
}
1233+
12121234
$out = self::OUT;
1213-
$callback = function ($type, $data) use ($callback, $out) {
1235+
1236+
return function ($type, $data) use ($callback, $out) {
12141237
if ($out == $type) {
12151238
$this->addOutput($data);
12161239
} else {

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Process/Tests/ProcessTest.php
+13-23Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,19 @@ public function testCallbackIsExecutedForOutput()
305305
$this->assertTrue($called, 'The callback should be executed with the output');
306306
}
307307

308+
public function testCallbackIsExecutedForOutputWheneverOutputIsDisabled()
309+
{
310+
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('echo \'foo\';')));
311+
$p->disableOutput();
312+
313+
$called = false;
314+
$p->run(function ($type, $buffer) use (&$called) {
315+
$called = $buffer === 'foo';
316+
});
317+
318+
$this->assertTrue($called, 'The callback should be executed with the output');
319+
}
320+
308321
public function testGetErrorOutput()
309322
{
310323
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
@@ -1108,29 +1121,6 @@ public function testSetNullIdleTimeoutWhileOutputIsDisabled()
11081121
$this->assertSame($process, $process->setIdleTimeout(null));
11091122
}
11101123

1111-
/**
1112-
* @dataProvider provideStartMethods
1113-
*/
1114-
public function testStartWithACallbackAndDisabledOutput($startMethod, $exception, $exceptionMessage)
1115-
{
1116-
$p = $this->getProcess('foo');
1117-
$p->disableOutput();
1118-
$this->setExpectedException($exception, $exceptionMessage);
1119-
if ('mustRun' === $startMethod) {
1120-
$this->skipIfNotEnhancedSigchild();
1121-
}
1122-
$p->{$startMethod}(function () {});
1123-
}
1124-
1125-
public function provideStartMethods()
1126-
{
1127-
return array(
1128-
array('start', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
1129-
array('run', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
1130-
array('mustRun', 'Symfony\Component\Process\Exception\LogicException', 'Output has been disabled, enable it to allow the use of a callback.'),
1131-
);
1132-
}
1133-
11341124
/**
11351125
* @dataProvider provideOutputFetchingMethods
11361126
* @expectedException \Symfony\Component\Process\Exception\LogicException

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.