Completed
Pull Request — master (#12)
by Harry
01:54
created

Table::formatRow()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 11
cts 11
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 10
nop 4
crap 5
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 15
        $this->processPool = $pool ?: new Pool();
53 15
        if (!$output instanceof DiffConsoleOutput) {
54 3
            $this->output = new DiffConsoleOutput($output);
55 3
            $this->output->setTrim(true);
56 3
        } else {
57 15
            $this->output = $output;
58
        }
59 15
        $this->terminal = $this->output->getTerminal();
60 15
        $this->exceptions = [];
61 15
    }
62
63
    /**
64
     * Parses the rows to determine the key lengths to make a pretty table
65
     *
66
     * @param array $data
67
     */
68 12 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 12
        $lengths = array_map('mb_strlen', $data);
71
72 12
        $keys = array_merge(array_keys($lengths), array_keys($this->maxLengths));
73
74 12
        foreach ($keys as $key) {
75 12
            if (!isset($this->maxLengths[$key])
76 12
                || (isset($lengths[$key]) && $lengths[$key] > $this->maxLengths[$key])
77 12
            ) {
78 12
                $this->maxLengths[$key] = $lengths[$key];
79 12
            }
80 12
        }
81 12
    }
82
83
    /**
84
     * @param array  $data
85
     * @param string $status
86
     * @param float  $duration
87
     * @param string $extra
88
     *
89
     * @return string
90
     */
91 12
    private function formatRow(array $data, $status, $duration, $extra = '')
92
    {
93 12
        $info = [];
94 12
        foreach ($data as $key => $value) {
95 12
            $length = isset($this->maxLengths[$key]) ? '-' . $this->maxLengths[$key] : '';
96 12
            if (is_int($key)) {
97 1
                $info[] = sprintf("%{$length}s", $value);
98 1
            } else {
99 11
                $info[] = sprintf("<info>%s</info>: %{$length}s", $key, $value);
100
            }
101 12
        }
102 12
        $extra = $extra ? '  ' . $this->terminal->filter($extra) : '';
103 12
        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 12
    public function add(Process $process, array $data = [])
111
    {
112 12
        $index = count($this->rows);
113 12
        $this->rows[$index] = $this->formatRow($data, '', 0);
114 12
        $spinner = 0;
115
116 12
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
117
            $onProgress = function ($process, $duration, $last) use ($index, $data, &$spinner) {
118 9
                $this->rows[$index] = $this->formatRow(
119 9
                    $data,
120 9
                    mb_substr(static::SPINNER, $spinner++, 1),
121 9
                    $duration,
122 9
                    ($this->showOutput ? $last : '')
123 9
                );
124 9
                if ($spinner > mb_strlen(static::SPINNER) - 1) {
125 1
                    $spinner = 0;
126 1
                }
127 9
                $this->render();
128 9
            };
129 9
        } else {
130 3
            $onProgress = null;
131
        }
132
133 12
        $run = new Run(
134 12
            $process,
135
            function ($process, $duration, $last) use ($index, $data) {
136 10
                $this->rows[$index] = $this->formatRow($data, "<info>✓</info>", $duration, $last);
137 10
                $this->render($index);
138 12
            },
139 12
            function ($process, $duration, $last) use ($index, $data) {
140 3
                $this->rows[$index] = $this->formatRow($data, "<error>x</error>", $duration, $last);
141 3
                $this->render($index);
142 3
                $this->exceptions[] = new ProcessFailedException($process);
143 12
            },
144
            $onProgress
145 12
        );
146 12
        $run->setUpdateOnProcessOutput(false);
147 12
        $this->processPool->add($run);
148
149 12
        $this->updateRowKeyLengths($data);
150 12
    }
151
152
    /**
153
     * @return string
154
     */
155 2
    private function getSummary()
156
    {
157 2
        if ($this->processPool->hasStarted()) {
158 2
            if ($this->processPool->isRunning()) {
159 2
                return sprintf(
160 2
                    '<comment>Total</comment>: %2d, <comment>Running</comment>: %2d, <comment>Waiting</comment>: %2d',
161 2
                    $this->processPool->count(),
162 2
                    count($this->processPool->getRunning()),
163 2
                    count($this->processPool->getWaiting())
164 2
                );
165
            } else {
166 2
                return '';
167
            }
168
        } else {
169 1
            return 'waiting...';
170
        }
171
    }
172
173
    /**
174
     * Render a specific row
175
     *
176
     * @param int $row
177
     */
178 12
    private function render($row = 0)
179
    {
180 12
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
181 9
            $rows = ($this->showSummary ? array_merge($this->rows, [$this->getSummary()]) : $this->rows);
182 9
            $this->output->reWrite($rows, !$this->showSummary);
183 9
        } else {
184 3
            $this->output->writeln($this->rows[$row]);
185
        }
186 12
    }
187
188
    /**
189
     * @param float $checkInterval
190
     *
191
     * @return bool true if all processes were successful
192
     * @throws Exception
193
     */
194 12
    public function run($checkInterval = Pool::CHECK_INTERVAL)
195
    {
196 12
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
197 9
            $this->render();
198 9
        }
199 12
        $output = $this->processPool->run($checkInterval);
200 12
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE && $this->showSummary) {
201 2
            $this->render();
202 2
        }
203
204 12
        if (count($this->exceptions) > 0) {
205 3
            foreach ($this->exceptions as $exception) {
206 3
                $this->output->writeln($exception->getMessage());
207 3
            }
208
209 3
            throw reset($this->exceptions);
210
        }
211
212 9
        return $output;
213
    }
214
215
    /**
216
     * @return bool
217
     */
218 1
    public function isShowOutput()
219
    {
220 1
        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 1
    public function isShowSummary()
238
    {
239 1
        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