Completed
Push — master ( 91c0a8...4616fd )
by Sebastian
01:37
created

ProcOpen::handleOutput()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
/**
3
 * This file is part of SebastianFeldmann\Cli.
4
 *
5
 * (c) Sebastian Feldmann <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace SebastianFeldmann\Cli\Processor;
11
12
use RuntimeException;
13
use SebastianFeldmann\Cli\Command\Result;
14
use SebastianFeldmann\Cli\Output;
15
use SebastianFeldmann\Cli\Processor;
16
17
/**
18
 * Class ProcOpen
19
 *
20
 * @package SebastianFeldmann\Cli
21
 * @author  Sebastian Feldmann <[email protected]>
22
 * @link    https://github.com/sebastianfeldmann/cli
23
 * @since   Class available since Release 0.9.0
24
 */
25
class ProcOpen implements Processor
26
{
27
    /**
28
     * Handles the output of stdOut
29
     *
30
     * @var \SebastianFeldmann\Cli\Output
31
     */
32
    private $stdOutOutput;
33
34
    /**
35
     * Handles the Output of stdErr
36
     *
37
     * @var \SebastianFeldmann\Cli\Output
38
     */
39
    private $stdErrOutput;
40
41
    /**
42
     * ProcOpen constructor
43
     *
44
     * @param \SebastianFeldmann\Cli\Output $stdOut
45
     * @param \SebastianFeldmann\Cli\Output $stdErr
46
     */
47 3
    public function __construct(Output $stdOut = null, Output $stdErr = null)
48
    {
49 3
        $this->stdOutOutput = $stdOut ?? new Output\Silent();
50 3
        $this->stdErrOutput = $stdErr ?? new Output\Silent();
51 3
    }
52
53
    /**
54
     * Execute the command
55
     *
56
     * @param  string $cmd
57
     * @param  int[]  $acceptableExitCodes
58
     * @return \SebastianFeldmann\Cli\Command\Result
59
     */
60 3
    public function run(string $cmd, array $acceptableExitCodes = [0]) : Result
61
    {
62 3
        $old    = error_reporting(0);
63 3
        $stdOut = '';
64 3
        $stdErr = '';
65 3
        $spec   = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']];
66
67 3
        $process = proc_open($cmd, $spec, $pipes);
68 3
        if (!is_resource($process)) {
69
            throw new RuntimeException('can\'t execute \'proc_open\'');
70
        }
71
72
        // Loop on process until it exits
73
        do {
74 3
            $status = proc_get_status($process);
75 3
            $out    = !feof($pipes[1]) ? (string) fgets($pipes[1]) : '';
76 3
            $err    = !feof($pipes[2]) ? (string) fgets($pipes[2]) : '';
77
78 3
            $this->handleOutput($out, $err);
79
80 3
            $stdOut .= $out;
81 3
            $stdErr .= $err;
82 3
        } while ($status['running']);
83
84
        // According to documentation, the exit code is only valid the first call
85
        // after a process is finished. We can't rely on the return value of
86
        // proc_close because proc_get_status will read the exit code first.
87 3
        $code = $status['exitcode'];
88 3
        proc_close($process);
89 3
        error_reporting($old);
90
91 3
        return new Result($cmd, $code, $stdOut, $stdErr, '', $acceptableExitCodes);
92
    }
93
94
    /**
95
     * Uses the output handlers to process the given stdOut and stdErr output
96
     *
97
     * @param  string $stdOut
98
     * @param  string $stdErr
99
     * @return void
100
     */
101 3
    private function handleOutput(string $stdOut, string $stdErr) : void
102
    {
103 3
        $this->stdOutOutput->write($stdOut);
104 3
        $this->stdErrOutput->write($stdErr);
105 3
    }
106
}
107