Skip to content

Commit 70877c9

Browse files
Merge pull request #40 from utopia-php/PLA-1644
feat: support array-based commands in execute to avoid allocating subshell
2 parents f8af1d6 + 0632875 commit 70877c9

2 files changed

Lines changed: 45 additions & 3 deletions

File tree

src/CLI/Console.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,19 @@ public static function exit(int $status = 0): void
124124
*
125125
* This function was inspired by: https://stackoverflow.com/a/13287902/2299554
126126
*
127-
* @param string $cmd
127+
* @param array|string $cmd
128128
* @param string $input
129129
* @param string $output
130130
* @param int $timeout
131131
* @return int
132132
*/
133-
public static function execute(string $cmd, string $input, string &$output, int $timeout = -1, callable $onProgress = null): int
133+
public static function execute(array|string $cmd, string $input, string &$output, int $timeout = -1, callable $onProgress = null): int
134134
{
135-
$cmd = '( '.$cmd.' ) 3>/dev/null ; echo $? >&3';
135+
// If the $cmd is passed as string, it will be wrapped into a subshell by \proc_open
136+
// Forward stdout and exit codes from the subshell.
137+
if (is_string($cmd)) {
138+
$cmd = '( '.$cmd.' ) 3>/dev/null ; echo $? >&3';
139+
}
136140

137141
$pipes = [];
138142
$process = \proc_open(

tests/CLI/ConsoleTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,44 @@ public function testExecuteBasic()
3636
$this->assertEquals(0, $code);
3737
}
3838

39+
public function testExecuteArray()
40+
{
41+
$output = '';
42+
$input = '';
43+
$cmd = ['php', '-r', "echo 'hello world';"];
44+
$code = Console::execute($cmd, $input, $output, 10);
45+
46+
$this->assertEquals('hello world', $output);
47+
$this->assertEquals(0, $code);
48+
}
49+
50+
// Validate existing environment variables are passed down to the executed command.
51+
public function testExecuteEnvVariables()
52+
{
53+
$randomData = base64_encode(random_bytes(10));
54+
putenv("FOO={$randomData}");
55+
56+
$output = '';
57+
$input = '';
58+
$cmd = ['printenv'];
59+
$code = Console::execute($cmd, $input, $output, 10);
60+
61+
$this->assertEquals(0, $code);
62+
63+
$data = [];
64+
foreach (explode("\n", $output) as $row) {
65+
if (empty($row)) {
66+
continue;
67+
}
68+
$kv = explode('=', $row, 2);
69+
$this->assertEquals(2, count($kv), $row);
70+
$data[$kv[0]] = $kv[1];
71+
}
72+
73+
$this->assertArrayHasKey('FOO', $data);
74+
$this->assertEquals($randomData, $data['FOO']);
75+
}
76+
3977
public function testExecuteStream()
4078
{
4179
$output = '';

0 commit comments

Comments
 (0)