@@ -53,6 +53,15 @@ class Command
53
53
*/
54
54
public $ procOptions ;
55
55
56
+ /**
57
+ * @var bool|null whether to set the stdout/stderr streams to non-blocking mode
58
+ * when `proc_open()` is used. This can fix issues with long running
59
+ * commands that hang indefinitely but can cause problems on Windows
60
+ * systems. The default is `null` in which case non-blocking mode is only
61
+ * enabled on non-Windows systems.
62
+ */
63
+ public $ nonBlockingMode ;
64
+
56
65
/**
57
66
* @var null|string the locale to temporarily set before calling `escapeshellargs()`. Default is `null` for none.
58
67
*/
@@ -345,6 +354,13 @@ public function execute()
345
354
$ process = proc_open ($ command , $ descriptors , $ pipes , $ this ->procCwd , $ this ->procEnv , $ this ->procOptions );
346
355
347
356
if (is_resource ($ process )) {
357
+ // Issue #20 Set non-blocking mode to fix hanging processes
358
+ $ nonBlocking = $ this ->nonBlockingMode === null ?
359
+ !$ this ->getIsWindows () : $ this ->nonBlockingMode ;
360
+ if ($ nonBlocking ) {
361
+ stream_set_blocking ($ pipes [1 ], false );
362
+ stream_set_blocking ($ pipes [2 ], false );
363
+ }
348
364
349
365
if ($ this ->_stdIn !==null ) {
350
366
if (is_resource ($ this ->_stdIn ) &&
@@ -362,8 +378,10 @@ public function execute()
362
378
363
379
$ this ->_exitCode = proc_close ($ process );
364
380
365
- if ($ this ->_exitCode !==0 ) {
366
- $ this ->_error = $ this ->_stdErr ? $ this ->_stdErr : "Failed without error message: $ command " ;
381
+ if ($ this ->_exitCode !== 0 ) {
382
+ $ this ->_error = $ this ->_stdErr ?
383
+ $ this ->_stdErr :
384
+ "Failed without error message: $ command (Exit code: {$ this ->_exitCode }) " ;
367
385
return false ;
368
386
}
369
387
} else {
0 commit comments