Table::setShowOutput()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
nc 1
nop 1
crap 1
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\Display;
15
16
use Exception;
17
use Graze\DiffRenderer\DiffConsoleOutput;
18
use Graze\DiffRenderer\Terminal\TerminalInterface;
19
use Graze\ParallelProcess\Event\PoolRunEvent;
20
use Graze\ParallelProcess\Event\RunEvent;
21
use Graze\ParallelProcess\OutputterInterface;
22
use Graze\ParallelProcess\PoolInterface;
23
use Graze\ParallelProcess\PriorityPool;
24
use Graze\ParallelProcess\ProcessRun;
25
use Graze\ParallelProcess\RunInterface;
26
use Symfony\Component\Console\Output\OutputInterface;
27
28
class Table
29
{
30
    use TagsTrait;
31
32
    const SPINNER = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
33
34
    /** @var PoolInterface */
35
    private $pool;
36
    /** @var string[] */
37
    private $rows = [];
38
    /** @var Exception[] */
39
    private $exceptions;
40
    /** @var DiffConsoleOutput */
41
    private $output;
42
    /** @var TerminalInterface */
43
    private $terminal;
44
    /** @var bool */
45
    private $showOutput = true;
46
    /** @var bool */
47
    private $showSummary = true;
48
49
    /**
50
     * Table constructor.
51
     *
52
     * @param OutputInterface    $output
53
     * @param PoolInterface|null $pool
54
     */
55 16
    public function __construct(OutputInterface $output, PoolInterface $pool = null)
56
    {
57 16
        $this->pool = $pool ?: new PriorityPool();
58 16
        if (!$output instanceof DiffConsoleOutput) {
59 3
            $this->output = new DiffConsoleOutput($output);
60 3
            $this->output->setTrim(true);
61 3
        } else {
62 16
            $this->output = $output;
63
        }
64 16
        $this->terminal = $this->output->getTerminal();
65 16
        $this->exceptions = [];
66
67 16
        $this->pool->addListener(
68 16
            PoolRunEvent::POOL_RUN_ADDED,
69
            function (PoolRunEvent $event) {
70 13
                $this->add($event->getRun());
71 13
            }
72 16
        );
73
74 16
        array_map([$this, 'add'], $this->pool->getAll());
75 16
    }
76
77
    /**
78
     * @param RunInterface $run
79
     * @param string       $status
80
     *
81
     * @return string
82
     */
83 13
    private function formatRow(RunInterface $run, $status)
84
    {
85 13
        $tags = $this->formatTags($run->getTags());
86 13
        $extra = ($this->showOutput && $run instanceof OutputterInterface && mb_strlen($run->getLastMessage()) > 0)
87 13
            ? '  ' . $this->terminal->filter($run->getLastMessage())
88 13
            : '';
89 13
        return sprintf("%s (<comment>%6.2fs</comment>) %s%s", $tags, $run->getDuration(), $status, $extra);
90
    }
91
92
    /**
93
     * @param RunInterface $run
94
     */
95 13
    public function add(RunInterface $run)
96
    {
97 13
        $index = count($this->rows);
98 13
        $this->rows[$index] = $this->formatRow($run, '');
99 13
        $spinner = 0;
100 13
        $bar = new TinyProgressBar(2, TinyProgressBar::FORMAT_DEFAULT, 1);
101
102 13
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
103 10
            $run->addListener(
104 10
                RunEvent::UPDATED,
105
                function (RunEvent $event) use ($index, &$spinner, $bar) {
106 10
                    $run = $event->getRun();
107 10
                    $progress = $run->getProgress();
108 10
                    $status = (!is_null($progress))
109 10
                        ? $bar->setPosition($progress[2])
110 1
                              ->setPosition($progress[0])
111 1
                              ->setMax($progress[1])
112 1
                              ->render()
113 10
                        : mb_substr(static::SPINNER, $spinner++, 1);
114 10
                    $this->rows[$index] = $this->formatRow(
115 10
                        $run,
116
                        $status
117 10
                    );
118 10
                    if ($spinner > mb_strlen(static::SPINNER) - 1) {
119 1
                        $spinner = 0;
120 1
                    }
121 10
                    $this->render();
122 10
                }
123 10
            );
124 10
        }
125
126 13
        $run->addListener(
127 13
            RunEvent::SUCCESSFUL,
128
            function (RunEvent $event) use ($index, &$bar, &$spinner) {
0 ignored issues
show
Unused Code introduced by
The import $spinner is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
Unused Code introduced by
The import $bar is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
129 11
                $this->rows[$index] = $this->formatRow($event->getRun(), "<info>✓</info>");
130 11
                $this->render($index);
131 11
            }
132 13
        );
133 13
        $run->addListener(
134 13
            RunEvent::FAILED,
135 3
            function (RunEvent $event) use ($index, &$bar, &$spinner) {
0 ignored issues
show
Unused Code introduced by
The import $spinner is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
Unused Code introduced by
The import $bar is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
136 3
                $run = $event->getRun();
137 3
                $this->rows[$index] = $this->formatRow($run, "<error>x</error>");
138 3
                $this->render($index);
139 3
                $this->exceptions += $run->getExceptions();
140 3
            }
141 13
        );
142 13
        if ($run instanceof ProcessRun) {
143 13
            $run->setUpdateOnProcessOutput(false);
144 13
        }
145 13
        $this->updateRowKeyLengths($run->getTags());
146 13
    }
147
148
    /**
149
     * @return string
150
     */
151 2
    private function getSummary()
152
    {
153 2
        $running = count($this->pool->getRunning());
154 2
        $finished = count($this->pool->getFinished());
155 2
        if ($running > 0 || $finished > 0) {
156 2
            if ($running > 0) {
157 2
                return sprintf(
158 2
                    '<comment>Total</comment>: %2d, <comment>Running</comment>: %2d, <comment>Waiting</comment>: %2d',
159 2
                    $this->pool->count(),
160 2
                    $running,
161 2
                    count($this->pool->getWaiting())
162 2
                );
163
            } else {
164 2
                return '';
165
            }
166
        } else {
167 2
            return 'waiting...';
168
        }
169
    }
170
171
    /**
172
     * Render a specific row
173
     *
174
     * @param int $row
175
     */
176 13
    private function render($row = 0)
177
    {
178 13
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
179 10
            $rows = ($this->showSummary ? array_merge($this->rows, [$this->getSummary()]) : $this->rows);
180 10
            $this->output->reWrite($rows, !$this->showSummary);
181 10
        } else {
182 3
            $this->output->writeln($this->rows[$row]);
183
        }
184 13
    }
185
186
    /**
187
     * @param float $checkInterval
188
     *
189
     * @return bool true if all processes were successful
190
     * @throws Exception
191
     */
192 13
    public function run($checkInterval = PriorityPool::CHECK_INTERVAL)
193
    {
194 13
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
195 10
            $this->render();
196 10
        }
197 13
        $output = $this->pool->run($checkInterval);
198 13
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE && $this->showSummary) {
199 2
            $this->render();
200 2
        }
201
202 13
        if (count($this->exceptions) > 0) {
203 3
            foreach ($this->exceptions as $exception) {
204 3
                $this->output->writeln($exception->getMessage());
205 3
            }
206
207 3
            throw reset($this->exceptions);
208
        }
209
210 10
        return $output;
211
    }
212
213
    /**
214
     * @return bool
215
     */
216 1
    public function isShowOutput()
217
    {
218 1
        return $this->showOutput;
219
    }
220
221
    /**
222
     * @param bool $showOutput
223
     *
224
     * @return $this
225
     */
226 11
    public function setShowOutput($showOutput)
227
    {
228 11
        $this->showOutput = $showOutput;
229 11
        return $this;
230
    }
231
232
    /**
233
     * @return bool
234
     */
235 1
    public function isShowSummary()
236
    {
237 1
        return $this->showSummary;
238
    }
239
240
    /**
241
     * @param bool $showSummary
242
     *
243
     * @return $this
244
     */
245 14
    public function setShowSummary($showSummary)
246
    {
247 14
        $this->showSummary = $showSummary;
248 14
        return $this;
249
    }
250
}
251