15
15
use Symfony \Component \Process \Exception \LogicException ;
16
16
use Symfony \Component \Process \Exception \ProcessFailedException ;
17
17
use Symfony \Component \Process \Exception \ProcessSignaledException ;
18
+ use Symfony \Component \Process \Exception \ProcessStartFailedException ;
18
19
use Symfony \Component \Process \Exception \ProcessTimedOutException ;
19
20
use Symfony \Component \Process \Exception \RuntimeException ;
20
21
use Symfony \Component \Process \Pipes \UnixPipes ;
@@ -233,11 +234,11 @@ public function __clone()
233
234
*
234
235
* @return int The exit status code
235
236
*
236
- * @throws RuntimeException When process can't be launched
237
- * @throws RuntimeException When process is already running
238
- * @throws ProcessTimedOutException When process timed out
239
- * @throws ProcessSignaledException When process stopped after receiving signal
240
- * @throws LogicException In case a callback is provided and output has been disabled
237
+ * @throws ProcessStartFailedException When process can't be launched
238
+ * @throws RuntimeException When process is already running
239
+ * @throws ProcessTimedOutException When process timed out
240
+ * @throws ProcessSignaledException When process stopped after receiving signal
241
+ * @throws LogicException In case a callback is provided and output has been disabled
241
242
*
242
243
* @final
243
244
*/
@@ -284,9 +285,9 @@ public function mustRun(callable $callback = null, array $env = []): static
284
285
* @param callable|null $callback A PHP callback to run whenever there is some
285
286
* output available on STDOUT or STDERR
286
287
*
287
- * @throws RuntimeException When process can't be launched
288
- * @throws RuntimeException When process is already running
289
- * @throws LogicException In case a callback is provided and output has been disabled
288
+ * @throws ProcessStartFailedException When process can't be launched
289
+ * @throws RuntimeException When process is already running
290
+ * @throws LogicException In case a callback is provided and output has been disabled
290
291
*/
291
292
public function start (callable $ callback = null , array $ env = []): void
292
293
{
@@ -306,12 +307,7 @@ public function start(callable $callback = null, array $env = []): void
306
307
$ env += '\\' === \DIRECTORY_SEPARATOR ? array_diff_ukey ($ this ->getDefaultEnv (), $ env , 'strcasecmp ' ) : $ this ->getDefaultEnv ();
307
308
308
309
if (\is_array ($ commandline = $ this ->commandline )) {
309
- $ commandline = implode (' ' , array_map ($ this ->escapeArgument (...), $ commandline ));
310
-
311
- if ('\\' !== \DIRECTORY_SEPARATOR ) {
312
- // exec is mandatory to deal with sending a signal to the process
313
- $ commandline = 'exec ' .$ commandline ;
314
- }
310
+ $ commandline = array_values (array_map (strval (...), $ commandline ));
315
311
} else {
316
312
$ commandline = $ this ->replacePlaceholders ($ commandline , $ env );
317
313
}
@@ -322,6 +318,11 @@ public function start(callable $callback = null, array $env = []): void
322
318
// last exit code is output on the fourth pipe and caught to work around --enable-sigchild
323
319
$ descriptors [3 ] = ['pipe ' , 'w ' ];
324
320
321
+ if (\is_array ($ commandline )) {
322
+ // exec is mandatory to deal with sending a signal to the process
323
+ $ commandline = 'exec ' .$ this ->buildShellCommandline ($ commandline );
324
+ }
325
+
325
326
// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
326
327
$ commandline = '{ ( ' .$ commandline .') <&3 3<&- 3>/dev/null & } 3<&0; ' ;
327
328
$ commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code ' ;
@@ -338,10 +339,20 @@ public function start(callable $callback = null, array $env = []): void
338
339
throw new RuntimeException (sprintf ('The provided cwd "%s" does not exist. ' , $ this ->cwd ));
339
340
}
340
341
341
- $ process = @proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ envPairs , $ this ->options );
342
+ $ lastError = null ;
343
+ set_error_handler (function ($ type , $ msg ) use (&$ lastError ) {
344
+ $ lastError = $ msg ;
345
+
346
+ return true ;
347
+ });
348
+ try {
349
+ $ process = @proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ envPairs , $ this ->options );
350
+ } finally {
351
+ restore_error_handler ();
352
+ }
342
353
343
354
if (!\is_resource ($ process )) {
344
- throw new RuntimeException ( ' Unable to launch a new process. ' );
355
+ throw new ProcessStartFailedException ( $ this , $ lastError );
345
356
}
346
357
$ this ->process = $ process ;
347
358
$ this ->status = self ::STATUS_STARTED ;
@@ -366,8 +377,8 @@ public function start(callable $callback = null, array $env = []): void
366
377
* @param callable|null $callback A PHP callback to run whenever there is some
367
378
* output available on STDOUT or STDERR
368
379
*
369
- * @throws RuntimeException When process can't be launched
370
- * @throws RuntimeException When process is already running
380
+ * @throws ProcessStartFailedException When process can't be launched
381
+ * @throws RuntimeException When process is already running
371
382
*
372
383
* @see start()
373
384
*
@@ -943,7 +954,7 @@ public function getLastOutputTime(): ?float
943
954
*/
944
955
public function getCommandLine (): string
945
956
{
946
- return \is_array ( $ this ->commandline ) ? implode ( ' ' , array_map ( $ this ->escapeArgument (...), $ this -> commandline )) : $ this -> commandline ;
957
+ return $ this ->buildShellCommandline ( $ this ->commandline );
947
958
}
948
959
949
960
/**
@@ -1472,8 +1483,18 @@ private function doSignal(int $signal, bool $throwException): bool
1472
1483
return true ;
1473
1484
}
1474
1485
1475
- private function prepareWindowsCommandLine (string $ cmd , array &$ env ): string
1486
+ private function buildShellCommandline (string |array $ commandline ): string
1487
+ {
1488
+ if (\is_string ($ commandline )) {
1489
+ return $ commandline ;
1490
+ }
1491
+
1492
+ return implode (' ' , array_map ($ this ->escapeArgument (...), $ commandline ));
1493
+ }
1494
+
1495
+ private function prepareWindowsCommandLine (string |array $ cmd , array &$ env ): string
1476
1496
{
1497
+ $ cmd = $ this ->buildShellCommandline ($ cmd );
1477
1498
$ uid = uniqid ('' , true );
1478
1499
$ cmd = preg_replace_callback (
1479
1500
'/"(?:(
0 commit comments