Passed
Push — master ( 086f4e...2ba8a2 )
by coExp
40s queued 10s
created

ProgressBar::formatTime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace coExp\WunderBar;
4
5
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
6
use Symfony\Component\Console\Output\ConsoleOutputInterface;
7
use Symfony\Component\Console\Output\OutputInterface;
8
9
class ProgressBar
10
{
11
    /** @var  OutputInterface */
12
    protected $output;
13
14
    # Length of the progression bar
15
    const PROGRESSION_LENGTH = 50;
16
    # Clear the line from the cursor
17
    const CLEAR_LINE = "\e[2K";
18
19
    /**
20
     * @var  int
21
     */
22
    protected $nbrSuccess, $nbrPassed, $nbrWarning, $nbrError = 0;
23
24
    /**
25
     * Nbr of things to do
26
     * @var  int
27
     */
28
    protected $length;
29
30
    /**
31
     * Time of begin of command
32
     * @var int|null
33
     */
34
    protected $time = null;
35
36
    /**
37
     * Last time progress bas has been shown
38
     * @var int|null
39
     */
40
    protected $lastShown = null;
41
42
    /**
43
     * ProgressBar constructor.
44
     * @param OutputInterface $output
45
     */
46
    public function __construct(OutputInterface $output)
47
    {
48
        $output->getFormatter()->setStyle('ok',  new OutputFormatterStyle('black', 'green', ['bold']));
49
        $output->getFormatter()->setStyle('err', new OutputFormatterStyle('red', 'black', ['bold']));
50
51
        if ($output instanceof ConsoleOutputInterface) {
52
            $output = $output->setErrorOutput($output);
53
        }
54
55
        $this->output = $output;
56
        $this->time = time();
57
    }
58
59
    /**
60
     * @param $length
61
     * @return $this
62
     */
63
    public function setLength($length): self
64
    {
65
        $this->length = $length;
66
67
        return $this;
68
    }
69
70
    /**
71
     * @param int $i
72
     * @return $this
73
     */
74
    public function addNbrPassed(int $i = 1): self
75
    {
76
        $this->nbrPassed += $i;
77
78
        return $this;
79
    }
80
81
    /**
82
     * @param int $i
83
     * @return $this
84
     */
85
    public function addNbrDone(int $i = 1): self
86
    {
87
        $this->nbrSuccess += $i;
88
89
        return $this;
90
    }
91
92
    /**
93
     * @param int $i
94
     * @return $this
95
     */
96
    public function addNbrWarning(int $i = 1): self
97
    {
98
        $this->nbrWarning += $i;
99
100
        return $this;
101
    }
102
103
    /**
104
     * @param int $i
105
     * @return $this
106
     */
107
    public function addNbrError(int $i = 1): self
108
    {
109
        $this->nbrError += $i;
110
111
        return $this;
112
    }
113
114
    /**
115
     * @param string $message
116
     * @return $this
117
     */
118
    public function write(string $message): self
119
    {
120
        $this->writeBlankLine();
121
        $this->output->write($message);
122
        $this->writeProgression(true);
123
124
        return $this;
125
    }
126
127
    /**
128
     * Write a line on output
129
     * @param string $message
130
     * @return $this
131
     */
132
    public function writeLine(string $message): self
133
    {
134
        $this->writeBlankLine();
135
        $this->output->writeln($message);
136
        $this->writeProgression(true);
137
138
        return $this;
139
    }
140
141
    /**
142
     * Erase the current output line
143
     */
144
    public function writeBlankLine(): self
145
    {
146
        self::blankLine($this->output);
147
148
        return $this;
149
    }
150
151
    /**
152
     * @param OutputInterface $output
153
     */
154
    public static function blankLine(OutputInterface $output)
155
    {
156
        try {
157
            $output->write("\r\e[2K");
158
        } catch (\Exception $e) {
159
            # Do not break your stuff
160
        }
161
    }
162
163
    /**
164
     * Show a cool and nice progression bar!
165
     * @param bool $force
166
     * @return $this
167
     */
168
    public function writeProgression(bool $force = false): self
169
    {
170
        # Show Progress bar each second
171
        if (!$force && $this->lastShown == time()) {
172
            return $this;
173
        }
174
175
        if ($this->length == 0) {
176
            return $this;
177
        }
178
179
        try {
180
            $nbrRemaining = $this->length - $this->getNbrDone();
181
182
            $timeElapsed = time() - $this->time;
183
            $timeETA = $nbrRemaining * ($timeElapsed / $this->getNbrSuccess(true));
184
185
            $percentPassed  = ($this->nbrPassed / $this->length);
186
            $percentWarning = ($this->nbrWarning / $this->length);
187
            $percentDone    = ($this->nbrSuccess / $this->length);
188
            $percentError   = ($this->nbrError / $this->length);
189
190
            $percent = $this->getNbrDone() / $this->length;
191
192
            $lengthPassed   = (int) ($percentPassed  * self::PROGRESSION_LENGTH);
193
            $lengthWarning  = (int) ($percentWarning * self::PROGRESSION_LENGTH);
194
            $lengthDone     = (int) ($percentDone    * self::PROGRESSION_LENGTH);
195
            $lengthError    = (int) ($percentError   * self::PROGRESSION_LENGTH);
196
197
            $lengthLeft = self::PROGRESSION_LENGTH - $lengthPassed - $lengthDone - $lengthError - $lengthWarning;
198
            $lengthLeft = ($lengthLeft < 0 ) ? 0 : $lengthLeft;
199
200
            $msg  = "\r" . sprintf('%3d', round($percent*100, 0)) . "%: [";
201
202
            $msg .= '<info>'    . str_repeat('#', $lengthDone)   . '</info>';
203
            $msg .= '<comment>' . str_repeat('#', $lengthPassed) . '</comment>';
204
            $msg .= '<err>'   . str_repeat('#', $lengthError)  . '</err>';
205
206
            $msg .= str_repeat('-', $lengthLeft) . '] ';
207
            $msg .= ($this->nbrSuccess)    ? " Done:<info>$this->nbrSuccess</info>" : '';
208
            $msg .= ($this->nbrWarning) ? " Warn:<comment>$this->nbrWarning</comment>" : '';
209
            $msg .= ($this->nbrPassed)  ? " Pass:$this->nbrPassed" : '';
210
            $msg .= ($this->nbrError)   ? " Err:<err>$this->nbrError</err>" : '';
211
            $msg .= ' Remaining:' . ($nbrRemaining);
212
213
            $msg .= ' Elapsed:<info>' . $this->formatTime($timeElapsed) . '</info>';
214
            $msg .= ' ETA:<comment>' . $this->formatTime($timeETA) . '</comment>';
215
216
            $msg .= " \r";
217
218
            $this->output->write($msg);
219
220
            # Show Progress bar each second
221
            $this->lastShown = time();
222
        } catch (\Exception $e) {
223
            # Do not break your stuff
224
        }
225
226
        return $this;
227
    }
228
229
    /**
230
     * @param int $time
231
     * @return string
232
     */
233
    private function formatTime(int $time): string
234
    {
235
        $sec  = $time % 60;
236
        $min  = ((int) ($time / 60)) % 60;
237
        $hour = (int) ($time / 3600);
238
239
        return sprintf('%02d:%02d:%02d', $hour, $min, $sec);
240
    }
241
242
    /**
243
     * @return int
244
     */
245
    public function getNbrDone()
246
    {
247
        return ($this->nbrPassed + $this->nbrWarning + $this->nbrSuccess + $this->nbrError);
248
    }
249
250
    /**
251
     * @param bool $doNotReturn0: Do not return 0 to avoid divedByZero
252
     * @return int
253
     */
254
    public function getNbrSuccess($doNotReturn0 = false): int
255
    {
256
        if ($doNotReturn0 && empty($this->nbrSuccess)) {
257
            return 1;
258
        }
259
260
        return $this->nbrSuccess;
261
    }
262
263
    /**
264
     * @return int
265
     */
266
    public function getNbrWarning(): int
267
    {
268
        return $this->nbrWarning;
269
    }
270
271
    /**
272
     * @return int
273
     */
274
    public function getNbrError(): int
275
    {
276
        return $this->nbrError;
277
    }
278
279
    /**
280
     * @return int
281
     */
282
    public function getNbrPassed(): int
283
    {
284
        return $this->nbrPassed;
285
    }
286
287
}
288