1616if ( ! class_exists (RuntimeCapabilities::class) ) {
1717 require_once __DIR__ . '/RuntimeCapabilities.php ' ;
1818}
19+ if ( ! class_exists (CommandSpec::class) ) {
20+ require_once __DIR__ . '/CommandSpec.php ' ;
21+ }
1922
2023final class ProcessRunner {
2124
@@ -24,18 +27,23 @@ final class ProcessRunner {
2427 /**
2528 * Execute a shell command and return a normalized result envelope.
2629 *
27- * @param string $ command Shell command to execute.
30+ * @param string|CommandSpec $command Shell command or argv command spec to execute.
2831 * @param array<string,mixed> $options Execution options.
2932 * @return array<string,mixed>|\WP_Error
3033 */
31- public static function run ( string $ command , array $ options = array () ): array |\WP_Error {
34+ public static function run ( string | CommandSpec $ command , array $ options = array () ): array |\WP_Error {
3235 $ timeout_seconds = max (0 , (int ) ( $ options ['timeout_seconds ' ] ?? 0 ));
3336 $ output_cap = max (0 , (int ) ( $ options ['output_cap_bytes ' ] ?? 0 ));
3437 $ on_output = is_callable ($ options ['on_output ' ] ?? null ) ? $ options ['on_output ' ] : null ;
35- $ env = isset ($ options ['env ' ]) && is_array ($ options ['env ' ]) ? $ options ['env ' ] : null ;
36- $ cwd = isset ($ options ['cwd ' ]) && is_string ($ options ['cwd ' ]) && '' !== $ options ['cwd ' ] ? $ options ['cwd ' ] : null ;
38+ $ env = self ::resolve_env ($ command , $ options );
39+ $ cwd = self ::resolve_cwd ($ command , $ options );
40+ $ is_command_spec = $ command instanceof CommandSpec;
41+
42+ if ( $ is_command_spec && null === $ command ->env () && isset ($ options ['env ' ]) && ! is_array ($ options ['env ' ]) ) {
43+ return self ::error ($ options , 'Process command environment must be an array. ' , array ( 'status ' => 400 ));
44+ }
3745
38- if ( 0 === $ timeout_seconds && null === $ on_output && null === $ env && null === $ cwd ) {
46+ if ( ! $ is_command_spec && 0 === $ timeout_seconds && null === $ on_output && null === $ env && null === $ cwd ) {
3947 return self ::run_via_exec ($ command , $ options , $ output_cap );
4048 }
4149
@@ -48,7 +56,9 @@ public static function run( string $command, array $options = array() ): array|\
4856 );
4957 }
5058
51- return self ::run_via_proc_open ($ command , $ options , $ timeout_seconds , $ output_cap , $ on_output , $ cwd , $ env );
59+ $ process_command = $ is_command_spec ? $ command ->argv () : $ command ;
60+
61+ return self ::run_via_proc_open ($ process_command , $ options , $ timeout_seconds , $ output_cap , $ on_output , $ cwd , $ env );
5262 }
5363
5464 /**
@@ -89,7 +99,7 @@ private static function run_via_exec( string $command, array $options, int $outp
8999 * @param array<string,mixed>|null $env
90100 * @return array<string,mixed>|\WP_Error
91101 */
92- private static function run_via_proc_open ( string $ command , array $ options , int $ timeout_seconds , int $ output_cap , ?callable $ on_output , ?string $ cwd , ?array $ env ): array |\WP_Error {
102+ private static function run_via_proc_open ( string | array $ command , array $ options , int $ timeout_seconds , int $ output_cap , ?callable $ on_output , ?string $ cwd , ?array $ env ): array |\WP_Error {
93103 $ descriptor_spec = array (
94104 1 => array ( 'pipe ' , 'w ' ),
95105 2 => array ( 'pipe ' , 'w ' ),
@@ -195,6 +205,31 @@ private static function run_via_proc_open( string $command, array $options, int
195205 return $ result ;
196206 }
197207
208+ /**
209+ * @param string|CommandSpec $command Shell command or argv command spec.
210+ * @param array<string,mixed> $options Execution options.
211+ */
212+ private static function resolve_cwd ( string |CommandSpec $ command , array $ options ): ?string {
213+ if ( isset ($ options ['cwd ' ]) && is_string ($ options ['cwd ' ]) && '' !== $ options ['cwd ' ] ) {
214+ return $ options ['cwd ' ];
215+ }
216+
217+ return $ command instanceof CommandSpec ? $ command ->cwd () : null ;
218+ }
219+
220+ /**
221+ * @param string|CommandSpec $command Shell command or argv command spec.
222+ * @param array<string,mixed> $options Execution options.
223+ * @return array<string,mixed>|null
224+ */
225+ private static function resolve_env ( string |CommandSpec $ command , array $ options ): ?array {
226+ if ( isset ($ options ['env ' ]) && is_array ($ options ['env ' ]) ) {
227+ return $ options ['env ' ];
228+ }
229+
230+ return $ command instanceof CommandSpec ? $ command ->env () : null ;
231+ }
232+
198233 /**
199234 * @param resource $process
200235 * @param array<int,resource> $pipes
0 commit comments