8000 feature #8655 Adds PTY mode & convenience method mustRun() (schmittjoh) · symfony/symfony@51d3d62 · GitHub
[go: up one dir, main page]

Skip to content

Commit 51d3d62

Browse files
committed
feature #8655 Adds PTY mode & convenience method mustRun() (schmittjoh)
This PR was merged into the 2.5-dev branch. Discussion ---------- Adds PTY mode & convenience method mustRun() This makes two additions. I've split them into separate commits so that you can pull them separately if required. 1. Adds PTY mode. In contrast to the existing TTY mode, the proc_open call becomes the master not the process currently executing. 2. Adds a ``mustRun`` method This is merely for convenience: ```php # Before $proc = new Process($cmd); if (0 !== $proc->run()) { throw new ProcessFailedException($proc); } $proc = new Process($cmd); if (0 !== $proc->run()) { throw new ProcessFailedException($proc); } # After (new Process($cmd))->mustRun(); (new Process($cmd))->mustRun(); Commits ------- dbd264a adds cache for isPtySupported() 6c11207 attempts to fix tests on Travis 2ff1870 adds convenience method mustRun 53441aa adds support for PTY mode
2 parents 7affb71 + dbd264a commit 51d3d62

File tree

5 files changed

+147
-2
lines changed

5 files changed

+147
-2
lines changed

src/Symfony/Component/Process/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
2.5.0
5+
-----
6+
7+
* added support for PTY mode
8+
* added the convenience method "mustRun"
9+
410
2.4.0
511
-----
612

src/Symfony/Component/Process/Process.php

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Process\Exception\InvalidArgumentException;
1515
use Symfony\Component\Process\Exception\LogicException;
16+
use Symfony\Component\Process\Exception\ProcessFailedException;
1617
use Symfony\Component\Process\Exception\ProcessTimedOutException;
1718
use Symfony\Component\Process\Exception\RuntimeException;
1819

@@ -62,6 +63,7 @@ class Process
6263
private $incrementalOutputOffset;
6364
private $incrementalErrorOutputOffset;
6465
private $tty;
66+
private $pty;
6567

6668
private $useFileHandles = false;
6769
/** @var ProcessPipes */
@@ -158,6 +160,7 @@ public function __construct($commandline, $cwd = null, array $env = null, $stdin
158160
$this->stdin = $stdin;
159161
$this->setTimeout($timeout);
160162
$this->useFileHandles = defined('PHP_WINDOWS_VERSION_BUILD');
163+
$this->pty = false;
161164
$this->enhanceWindowsCompatibility = true;
162165
$this->enhanceSigchildCompatibility = !defined('PHP_WINDOWS_VERSION_BUILD') && $this->isSigchildEnabled();
163166
$this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
@@ -200,6 +203,25 @@ public function run($callback = null)
200203
return $this->wait();
201204
}
202205

206+
/**
207+
* Runs the process.
208+
*
209+
* This is identical to run() except that an exception is thrown if the process
210+
* exits with a non-zero exit code.
211+
*
212+
* @param callable|null $callback
213+
*
214+
* @return self
215+
*/
216+
public function mustRun($callback = null)
217+
{
218+
if (0 !== $this->run($callback)) {
219+
throw new ProcessFailedException($this);
220+
}
221+
222+
return $this;
223+
}
224+
203225
/**
204226
* Starts the process and returns after sending the STDIN.
205227
*
@@ -809,6 +831,30 @@ public function isTty()
809831
return $this->tty;
810832
}
811833

834+
/**
835+
* Sets PTY mode.
836+
*
837+
* @param Boolean $bool
838+
*
839+
* @return self
840+
*/
841+
public function setPty($bool)
842+
{
843+
$this->pty = (Boolean) $bool;
844+
845+
return $this;
846+
}
847+
848+
/**
849+
* Returns PTY state.
850+
*
851+
* @return Boolean
852 B41A +
*/
853+
public function isPty()
854+
{
855+
return $this->pty;
856+
}
857+
812858
/**
813859
* Gets the working directory.
814860
*
@@ -1000,14 +1046,41 @@ public function checkTimeout()
10001046
}
10011047
}
10021048

1049+
/**
1050+
* Returns whether PTY is supported on the current operating system.
1051+
*
1052+
* @return Boolean
1053+
*/
1054+
public static function isPtySupported()
1055+
{
1056+
static $result;
1057+
1058+
if (null !== $result) {
1059+
return $result;
1060+
}
1061+
1062+
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
1063+
return $result = false;
1064+
}
1065+
1066+
$proc = @proc_open('echo 1', array(array('pty'), array('pty'), array('pty')), $pipes);
1067+
if (is_resource($proc)) {
1068+
proc_close($proc);
1069+
1070+
return $result = true;
1071+
}
1072+
1073+
return $result = false;
1074+
}
1075+
10031076
/**
10041077
* Creates the descriptors needed by the proc_open.
10051078
*
10061079
* @return array
10071080
*/
10081081
private function getDescriptors()
10091082
{
1010-
$this->processPipes = new ProcessPipes($this->useFileHandles, $this->tty);
1083+
$this->processPipes = new ProcessPipes($this->useFileHandles, $this->tty, $this->pty);
10111084
$descriptors = $this->processPipes->getDescriptors();
10121085

10131086
if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {

src/Symfony/Component/Process/ProcessPipes.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ class ProcessPipes
2828
private $useFiles;
2929
/** @var Boolean */
3030
private $ttyMode;
31+
/** @var Boolean */
32+
private $ptyMode;
3133

32-
public function __construct($useFiles, $ttyMode)
34+
public function __construct($useFiles, $ttyMode, $ptyMode = false)
3335
{
3436
$this->useFiles = (Boolean) $useFiles;
3537
$this->ttyMode = (Boolean) $ttyMode;
38+
$this->ptyMode = (Boolean) $ptyMode;
3639

3740
// Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
3841
// Workaround for this problem is to use temporary files instead of pipes on Windows platform.
@@ -117,6 +120,12 @@ public function getDescriptors()
117120
array('file', '/dev/tty', 'w'),
118121
array('file', '/dev/tty', 'w'),
119122
);
123+
} elseif ($this->ptyMode && Porcess::isPtySupported()) {
124+
$descriptors = array(
125+
array('pty'),
126+
array('pty'),
127+
array('pty'),
128+
);
120129
}
121130

122131
return array(

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,45 @@ public function testTTYCommand()
247247
$this->assertSame(Process::STATUS_TERMINATED, $process->getStatus());
248248
}
249249

250+
/**
251+
* @group pty
252+
*/
253+
public function testPTYCommand()
254+
{
255+
if (!Process::isPtySupported()) {
256+
$this->markTestSkipped('PTY is not supported on this operating system.');
257+
}
258+
259+
$process = $this->getProcess('echo "foo"');
260+
$process->setPty(true);
261+
$process->run();
262+
263+
$this->assertSame(Process::STATUS_TERMINATED, $process->getStatus());
264+
$this->assertEquals("foo\r\n", $process->getOutput());
265+
}
266+
267+
/**
268+
* @group mustRun
269+
*/
270+
public function testMustRun()
271+
{
272+
$process = $this->getProcess('echo "foo"');
273+
274+
$this->assertSame($process, $process->mustRun());
275+
$this->assertEquals("foo\n", $process->getOutput());
276+
$this->assertEquals(0, $process->getExitCode());
277+
}
278+
279+
/**
280+
* @expectedException Symfony\Component\Process\Exception\ProcessFailedException
281+
* @group mustRun
282+
*/
283+
public function testMustRunThrowsException()
284+
{
285+
$process = $this->getProcess('exit 1');
286+
$process->mustRun();
287+
}
288+
250289
public function testExitCodeText()
251290
{
252291
$process = $this->getProcess('');

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ public function testExitCodeCommandFailed()
4545
parent::testExitCodeCommandFailed();
4646
}
4747

48+
/**
49+
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
50+
* @group mustRun
51+
*/
52+
public function testMustRun()
53+
{
54+
parent::testMustRun();
55+
}
56+
57+
/**
58+
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
59+
* @group mustRun
60+
*/
61+
public function testMustRunThrowsException()
62+
{
63+
parent::testMustRunThrowsException();
64+
}
65+
4866
/**
4967
* @expectedException \Symfony\Component\Process\Exception\RuntimeException
5068
*/

0 commit comments

Comments
 (0)
0