Completed
Push — master ( 7df873...57a8d7 )
by Greg
02:28
created

src/Task/Base/ParallelExec.php (1 issue)

mismatching argument types.

Documentation Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Robo\Task\Base;
3
4
use Robo\Contract\CommandInterface;
5
use Robo\Contract\PrintedInterface;
6
use Robo\Result;
7
use Robo\Task\BaseTask;
8
use Symfony\Component\Process\Exception\ProcessTimedOutException;
9
use Symfony\Component\Process\Process;
10
11
/**
12
 * Class ParallelExecTask
13
 *
14
 * ``` php
15
 * <?php
16
 * $this->taskParallelExec()
17
 *   ->process('php ~/demos/script.php hey')
18
 *   ->process('php ~/demos/script.php hoy')
19
 *   ->process('php ~/demos/script.php gou')
20
 *   ->run();
21
 * ?>
22
 * ```
23
 */
24
class ParallelExec extends BaseTask implements CommandInterface, PrintedInterface
25
{
26
    use \Robo\Common\CommandReceiver;
27
28
    /**
29
     * @var Process[]
30
     */
31
    protected $processes = [];
32
33
    /**
34
     * @var null|int
35
     */
36
    protected $timeout = null;
37
38
    /**
39
     * @var null|int
40
     */
41
    protected $idleTimeout = null;
42
43
    /**
44
     * @var null|int
45
     */
46
    protected $waitInterval = 0;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $isPrinted = false;
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function getPrinted()
57
    {
58
        return $this->isPrinted;
59
    }
60
61
    /**
62
     * @param bool $isPrinted
63
     *
64
     * @return $this
65
     */
66
    public function printed($isPrinted = true)
67
    {
68
        $this->isPrinted = $isPrinted;
69
        return $this;
70
    }
71
72
    /**
73
     * @param string|\Robo\Contract\CommandInterface $command
74
     *
75
     * @return $this
76
     */
77
    public function process($command)
78
    {
79
        // TODO: Symfony 4 requires that we supply the working directory.
80
        $this->processes[] = new Process($this->receiveCommand($command), getcwd());
0 ignored issues
show
$this->receiveCommand($command) is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
81
        return $this;
82
    }
83
84
    /**
85
     * Stops process if it runs longer then `$timeout` (seconds).
86
     *
87
     * @param int $timeout
88
     *
89
     * @return $this
90
     */
91
    public function timeout($timeout)
92
    {
93
        $this->timeout = $timeout;
94
        return $this;
95
    }
96
97
    /**
98
     * Stops process if it does not output for time longer then `$timeout` (seconds).
99
     *
100
     * @param int $idleTimeout
101
     *
102
     * @return $this
103
     */
104
    public function idleTimeout($idleTimeout)
105
    {
106
        $this->idleTimeout = $idleTimeout;
107
        return $this;
108
    }
109
110
    /**
111
     * Parallel processing will wait `$waitInterval` seconds after launching each process and before
112
     * the next one.
113
     *
114
     * @param int $waitInterval
115
     *
116
     * @return $this
117
     */
118
    public function waitInterval($waitInterval)
119
    {
120
        $this->waitInterval = $waitInterval;
121
        return $this;
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function getCommand()
128
    {
129
        return implode(' && ', $this->processes);
130
    }
131
132
    /**
133
     * @return int
134
     */
135
    public function progressIndicatorSteps()
136
    {
137
        return count($this->processes);
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function run()
144
    {
145
        $this->startProgressIndicator();
146
        $running = [];
147
        $queue = $this->processes;
148
        $nextTime = time();
149
        while (true) {
150
            if (($nextTime <= time()) && !empty($queue)) {
151
                $process = array_shift($queue);
152
                $process->setIdleTimeout($this->idleTimeout);
153
                $process->setTimeout($this->timeout);
154
                $process->start();
155
                $this->printTaskInfo($process->getCommandLine());
156
                $running[] = $process;
157
                $nextTime = time() + $this->waitInterval;
158
            }
159
            foreach ($running as $k => $process) {
160
                try {
161
                    $process->checkTimeout();
162
                } catch (ProcessTimedOutException $e) {
163
                    $this->printTaskWarning("Process timed out for {command}", ['command' => $process->getCommandLine(), '_style' => ['command' => 'fg=white;bg=magenta']]);
164
                }
165
                if (!$process->isRunning()) {
166
                    $this->advanceProgressIndicator();
167
                    if ($this->isPrinted) {
168
                        $this->printTaskInfo("Output for {command}:\n\n{output}", ['command' => $process->getCommandLine(), 'output' => $process->getOutput(), '_style' => ['command' => 'fg=white;bg=magenta']]);
169
                        $errorOutput = $process->getErrorOutput();
170
                        if ($errorOutput) {
171
                            $this->printTaskError(rtrim($errorOutput));
172
                        }
173
                    }
174
                    unset($running[$k]);
175
                }
176
            }
177
            if (empty($running) && empty($queue)) {
178
                break;
179
            }
180
            usleep(1000);
181
        }
182
        $this->stopProgressIndicator();
183
184
        $errorMessage = '';
185
        $exitCode = 0;
186
        foreach ($this->processes as $p) {
187
            if ($p->getExitCode() === 0) {
188
                continue;
189
            }
190
            $errorMessage .= "'" . $p->getCommandLine() . "' exited with code ". $p->getExitCode()." \n";
191
            $exitCode = max($exitCode, $p->getExitCode());
192
        }
193
        if (!$errorMessage) {
194
            $this->printTaskSuccess('{process-count} processes finished running', ['process-count' => count($this->processes)]);
195
        }
196
197
        return new Result($this, $exitCode, $errorMessage, ['time' => $this->getExecutionTime()]);
198
    }
199
}
200