From 06328751115d8f1e02f8a6c1ea97c067167145a9 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Thu, 19 Sep 2024 18:23:18 +0200 Subject: [PATCH] feat: support array-based commands in execute to avoid allocating subshell --- src/CLI/Console.php | 10 +++++++--- tests/CLI/ConsoleTest.php | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/CLI/Console.php b/src/CLI/Console.php index 94407d5..8014859 100644 --- a/src/CLI/Console.php +++ b/src/CLI/Console.php @@ -124,15 +124,19 @@ public static function exit(int $status = 0): void * * This function was inspired by: https://stackoverflow.com/a/13287902/2299554 * - * @param string $cmd + * @param array|string $cmd * @param string $input * @param string $output * @param int $timeout * @return int */ - public static function execute(string $cmd, string $input, string &$output, int $timeout = -1, callable $onProgress = null): int + public static function execute(array|string $cmd, string $input, string &$output, int $timeout = -1, callable $onProgress = null): int { - $cmd = '( '.$cmd.' ) 3>/dev/null ; echo $? >&3'; + // If the $cmd is passed as string, it will be wrapped into a subshell by \proc_open + // Forward stdout and exit codes from the subshell. + if (is_string($cmd)) { + $cmd = '( '.$cmd.' ) 3>/dev/null ; echo $? >&3'; + } $pipes = []; $process = \proc_open( diff --git a/tests/CLI/ConsoleTest.php b/tests/CLI/ConsoleTest.php index 61e5034..afae8f5 100755 --- a/tests/CLI/ConsoleTest.php +++ b/tests/CLI/ConsoleTest.php @@ -36,6 +36,44 @@ public function testExecuteBasic() $this->assertEquals(0, $code); } + public function testExecuteArray() + { + $output = ''; + $input = ''; + $cmd = ['php', '-r', "echo 'hello world';"]; + $code = Console::execute($cmd, $input, $output, 10); + + $this->assertEquals('hello world', $output); + $this->assertEquals(0, $code); + } + + // Validate existing environment variables are passed down to the executed command. + public function testExecuteEnvVariables() + { + $randomData = base64_encode(random_bytes(10)); + putenv("FOO={$randomData}"); + + $output = ''; + $input = ''; + $cmd = ['printenv']; + $code = Console::execute($cmd, $input, $output, 10); + + $this->assertEquals(0, $code); + + $data = []; + foreach (explode("\n", $output) as $row) { + if (empty($row)) { + continue; + } + $kv = explode('=', $row, 2); + $this->assertEquals(2, count($kv), $row); + $data[$kv[0]] = $kv[1]; + } + + $this->assertArrayHasKey('FOO', $data); + $this->assertEquals($randomData, $data['FOO']); + } + public function testExecuteStream() { $output = '';