Completed
Push — master ( ac786e...a9b395 )
by Sebastian
09:39
created

PrinterCli::formatWithColor()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 23
ccs 16
cts 16
cp 1
rs 8.7972
cc 4
eloc 14
nc 5
nop 2
crap 4
1
<?php
2
namespace phpbu\App\Result;
3
4
use InvalidArgumentException;
5
use phpbu\App\Event;
6
use phpbu\App\Listener;
7
use phpbu\App\Result;
8
use phpbu\App\Util;
9
use phpbu\App\Version;
10
use PHP_Timer;
11
use SebastianBergmann\Environment\Console;
12
13
/**
14
 * Default app output.
15
 *
16
 * Heavily 'inspired' by Sebastian Bergmann's phpunit PHPUnit_TextUI_ResultPrinter.
17
 *
18
 * @package    phpbu
19
 * @subpackage Result
20
 * @author     Sebastian Feldmann <[email protected]>
21
 * @copyright  Sebastian Feldmann <[email protected]>
22
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
23
 * @link       http://phpbu.de/
24
 * @since      Class available since Release 1.0.0
25
 */
26
class PrinterCli implements Listener
27
{
28
    /**
29
     * Verbose output
30
     *
31
     * @var boolean
32
     */
33
    protected $verbose;
34
35
    /**
36
     * Output with colors
37
     *
38
     * @var boolean
39
     */
40
    protected $colors;
41
42
    /**
43
     * Is debug active
44
     *
45
     * @var boolean
46
     */
47
    protected $debug;
48
49
    /**
50
     * Amount of executed backups
51
     *
52
     * @var integer
53
     */
54
    private $numBackups = 0;
55
56
    /**
57
     * Amount of executed checks
58
     *
59
     * @var integer
60
     */
61
    private $numChecks = 0;
62
63
    /**
64
     * Amount of executed crypts
65
     *
66
     * @var integer
67
     */
68
    private $numCrypts = 0;
69
70
    /**
71
     * Amount of executed Syncs
72
     *
73
     * @var integer
74
     */
75
    private $numSyncs = 0;
76
77
    /**
78
     * Amount of executed Cleanups
79
     *
80
     * @var integer
81
     */
82
    private $numCleanups = 0;
83
84
    /**
85
     * Returns an array of event names this subscriber wants to listen to.
86
     *
87
     * The array keys are event names and the value can be:
88
     *
89
     *  * The method name to call (priority defaults to 0)
90
     *  * An array composed of the method name to call and the priority
91
     *  * An array of arrays composed of the method names to call and respective
92
     *    priorities, or 0 if unset
93
     *
94
     * @return array The event names to listen to
95
     */
96
    public static function getSubscribedEvents()
97
    {
98
        return array(
99
            'phpbu.debug'           => 'onDebug',
100
            'phpbu.app_start'       => 'onPhpbuStart',
101
            'phpbu.backup_start'    => 'onBackupStart',
102
            'phpbu.backup_failed'   => 'onBackupFailed',
103
            'phpbu.backup_end'      => 'onBackupEnd',
104
            'phpbu.check_start'     => 'onCheckStart',
105
            'phpbu.check_failed'    => 'onCheckFailed',
106
            'phpbu.check_end'       => 'onCheckEnd',
107
            'phpbu.crypt_start'     => 'onCryptStart',
108
            'phpbu.crypt_skipped'   => 'onCryptSkipped',
109
            'phpbu.crypt_failed'    => 'onCryptFailed',
110
            'phpbu.crypt_end'       => 'onCryptEnd',
111
            'phpbu.sync_start'      => 'onSyncStart',
112
            'phpbu.sync_skipped'    => 'onSyncSkipped',
113 2
            'phpbu.sync_failed'     => 'onSyncFailed',
114
            'phpbu.sync_end'        => 'onSyncEnd',
115
            'phpbu.cleanup_start'   => 'onCleanupStart',
116 2
            'phpbu.cleanup_skipped' => 'onCleanupSkipped',
117 2
            'phpbu.cleanup_failed'  => 'onCleanupFailed',
118 2
            'phpbu.cleanup_end'     => 'onCleanupEnd',
119 2
            'phpbu.app_end'         => 'onPhpbuEnd',
120 2
        );
121 2
    }
122 2
123 2
    /**
124 2
     * Constructor
125 2
     *
126 2
     * @param  boolean $verbose
127 2
     * @param  boolean $colors
128 2
     * @param  boolean $debug
129 2
     * @throws \InvalidArgumentException
130 2
     */
131 2
    public function __construct($verbose = false, $colors = false, $debug = false)
132 2
    {
133 2
        if (!is_bool($verbose)) {
134 2
            throw new InvalidArgumentException('Expected $verbose to be of type boolean');
135 2
        }
136 2
        if (!is_bool($colors)) {
137 2
            throw new InvalidArgumentException('Expected $colors to be of type boolean');
138
        }
139
        if (!is_bool($debug)) {
140
            throw new InvalidArgumentException('Expected $debug to be of type boolean');
141
        }
142
143
        $this->debug   = $debug;
144
        $this->verbose = $verbose;
145
        $console       = new Console;
146
        $this->colors  = $colors && $console->hasColorSupport();
147
    }
148 30
149
    /**
150 30
     * phpbu start event.
151 29
     *
152 29
     * @param \phpbu\App\Event\App\Start $event
153 1
     */
154
    public function onPhpbuStart(Event\App\Start $event)
155
    {
156 29
        $configuration = $event->getConfiguration();
157 28
        $this->write(
158 28
            Version::getVersionString() . PHP_EOL .
159 28
            PHP_EOL .
160 1
            'Configuration read from ' . $configuration->getFilename() . PHP_EOL .
161
            PHP_EOL
162
        );
163 28
    }
164 27
165 27
    /**
166 1
     * Backup start event.
167
     *
168 27
     * @param \phpbu\App\Event\Backup\Start $event
169
     */
170 View Code Duplication
    public function onBackupStart(Event\Backup\Start $event)
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...
171
    {
172
        $backup = $event->getConfiguration();
173
        $this->numBackups++;
174
        if ($this->debug) {
175 1
            $this->write(Util\Cli::formatWithAsterisk('backup: [' . $backup->getSource()->type . '] '));
176
        }
177 1
    }
178 1
179 1
    /**
180 1
     * Backup failed event.
181 1
     *
182
     * @param \phpbu\App\Event\Backup\Failed $event
183 1
     */
184 1
    public function onBackupFailed(Event\Backup\Failed $event)
185
    {
186
        if ($this->debug) {
187
            $this->writeWithColor('fg-white, bg-red, bold', 'failed' . PHP_EOL);
188
        }
189
    }
190
191 3
    /**
192
     * Backup end event.
193 3
     *
194 3
     * @param \phpbu\App\Event\Backup\End $event
195 3
     */
196 2
    public function onBackupEnd(Event\Backup\End $event)
197 2
    {
198 3
        if ($this->debug) {
199
            $this->writeWithColor('fg-black, bg-green', 'ok' . PHP_EOL);
200
        }
201
    }
202
203
    /**
204
     * Check start event.
205 1
     *
206
     * @param \phpbu\App\Event\Check\Start $event
207 1
     */
208 1 View Code Duplication
    public function onCheckStart(Event\Check\Start $event)
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...
209 1
    {
210
        $check = $event->getConfiguration();
211 1
        $this->numChecks++;
212 1
        if ($this->debug) {
213 1
            $this->write(Util\Cli::formatWithAsterisk('check: [' . $check->type . '] '));
214
        }
215
    }
216
217
    /**
218
     * Check failed event.
219
     *
220 2
     * @param \phpbu\App\Event\Check\Failed $event
221
     */
222 2
    public function onCheckFailed(Event\Check\Failed $event)
223 1
    {
224 1
        if ($this->debug) {
225 2
            $this->writeWithColor('fg-white, bg-red, bold', 'failed' . PHP_EOL);
226
        }
227
    }
228
229
    /**
230
     * Check end event.
231
     *
232 3
     * @param \phpbu\App\Event\Check\End $event
233
     */
234 3
    public function onCheckEnd(Event\Check\End $event)
235 3
    {
236 3
        if ($this->debug) {
237 2
            $this->writeWithColor('fg-black, bg-green', 'ok' . PHP_EOL);
238 2
        }
239 3
    }
240
241
    /**
242
     * Crypt start event.
243
     *
244
     * @param \phpbu\App\Event\Crypt\Start $event
245
     */
246 1 View Code Duplication
    public function onCryptStart(Event\Crypt\Start $event)
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...
247
    {
248 1
        $crypt = $event->getConfiguration();
249 1
        $this->numCrypts++;
250 1
        if ($this->debug) {
251
            $this->write(Util\Cli::formatWithAsterisk('crypt: [' . $crypt->type . '] '));
252 1
        }
253 1
    }
254 1
255
    /**
256
     * Crypt skipped event.
257
     *
258
     * @param \phpbu\App\Event\Crypt\Skipped $event
259
     */
260
    public function onCryptSkipped(Event\Crypt\Skipped $event)
261 2
    {
262
        if ($this->debug) {
263 2
            $this->writeWithColor('fg-black, bg-yellow', 'skipped' . PHP_EOL);
264 1
        }
265 1
    }
266 2
267
    /**
268
     * Crypt failed event.
269
     *
270
     * @param \phpbu\App\Event\Crypt\Failed $event
271
     */
272
    public function onCryptFailed(Event\Crypt\Failed $event)
273 4
    {
274
        if ($this->debug) {
275 4
            $this->writeWithColor('fg-white, bg-red, bold', 'failed' . PHP_EOL);
276 4
        }
277 4
    }
278 3
279 3
    /**
280 4
     * Crypt end event.
281
     *
282
     * @param \phpbu\App\Event\Crypt\End $event
283
     */
284
    public function onCryptEnd(Event\Crypt\End $event)
285
    {
286
        if ($this->debug) {
287 1
            $this->writeWithColor('fg-black, bg-green', 'ok' . PHP_EOL);
288
        }
289 1
    }
290 1
291 1
    /**
292
     * Sync start event.
293 1
     *
294 1
     * @param \phpbu\App\Event\Sync\Start $event
295 1
     */
296 View Code Duplication
    public function onSyncStart(Event\Sync\Start $event)
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...
297
    {
298
        $sync = $event->getConfiguration();
299
        $this->numSyncs++;
300
        if ($this->debug) {
301
            $this->write(Util\Cli::formatWithAsterisk('sync: [' . $sync->type . '] '));
302 1
        }
303
    }
304 1
305 1
    /**
306 1
     * Sync skipped event.
307
     *
308 1
     * @param \phpbu\App\Event\Sync\Skipped $event
309 1
     */
310 1
    public function onSyncSkipped(Event\Sync\Skipped $event)
311
    {
312
        if ($this->debug) {
313
            $this->writeWithColor('fg-black, bg-yellow', 'skipped' . PHP_EOL);
314
        }
315
    }
316
317 2
    /**
318
     * Sync failed event.
319 2
     *
320 1
     * @param \phpbu\App\Event\Sync\Failed $event
321 1
     */
322 2
    public function onSyncFailed(Event\Sync\Failed $event)
323
    {
324
        if ($this->debug) {
325
            $this->writeWithColor('fg-white, bg-red, bold', 'failed' . PHP_EOL);
326
        }
327
    }
328
329 4
    /**
330
     * Sync end event.
331 4
     *
332 4
     * @param \phpbu\App\Event\Sync\End $event
333 4
     */
334 3
    public function onSyncEnd(Event\Sync\End $event)
335 3
    {
336 4
        if ($this->debug) {
337
            $this->writeWithColor('fg-black, bg-green', 'ok' . PHP_EOL);
338
        }
339
    }
340
341
    /**
342
     * Cleanup start event.
343 1
     *
344
     * @param \phpbu\App\Event\Cleanup\Start $event
345 1
     */
346 1 View Code Duplication
    public function onCleanupStart(Event\Cleanup\Start $event)
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...
347 1
    {
348
        $cleanup = $event->getConfiguration();
349 1
        $this->numCleanups++;
350 1
        if ($this->debug) {
351 1
            $this->write(Util\Cli::formatWithAsterisk('cleanup: [' . $cleanup->type . '] '));
352
        }
353
    }
354
355
    /**
356
     * Cleanup skipped event.
357
     *
358 1
     * @param \phpbu\App\Event\Cleanup\Skipped $event
359
     */
360 1
    public function onCleanupSkipped(Event\Cleanup\Skipped $event)
361 1
    {
362 1
        if ($this->debug) {
363
            $this->writeWithColor('fg-black, bg-yellow', 'skipped' . PHP_EOL);
364 1
        }
365 1
    }
366 1
367
    /**
368
     * Cleanup failed event.
369
     *
370
     * @param \phpbu\App\Event\Cleanup\Failed $event
371
     */
372
    public function onCleanupFailed(Event\Cleanup\Failed $event)
373 2
    {
374
        if ($this->debug) {
375 2
            $this->writeWithColor('fg-white, bg-red, bold', 'failed' . PHP_EOL);
376 1
        }
377 1
    }
378 2
379
    /**
380
     * Cleanup end event.
381
     *
382
     * @param \phpbu\App\Event\Cleanup\End $event
383
     */
384
    public function onCleanupEnd(Event\Cleanup\End $event)
385 4
    {
386
        if ($this->debug) {
387 4
            $this->writeWithColor('fg-black, bg-green', 'ok' . PHP_EOL);
388 4
        }
389 4
    }
390 3
391 3
    /**
392 4
     * Debugging.
393
     *
394
     * @param \phpbu\App\Event\Debug $event
395
     */
396
    public function onDebug(Event\Debug $event)
397
    {
398
        if ($this->debug) {
399 1
            $this->write(wordwrap($event->getMessage(), 70, PHP_EOL, true) . PHP_EOL);
400
        }
401 1
    }
402 1
403 1
    /**
404
     * phpbu end event.
405 1
     *
406 1
     * @param \phpbu\App\Event\App\End $event
407 1
     */
408
    public function onPhpbuEnd(Event\App\End $event)
409
    {
410
        $result = $event->getResult();
411
        $this->printResult($result);
412
    }
413
414 1
    /**
415
     * Prints a result summary.
416 1
     *
417 1
     * @param \phpbu\App\Result $result
418 1
     */
419
    public function printResult(Result $result)
420 1
    {
421 1
        $this->printHeader();
422 1
        $this->printErrors($result);
423
424
        if ($this->verbose) {
425
            foreach ($result->getBackups() as $backup) {
426
                $this->printBackupVerbose($backup);
427
            }
428
        }
429 2
        $this->printFooter($result);
430
    }
431 2
432 1
    /**
433 1
     * Prints the result header with memory usage info.
434 2
     */
435
    protected function printHeader()
436
    {
437
        $this->write(PHP_Timer::resourceUsage() . PHP_EOL . PHP_EOL);
438
    }
439
440
    /**
441 1
     * Print error information.
442
     *
443 1
     * @param \phpbu\App\Result $result
444 1
     */
445 1
    protected function printErrors(Result $result)
446 1
    {
447
        /* @var $e \Exception */
448
        foreach ($result->getErrors() as $e) {
449
            $this->write(
450
                sprintf(
451
                    "Exception '%s' with message '%s'\nin %s:%d\n\n",
452
                    get_class($e),
453 1
                    $e->getMessage(),
454
                    $e->getFile(),
455 1
                    $e->getLine()
456 1
                )
457 1
            );
458
        }
459
    }
460
461
    /**
462
     * Prints verbose backup information.
463
     *
464 5
     * @param \phpbu\App\Result\Backup $backup
465
     */
466 5
    protected function printBackupVerbose(Result\Backup $backup)
467 5
    {
468
        $this->write(sprintf('backup %s: ', $backup->getName()));
469 5
        if ($backup->allOk()) {
470 3
            $this->writeWithColor(
471 3
                'fg-black, bg-green',
472 3
                'OK'
473 3
            );
474 5
        } elseif ($backup->okButSkipsOrFails()) {
475 5
                $this->writeWithColor(
476
                    'fg-black, bg-yellow',
477
                    'OK, but skipped or failed Crypts, Syncs or Cleanups!'
478
                );
479
        } else {
480 5
            $this->writeWithColor(
481
                'fg-white, bg-red, bold',
482 5
                'FAILED'
483 5
            );
484
        }
485
        $chExecuted = str_pad($backup->checkCount(), 8, ' ', STR_PAD_LEFT);
486
        $chFailed   = str_pad($backup->checkCountFailed(), 6, ' ', STR_PAD_LEFT);
487
        $crExecuted = str_pad($backup->cryptCount(), 8, ' ', STR_PAD_LEFT);
488
        $crSkipped  = str_pad($backup->cryptCountSkipped(), 7, ' ', STR_PAD_LEFT);
489
        $crFailed   = str_pad($backup->cryptCountFailed(), 6, ' ', STR_PAD_LEFT);
490 5
        $syExecuted = str_pad($backup->syncCount(), 8, ' ', STR_PAD_LEFT);
491
        $sySkipped  = str_pad($backup->syncCountSkipped(), 7, ' ', STR_PAD_LEFT);
492
        $syFailed   = str_pad($backup->syncCountFailed(), 6, ' ', STR_PAD_LEFT);
493 5
        $clExecuted = str_pad($backup->cleanupCount(), 8, ' ', STR_PAD_LEFT);
494 1
        $clSkipped  = str_pad($backup->cleanupCountSkipped(), 7, ' ', STR_PAD_LEFT);
495 1
        $clFailed   = str_pad($backup->cleanupCountFailed(), 6, ' ', STR_PAD_LEFT);
496 1
497 1
        $out = PHP_EOL . '          | executed | skipped | failed |' . PHP_EOL
498 1
            . '----------+----------+---------+--------+' . PHP_EOL
499 1
            . ' checks   | ' . $chExecuted . ' |         | ' . $chFailed . ' |' . PHP_EOL
500 1
            . ' crypts   | ' . $crExecuted . ' | ' . $crSkipped . ' | ' . $crFailed . ' |' . PHP_EOL
501 1
            . ' syncs    | ' . $syExecuted . ' | ' . $sySkipped . ' | ' . $syFailed . ' |' . PHP_EOL
502 1
            . ' cleanups | ' . $clExecuted . ' | ' . $clSkipped . ' | ' . $clFailed . ' |' . PHP_EOL
503 5
            . '----------+----------+---------+--------+' . PHP_EOL . PHP_EOL;
504 5
505
        $this->write($out);
506
    }
507
508
    /**
509
     * Prints 'OK' or 'FAILURE' footer.
510
     *
511 3
     * @param Result $result
512
     */
513 3
    protected function printFooter(Result $result)
514 3
    {
515 1
        if (count($result->getBackups()) === 0) {
516 1
            $this->writeWithColor(
517
                'fg-black, bg-yellow',
518 1
                'No backups executed!'
519 3
            );
520 1
        } elseif ($result->allOk()) {
521 1
            $this->writeWithColor(
522
                'fg-black, bg-green',
523 1
                sprintf(
524 1
                    'OK (%d %s, %d %s, %d %s, %d %s, %d %s)' . PHP_EOL,
525 1
                    count($result->getBackups()),
526 1
                    Util\Str::appendPluralS('backup', count($result->getBackups())),
527
                    $this->numChecks,
528 1
                    Util\Str::appendPluralS('check', $this->numChecks),
529
                    $this->numCrypts,
530 3
                    Util\Str::appendPluralS('crypt', $this->numCrypts),
531 3
                    $this->numSyncs,
532 3
                    Util\Str::appendPluralS('sync', $this->numSyncs),
533 3
                    $this->numCleanups,
534 3
                    Util\Str::appendPluralS('cleanup', $this->numCleanups)
535 3
                )
536 3
            );
537 3
        } elseif ($result->backupOkButSkipsOrFails()) {
538 3
            $this->writeWithColor(
539 3
                'fg-black, bg-yellow',
540 3
                sprintf(
541
                    "OK, but skipped|failed Crypts, Syncs or Cleanups!\n" .
542 3
                    'Backups: %d, Crypts: %d|%d, Syncs: %d|%d, Cleanups: %d|%d.' . PHP_EOL,
543 3
                    count($result->getBackups()),
544 3
                    $result->cryptsSkippedCount(),
545 3
                    $result->cryptsFailedCount(),
546 3
                    $result->syncsSkippedCount(),
547 3
                    $result->syncsFailedCount(),
548 3
                    $result->cleanupsSkippedCount(),
549
                    $result->cleanupsFailedCount()
550 3
                )
551 3
            );
552
        } else {
553
            $this->writeWithColor(
554
                'fg-white, bg-red',
555
                sprintf(
556
                    "FAILURE!\n" .
557
                    'Backups: %d, failed Checks: %d, failed Crypts: %d, failed Syncs: %d, failed Cleanups: %d.' . PHP_EOL,
558 5
                    count($result->getBackups()),
559
                    $result->checksFailedCount(),
560 5
                    $result->cryptsFailedCount(),
561 2
                    $result->syncsFailedCount(),
562 2
                    $result->cleanupsFailedCount()
563
                )
564 2
            );
565 5
        }
566 1
    }
567 1
568 1
    /**
569 1
     * Writes a buffer out with a color sequence if colors are enabled.
570 1
     *
571 1
     * @author Sebastian Bergmann <[email protected]>
572 1
     * @param  string $color
573 1
     * @param  string $buffer
574 1
     */
575 1
    protected function writeWithColor($color, $buffer)
576 1
    {
577 1
        if ($this->colors) {
578 1
            $buffer = Util\Cli::formatWithColor($color, $buffer);
579 1
        }
580 1
        $this->write($buffer . PHP_EOL);
581 1
    }
582 3
583 1
    /**
584 1
     * Writes a buffer.
585 1
     *
586
     * @param string $buffer
587 1
     */
588 1
    public function write($buffer)
589 1
    {
590 1
        if (PHP_SAPI != 'cli') {
591 1
            $buffer = htmlspecialchars($buffer);
592 1
        }
593 1
        echo $buffer;
594 1
    }
595
}
596