Completed
Pull Request — master (#12)
by Harry
11:21
created

Table::formatRow()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 0
cts 0
cp 0
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 10
nop 4
crap 30
1
<?php
2
/**
3
 * This file is part of graze/parallel-process.
4
 *
5
 * Copyright (c) 2017 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\DiffRenderer\DiffConsoleOutput;
18
use Graze\DiffRenderer\Terminal\TerminalInterface;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Process\Exception\ProcessFailedException;
21
use Symfony\Component\Process\Process;
22
23
class Table
24
{
25
    const SPINNER = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
26
27
    /** @var Pool */
28
    private $processPool;
29
    /** @var string[] */
30
    private $rows = [];
31
    /** @var Exception[] */
32
    private $exceptions;
33
    /** @var int[] */
34
    private $maxLengths = [];
35
    /** @var DiffConsoleOutput */
36
    private $output;
37
    /** @var TerminalInterface */
38
    private $terminal;
39
    /** @var bool */
40
    private $showOutput = true;
41
    /** @var bool */
42
    private $showSummary = true;
43
44
    /**
45
     * Table constructor.
46
     *
47
     * @param OutputInterface $output
48
     * @param Pool|null       $pool
49
     */
50 15 View Code Duplication
    public function __construct(OutputInterface $output, Pool $pool = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
    {
52 12
        $this->processPool = $pool ?: new Pool();
53 12
        if (!$output instanceof DiffConsoleOutput) {
54
            $this->output = new DiffConsoleOutput($output);
55
            $this->output->setTrim(true);
56
        } else {
57 15
            $this->output = $output;
58 3
        }
59
        $this->terminal = $this->output->getTerminal();
60 12
        $this->exceptions = [];
61
    }
62
63
    /**
64
     * Parses the rows to determine the key lengths to make a pretty table
65
     *
66
     * @param array $data
67
     */
68 2 View Code Duplication
    private function updateRowKeyLengths(array $data = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
    {
70
        $lengths = array_map('mb_strlen', $data);
71
72
        $keys = array_merge(array_keys($lengths), array_keys($this->maxLengths));
73
74
        foreach ($keys as $key) {
75 2
            if (!isset($this->maxLengths[$key])
76
                || (isset($lengths[$key]) && $lengths[$key] > $this->maxLengths[$key])
77
            ) {
78 2
                $this->maxLengths[$key] = $lengths[$key];
79
            }
80
        }
81
    }
82
83
    /**
84
     * @param array  $data
85
     * @param string $status
86
     * @param float  $duration
87
     * @param string $extra
88
     *
89
     * @return string
90
     */
91
    private function formatRow(array $data, $status, $duration, $extra = '')
92
    {
93
        $info = [];
94
        foreach ($data as $key => $value) {
95
            $length = isset($this->maxLengths[$key]) ? '-' . $this->maxLengths[$key] : '';
96
            if (is_int($key)) {
97
                $info[] = sprintf("%{$length}s", $value);
98
            } else {
99
                $info[] = sprintf("<info>%s</info>: %{$length}s", $key, $value);
100
            }
101
        }
102
        $extra = $extra ? '  ' . $this->terminal->filter($extra) : '';
103
        return sprintf("%s (<comment>%6.2fs</comment>) %s%s", implode(' ', $info), $duration, $status, $extra);
104
    }
105
106
    /**
107
     * @param Process $process
108
     * @param array   $data
109
     */
110 8
    public function add(Process $process, array $data = [])
111
    {
112
        $index = count($this->rows);
113
        $this->rows[$index] = $this->formatRow($data, '', 0);
114 8
        $spinner = 0;
115
116
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
117
            $onProgress = function ($process, $duration, $last) use ($index, $data, &$spinner) {
118 5
                $this->rows[$index] = $this->formatRow(
119
                    $data,
120 5
                    mb_substr(static::SPINNER, $spinner++, 1),
121
                    $duration,
122 5
                    ($this->showOutput ? $last : '')
123
                );
124
                if ($spinner > mb_strlen(static::SPINNER) - 1) {
125 1
                    $spinner = 0;
126
                }
127
                $this->render();
128
            };
129
        } else {
130 2
            $onProgress = null;
131 6
        }
132
133
        $run = new Run(
134
            $process,
135
            function ($process, $duration, $last) use ($index, $data) {
136
                $this->rows[$index] = $this->formatRow($data, "<info>✓</info>", $duration, $last);
137
                $this->render($index);
138 2
            },
139 6
            function ($process, $duration, $last) use ($index, $data) {
140
                $this->rows[$index] = $this->formatRow($data, "<error>x</error>", $duration, $last);
141
                $this->render($index);
142
                $this->exceptions[] = new ProcessFailedException($process);
143 6
            },
144
            $onProgress
145
        );
146
        $run->setUpdateOnProcessOutput(false);
147
        $this->processPool->add($run);
148
149
        $this->updateRowKeyLengths($data);
150
    }
151
152
    /**
153
     * @return string
154
     */
155 1
    private function getSummary()
156
    {
157
        if ($this->processPool->hasStarted()) {
158
            if ($this->processPool->isRunning()) {
159
                return sprintf(
160
                    '<comment>Total</comment>: %2d, <comment>Running</comment>: %2d, <comment>Waiting</comment>: %2d',
161
                    $this->processPool->count(),
162
                    count($this->processPool->getRunning()),
163
                    count($this->processPool->getWaiting())
164
                );
165
            } else {
166 1
                return '';
167
            }
168
        } else {
169 1
            return 'waiting...';
170
        }
171
    }
172
173
    /**
174
     * Render a specific row
175
     *
176
     * @param int $row
177
     */
178 2
    private function render($row = 0)
179
    {
180
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
181
            $rows = ($this->showSummary ? array_merge($this->rows, [$this->getSummary()]) : $this->rows);
182
            $this->output->reWrite($rows, !$this->showSummary);
183
        } else {
184
            $this->output->writeln($this->rows[$row]);
185
        }
186 2
    }
187
188
    /**
189
     * @param float $checkInterval
190
     *
191
     * @return bool true if all processes were successful
192
     * @throws Exception
193
     */
194 9
    public function run($checkInterval = Pool::CHECK_INTERVAL)
195
    {
196
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
197
            $this->render();
198
        }
199
        $output = $this->processPool->run($checkInterval);
200
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE && $this->showSummary) {
201
            $this->render();
202
        }
203
204
        if (count($this->exceptions) > 0) {
205 3
            foreach ($this->exceptions as $exception) {
206
                $this->output->writeln($exception->getMessage());
207
            }
208
209
            throw reset($this->exceptions);
210
        }
211
212 9
        return $output;
213
    }
214
215
    /**
216
     * @return bool
217
     */
218
    public function isShowOutput()
219
    {
220
        return $this->showOutput;
221
    }
222
223
    /**
224
     * @param bool $showOutput
225
     *
226
     * @return $this
227
     */
228 11
    public function setShowOutput($showOutput)
229
    {
230 11
        $this->showOutput = $showOutput;
231 11
        return $this;
232
    }
233
234
    /**
235
     * @return bool
236
     */
237
    public function isShowSummary()
238
    {
239
        return $this->showSummary;
240
    }
241
242
    /**
243
     * @param bool $showSummary
244
     *
245
     * @return $this
246
     */
247 13
    public function setShowSummary($showSummary)
248
    {
249 13
        $this->showSummary = $showSummary;
250 13
        return $this;
251
    }
252
}
253