Passed
Pull Request — master (#18)
by Harry
04:35 queued 23s
created

ProcessRun::poll()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 25
rs 9.2222
c 0
b 0
f 0
ccs 15
cts 15
cp 1
cc 6
nc 5
nop 0
crap 6
1
<?php
2
/**
3
 * This file is part of graze/parallel-process.
4
 *
5
 * Copyright © 2018 Nature Delivered Ltd. <https://www.graze.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license https://github.com/graze/parallel-process/blob/master/LICENSE.md
11
 * @link    https://github.com/graze/parallel-process
12
 */
13
14
namespace Graze\ParallelProcess;
15
16
use Exception;
17
use Graze\ParallelProcess\Event\EventDispatcherTrait;
18
use Graze\ParallelProcess\Event\RunEvent;
19
use Symfony\Component\Process\Exception\ProcessFailedException;
20
use Symfony\Component\Process\Process;
21
use Throwable;
22
23
class ProcessRun implements RunInterface, OutputterInterface
24
{
25
    use EventDispatcherTrait;
26
    use RunningStateTrait;
27
28
    /** @var Process */
29
    private $process;
30
    /** @var bool */
31
    private $successful = false;
32
    /** @var bool */
33
    private $completed = false;
34
    /** @var string */
35
    private $last = '';
36
    /** @var string */
37
    private $lastType = 'std';
38
    /** @var bool */
39
    private $updateOnPoll = true;
40
    /** @var bool */
41
    private $updateOnProcessOutput = true;
42
    /** @var string[] */
43
    private $tags;
44
    /** @var float */
45
    private $priority;
46
47
    /**
48
     * Run constructor.
49
     *
50
     * @param Process  $process
51
     * @param string[] $tags List of key value tags associated with this run
52
     * @param float    $priority
53
     */
54 51
    public function __construct(Process $process, array $tags = [], $priority = 1.0)
55
    {
56 51
        $this->process = $process;
57 51
        $this->tags = $tags;
58 51
        $this->priority = $priority;
59 51
    }
60
61
    /**
62
     * @param float $priority
63
     *
64
     * @return ProcessRun
65
     */
66 1
    public function setPriority($priority)
67
    {
68 1
        $this->priority = $priority;
69 1
        return $this;
70
    }
71
72
    /**
73
     * @return string[]
74
     */
75 45
    protected function getEventNames()
76
    {
77
        return [
78 45
            RunEvent::STARTED,
79
            RunEvent::COMPLETED,
80
            RunEvent::FAILED,
81
            RunEvent::UPDATED,
82
            RunEvent::SUCCESSFUL,
83
        ];
84
    }
85
86
    /**
87
     * Start the process
88
     *
89
     * @return $this
90
     */
91 38
    public function start()
92
    {
93 38
        if (!$this->process->isStarted()) {
94 37
            $this->setStarted();
95 37
            $this->dispatch(RunEvent::STARTED, new RunEvent($this));
96 37
            $this->process->start(
97 37
                function ($type, $data) {
98 21
                    $this->lastType = $type;
99 21
                    foreach (explode("\n", $data) as $line) {
100 21
                        $line = rtrim($line);
101 21
                        if (mb_strlen($line) > 0) {
102 21
                            $this->last = $line;
103 21
                            if ($this->updateOnProcessOutput) {
104 21
                                $this->dispatch(RunEvent::UPDATED, new RunEvent($this));
105
                            }
106
                        }
107
                    }
108 37
                }
109
            );
110 37
            $this->completed = false;
111
        }
112
113 38
        return $this;
114
    }
115
116
    /**
117
     * Poll the process to see if it is still running, and trigger events
118
     *
119
     * @return bool true if the process is currently running (started and not terminated)
120
     */
121 34
    public function poll()
122
    {
123 34
        if ($this->completed || !$this->hasStarted()) {
124 2
            return false;
125
        }
126
127 34
        if ($this->process->isRunning()) {
128 25
            if ($this->updateOnPoll) {
129 16
                $this->dispatch(RunEvent::UPDATED, new RunEvent($this));
130
            }
131 25
            return true;
132
        }
133
134 34
        $this->completed = true;
135 34
        $this->setFinished();
136
137 34
        if ($this->process->isSuccessful()) {
138 30
            $this->successful = true;
139 30
            $this->dispatch(RunEvent::SUCCESSFUL, new RunEvent($this));
140
        } else {
141 5
            $this->dispatch(RunEvent::FAILED, new RunEvent($this));
142
        }
143 34
        $this->dispatch(RunEvent::COMPLETED, new RunEvent($this));
144
145 34
        return false;
146
    }
147
148
    /**
149
     * Return if the underlying process is running
150
     *
151
     * @return bool
152
     */
153 37
    public function isRunning()
154
    {
155 37
        return $this->process->isRunning();
156
    }
157
158
    /**
159
     * @return bool
160
     */
161 28
    public function isSuccessful()
162
    {
163 28
        return $this->successful;
164
    }
165
166
    /**
167
     * @return bool
168
     */
169 46
    public function hasStarted()
170
    {
171 46
        return $this->process->isStarted();
172
    }
173
174
    /**
175
     * @return Process
176
     */
177 6
    public function getProcess()
178
    {
179 6
        return $this->process;
180
    }
181
182
    /**
183
     * @param bool $updateOnPoll
184
     *
185
     * @return $this
186
     */
187 10
    public function setUpdateOnPoll($updateOnPoll)
188
    {
189 10
        $this->updateOnPoll = $updateOnPoll;
190 10
        return $this;
191
    }
192
193
    /**
194
     * @return bool
195
     */
196 2
    public function isUpdateOnPoll()
197
    {
198 2
        return $this->updateOnPoll;
199
    }
200
201
    /**
202
     * @param bool $update
203
     *
204
     * @return $this
205
     */
206 15
    public function setUpdateOnProcessOutput($update)
207
    {
208 15
        $this->updateOnProcessOutput = $update;
209 15
        return $this;
210
    }
211
212
    /**
213
     * @return bool
214
     */
215 2
    public function isUpdateOnProcessOutput()
216
    {
217 2
        return $this->updateOnProcessOutput;
218
    }
219
220
    /**
221
     * @return array
222
     */
223 21
    public function getTags()
224
    {
225 21
        return $this->tags;
226
    }
227
228
    /**
229
     * @return float[]|null the process between 0 and 1 if the run supports it, otherwise null
230
     */
231 15
    public function getProgress()
232
    {
233 15
        return null;
234
    }
235
236
    /**
237
     * @return string
238
     */
239 15
    public function getLastMessage()
240
    {
241 15
        return $this->last;
242
    }
243
244
    /**
245
     * @return string
246
     */
247 9
    public function getLastMessageType()
248
    {
249 9
        return $this->lastType;
250
    }
251
252
    /**
253
     * If the run was unsuccessful, get the error if applicable
254
     *
255
     * @return Exception[]|Throwable[]
256
     */
257 5
    public function getExceptions()
258
    {
259 5
        if ($this->hasStarted() && !$this->isSuccessful()) {
260 4
            return [new ProcessFailedException($this->process)];
261
        }
262 1
        return [];
263
    }
264
265
    /**
266
     * @return float The priority for this run, where the larger the number the higher the priority
267
     */
268 30
    public function getPriority()
269
    {
270 30
        return $this->priority;
271
    }
272
}
273