Completed
Push — master ( 05a136...33b2da )
by Harry
01:36
created

Table::setShowOutput()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
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
42
    /**
43
     * Table constructor.
44
     *
45
     * @param OutputInterface $output
46
     * @param Pool|null       $pool
47
     */
48
    public function __construct(OutputInterface $output, Pool $pool = null)
49
    {
50
        $this->processPool = $pool ?: new Pool();
51
        if (!$output instanceof DiffConsoleOutput) {
52
            $this->output = new DiffConsoleOutput($output);
53
            $this->output->setTrim(true);
54
        } else {
55
            $this->output = $output;
56
        }
57
        $this->terminal = $this->output->getTerminal();
58
        $this->exceptions = [];
59
    }
60
61
    /**
62
     * Parses the rows to determine the key lengths to make a pretty table
63
     *
64
     * @param array $data
65
     */
66
    private function updateRowKeyLengths(array $data = [])
67
    {
68
        $lengths = array_map('mb_strlen', $data);
69
70
        $keys = array_merge(array_keys($lengths), array_keys($this->maxLengths));
71
72
        foreach ($keys as $key) {
73
            if (!isset($this->maxLengths[$key])
74
                || (isset($lengths[$key]) && $lengths[$key] > $this->maxLengths[$key])
75
            ) {
76
                $this->maxLengths[$key] = $lengths[$key];
77
            }
78
        }
79
    }
80
81
    /**
82
     * @param array  $data
83
     * @param string $status
84
     * @param float  $duration
85
     * @param string $extra
86
     *
87
     * @return string
88
     */
89
    private function formatRow(array $data, $status, $duration, $extra = '')
90
    {
91
        $info = [];
92
        foreach ($data as $key => $value) {
93
            $length = isset($this->maxLengths[$key]) ? '-' . $this->maxLengths[$key] : '';
94
            $info[] = sprintf("<info>%s</info>: %{$length}s", $key, $value);
95
        }
96
        $extra = $extra ? '  ' . $this->terminal->filter($extra) : '';
97
        return sprintf("%s (<comment>%6.2fs</comment>) %s%s", implode(' ', $info), $duration, $status, $extra);
98
    }
99
100
    /**
101
     * @param Process $process
102
     * @param array   $data
103
     */
104
    public function add(Process $process, array $data = [])
105
    {
106
        $index = count($this->rows);
107
        $this->rows[$index] = $this->formatRow($data, '', 0);
108
        $spinner = 0;
109
110
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
111
            $onProgress = function ($process, $duration, $last) use ($index, $data, &$spinner) {
112
                $this->rows[$index] = $this->formatRow(
113
                    $data,
114
                    mb_substr(static::SPINNER, $spinner++, 1),
115
                    $duration,
116
                    ($this->showOutput ? $last : '')
117
                );
118
                if ($spinner > mb_strlen(static::SPINNER) - 1) {
119
                    $spinner = 0;
120
                }
121
                $this->render();
122
            };
123
        } else {
124
            $onProgress = null;
125
        }
126
127
        $this->processPool->add(new Run(
128
            $process,
129
            function ($process, $duration, $last) use ($index, $data) {
130
                $this->rows[$index] = $this->formatRow($data, "<info>✓</info>", $duration, $last);
131
                $this->render($index);
132
            },
133
            function ($process, $duration, $last) use ($index, $data) {
134
                $this->rows[$index] = $this->formatRow($data, "<error>x</error>", $duration, $last);
135
                $this->render($index);
136
                $this->exceptions[] = new ProcessFailedException($process);
137
            },
138
            $onProgress
139
        ));
140
141
        $this->updateRowKeyLengths($data);
142
    }
143
144
    /**
145
     * Render a specific row
146
     *
147
     * @param int $row
148
     */
149
    private function render($row = 0)
150
    {
151
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
152
            $this->output->reWrite($this->rows, true);
153
        } else {
154
            $this->output->writeln($this->rows[$row]);
155
        }
156
    }
157
158
    /**
159
     * @param float $checkInterval
160
     *
161
     * @return bool true if all processes were successful
162
     * @throws Exception
163
     */
164
    public function run($checkInterval = Pool::CHECK_INTERVAL)
165
    {
166
        if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
167
            $this->render();
168
        }
169
        $output = $this->processPool->run($checkInterval);
170
171
        if (count($this->exceptions) > 0) {
172
            foreach ($this->exceptions as $exception) {
173
                $this->output->writeln($exception->getMessage());
174
            }
175
176
            throw reset($this->exceptions);
177
        }
178
179
        return $output;
180
    }
181
182
    /**
183
     * @return bool
184
     */
185
    public function isShowOutput()
186
    {
187
        return $this->showOutput;
188
    }
189
190
    /**
191
     * @param bool $showOutput
192
     *
193
     * @return $this
194
     */
195
    public function setShowOutput($showOutput)
196
    {
197
        $this->showOutput = $showOutput;
198
199
        return $this;
200
    }
201
}
202