• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Cli / 8628398942

29 Mar 2024 11:53AM UTC coverage: 81.315%. Remained the same
8628398942

push

github

web-flow
Fixed profiler formatting (#28)

Some minor adjustments were made to improve readability and accuracy of
output. Padding was added to further standardize the spacing of output
values, some conditionals were adjusted, and 'Exit Code' output was
changed from 'Info' to 'Debug' level. Extraneous test assertions were
removed accordingly.

10 of 12 new or added lines in 1 file covered. (83.33%)

3 existing lines in 1 file now uncovered.

1014 of 1247 relevant lines covered (81.32%)

241.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.19
/src/OutputMods/Text.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Cli.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Cli
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\Cli\OutputMods;
18

19
use JBZoo\Cli\CliApplication;
20
use JBZoo\Cli\Exception;
21
use JBZoo\Cli\OutLvl;
22
use JBZoo\Cli\ProgressBars\AbstractProgressBar;
23
use JBZoo\Cli\ProgressBars\ProgressBarSymfony;
24
use JBZoo\Utils\FS;
25
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
26
use Symfony\Component\Console\Input\InputInterface;
27
use Symfony\Component\Console\Output\ConsoleOutput;
28
use Symfony\Component\Console\Output\OutputInterface;
29

30
use function JBZoo\Utils\bool;
31

32
class Text extends AbstractOutputMode
33
{
34
    public function __construct(InputInterface $input, OutputInterface $output, CliApplication $application)
35
    {
36
        parent::__construct($input, $output, $application);
624✔
37

38
        self::addOutputStyles($this->getOutput());
624✔
39
        self::addOutputStyles($this->getErrOutput());
624✔
40

41
        if ($this->output instanceof ConsoleOutput && $this->isStdoutOnly()) {
624✔
42
            $this->output->setErrorOutput($this->output);
48✔
43
        }
44
    }
45

46
    public function onExecBefore(): void
47
    {
48
        $this->_('Working Directory is <i>' . \getcwd() . '</i>', OutLvl::DEBUG);
624✔
49
    }
50

51
    public function onExecAfter(int $exitCode, ?string $outputLevel = null): void
52
    {
53
        $isParrallelExec = self::isParallelExec();
624✔
54

55
        $outputLevel ??= $isParrallelExec ? OutLvl::DEBUG : OutLvl::INFO;
624✔
56
        if ($this->isDisplayProfiling()) {
624✔
57
            $outputLevel = OutLvl::DEFAULT;
42✔
58
        }
59

60
        $profile = $this->getProfileInfo();
624✔
61

62
        $totalTime = \number_format(\microtime(true) - $this->getStartTime(), 3);
624✔
63
        $curMemory = FS::format($profile['memory_usage']);
624✔
64
        $maxMemory = FS::format($profile['memory_peak_real']);
624✔
65
        $bootTime  = (int)$profile['time_bootstrap_ms'];
624✔
66

67
        $showBootTime = $this->isDisplayProfiling() && $this->isDebugLevel();
624✔
68

69
        $this->_(
624✔
70
            "Memory: <green>{$curMemory}</green>; Real peak: <green>{$maxMemory}</green>; " .
624✔
71
            "Time: <green>{$totalTime} sec</green>" .
624✔
72
            ($showBootTime ? " <gray>+{$bootTime} ms (bootstrap)</gray>" : ''),
624✔
73
            $outputLevel,
624✔
74
        );
624✔
75

76
        $this->_("Exit Code is \"{$exitCode}\"", OutLvl::DEBUG);
624✔
77
    }
78

79
    public function onExecException(\Exception $exception): void
80
    {
81
        if (bool($this->getInput()->getOption('mute-errors'))) {
102✔
82
            $this->_($exception->getMessage(), OutLvl::EXCEPTION);
12✔
83
        }
84
    }
85

86
    public function createProgressBar(): AbstractProgressBar
87
    {
88
        return new ProgressBarSymfony($this);
138✔
89
    }
90

91
    public static function getName(): string
92
    {
93
        return 'text';
858✔
94
    }
95

96
    public static function getDescription(): string
97
    {
98
        return 'Default text output format, userfriendly and easy to read.';
858✔
99
    }
100

101
    public static function addOutputStyles(OutputInterface $output): void
102
    {
103
        $formatter    = $output->getFormatter();
624✔
104
        $defaultColor = 'default';
624✔
105

106
        $colors = [
624✔
107
            'black',
624✔
108
            'red',
624✔
109
            'green',
624✔
110
            'yellow',
624✔
111
            'blue',
624✔
112
            'magenta',
624✔
113
            'cyan',
624✔
114
            'white',
624✔
115
            'gray',
624✔
116
            'bright-red',
624✔
117
            'bright-green',
624✔
118
            'bright-yellow',
624✔
119
            'bright-blue',
624✔
120
            'bright-magenta',
624✔
121
            'bright-cyan',
624✔
122
            'bright-white',
624✔
123
            $defaultColor,
624✔
124
        ];
624✔
125

126
        foreach ($colors as $color) {
624✔
127
            $formatter->setStyle($color, new OutputFormatterStyle($color));
624✔
128
            $formatter->setStyle("{$color}-b", new OutputFormatterStyle($color, null, ['bold']));
624✔
129
            $formatter->setStyle("{$color}-u", new OutputFormatterStyle($color, null, ['underscore']));
624✔
130
            $formatter->setStyle("{$color}-r", new OutputFormatterStyle($color, null, ['reverse']));
624✔
131
            $formatter->setStyle("{$color}-bg", new OutputFormatterStyle(null, $color));
624✔
132
            $formatter->setStyle("{$color}-bl", new OutputFormatterStyle($color, null, ['blink']));
624✔
133
        }
134

135
        $formatter->setStyle('bl', new OutputFormatterStyle($defaultColor, null, ['blink']));
624✔
136
        $formatter->setStyle('b', new OutputFormatterStyle($defaultColor, null, ['bold']));
624✔
137
        $formatter->setStyle('u', new OutputFormatterStyle($defaultColor, null, ['underscore']));
624✔
138
        $formatter->setStyle('r', new OutputFormatterStyle(null, null, ['reverse']));
624✔
139
        $formatter->setStyle('bg', new OutputFormatterStyle('black', 'white'));
624✔
140

141
        // Aliases
142
        $formatter->setStyle('i', new OutputFormatterStyle('green')); // Alias for <info>
624✔
143
        $formatter->setStyle('c', new OutputFormatterStyle('yellow')); // Alias for <comment>
624✔
144
        $formatter->setStyle('q', new OutputFormatterStyle('black', 'cyan')); // Alias for <question>
624✔
145
        $formatter->setStyle('e', new OutputFormatterStyle('white', 'red')); // Alias for <error>
624✔
146

147
        $output->setFormatter($formatter);
624✔
148
    }
149

150
    /**
151
     * Alias to write new line in std output.
152
     * @SuppressWarnings(PHPMD.NPathComplexity)
153
     */
154
    protected function printMessage(
155
        string $message = '',
156
        string $verboseLevel = OutLvl::DEFAULT,
157
        array $context = [],
158
    ): void {
159
        if (\count($context) > 0) {
624✔
160
            $message .= ' ' . \json_encode($context, \JSON_THROW_ON_ERROR);
138✔
161
        }
162

163
        $profilePrefix = '';
624✔
164

165
        if ($this->isDisplayTimestamp()) {
624✔
166
            $timestamp = (new \DateTimeImmutable())->format($this->timestampFormat);
36✔
167
            $profilePrefix .= "<green>[</green>{$timestamp}<green>]</green> ";
36✔
168
        }
169

170
        $executePrint  = false;
624✔
171
        $printCallback = null;
624✔
172
        $vNormal       = OutputInterface::VERBOSITY_NORMAL;
624✔
173

174
        if ($verboseLevel === OutLvl::DEFAULT) {
624✔
175
            $executePrint  = $this->showMessage($vNormal);
594✔
176
            $printCallback = function (string $profilePrefix) use ($message, $vNormal): void {
594✔
177
                $this->getOutput()->writeln($profilePrefix . $message, $vNormal);
582✔
178
            };
594✔
179
        } elseif ($verboseLevel === OutLvl::V) {
624✔
180
            $executePrint  = $this->showMessage(OutputInterface::VERBOSITY_VERBOSE);
468✔
181
            $printCallback = function (string $profilePrefix) use ($message): void {
468✔
182
                $this->getOutput()->writeln($profilePrefix . $message, OutputInterface::VERBOSITY_VERBOSE);
60✔
183
            };
468✔
184
        } elseif ($verboseLevel === OutLvl::VV) {
624✔
185
            $executePrint  = $this->showMessage(OutputInterface::VERBOSITY_VERY_VERBOSE);
156✔
186
            $printCallback = function (string $profilePrefix) use ($message): void {
156✔
187
                $this->getOutput()->writeln($profilePrefix . $message, OutputInterface::VERBOSITY_VERY_VERBOSE);
48✔
188
            };
156✔
189
        } elseif ($verboseLevel === OutLvl::VVV) {
624✔
190
            $executePrint  = $this->showMessage(OutputInterface::VERBOSITY_DEBUG);
624✔
191
            $printCallback = function (string $profilePrefix) use ($message): void {
624✔
192
                $this->getOutput()->writeln($profilePrefix . $message, OutputInterface::VERBOSITY_DEBUG);
18✔
193
            };
624✔
194
        } elseif ($verboseLevel === OutLvl::Q) {
624✔
195
            $executePrint  = $this->showMessage(OutputInterface::VERBOSITY_QUIET);
240✔
196
            $printCallback = function (string $profilePrefix) use ($message): void {
240✔
197
                $this->getOutput()->writeln(
240✔
198
                    $profilePrefix . $message,
240✔
199
                    OutputInterface::VERBOSITY_QUIET,
240✔
200
                ); // Show ALWAYS!
240✔
201
            };
240✔
202
        } elseif ($verboseLevel === OutLvl::LEGACY) {
624✔
203
            $this->_("<yellow>Legacy Output:</yellow> {$message}");
126✔
204
        } elseif ($verboseLevel === OutLvl::DEBUG) {
624✔
205
            $this->_("<magenta>Debug:</magenta> {$message}", OutLvl::VVV);
624✔
206
        } elseif ($verboseLevel === OutLvl::WARNING) {
486✔
207
            $this->_("<yellow>Warning:</yellow> {$message}", OutLvl::VV);
156✔
208
        } elseif ($verboseLevel === OutLvl::INFO) {
468✔
209
            $this->_("<blue>Info:</blue> {$message}", OutLvl::V);
468✔
210
        } elseif ($verboseLevel === OutLvl::E) {
126✔
211
            $executePrint  = $this->showMessage($vNormal);
126✔
212
            $printCallback = function (string $profilePrefix) use ($message, $vNormal): void {
126✔
213
                $this->markOutputHasErrors(true);
114✔
214
                $this->getErrOutput()->writeln($profilePrefix . $message, $vNormal);
114✔
215
            };
126✔
216
        } elseif ($verboseLevel === OutLvl::ERROR) {
126✔
217
            $executePrint  = $this->showMessage($vNormal);
126✔
218
            $printCallback = function (string $profilePrefix) use ($message, $vNormal): void {
126✔
219
                $this->markOutputHasErrors(true);
114✔
220
                $this->getErrOutput()->writeln("{$profilePrefix}<red-bg>Error:</red-bg> {$message}", $vNormal);
114✔
221
            };
126✔
222
        } elseif ($verboseLevel === OutLvl::EXCEPTION) {
126✔
223
            $executePrint  = $this->showMessage($vNormal);
126✔
224
            $printCallback = function (string $profilePrefix) use ($message, $vNormal): void {
126✔
225
                $this->markOutputHasErrors(true);
114✔
226
                $this->getErrOutput()->writeln(
114✔
227
                    "{$profilePrefix}<red-bg>Muted Exception:</red-bg> {$message}",
114✔
228
                    $vNormal,
114✔
229
                );
114✔
230
            };
126✔
231
        } else {
232
            throw new Exception("Undefined verbose level: \"{$verboseLevel}\"");
×
233
        }
234

235
        if ($executePrint && $printCallback !== null) {
624✔
236
            if ($this->isDisplayProfiling()) {
600✔
237
                $profile = $this->getProfileInfo();
42✔
238
                $oneKb   = 1024;
42✔
239

240
                $timeTotal = \str_pad(\number_format($profile['time_total_ms'] / 1000, 2), 5, ' ', \STR_PAD_LEFT);
42✔
241

242
                $timeDiff = \str_pad(\number_format($profile['time_diff_ms'] / 1000, 2), 5, ' ', \STR_PAD_LEFT);
42✔
243
                $timeDiff = $timeDiff === ' 0.00' ? '<gray>    0</gray>' : $timeDiff;
42✔
244

245
                $memoryDiff = FS::format($profile['memory_usage_diff'], 0);
42✔
246
                $memoryDiff = \str_pad($memoryDiff, 6, ' ', \STR_PAD_LEFT);
42✔
247
                if (\abs($profile['memory_usage_diff']) < $oneKb) {
42✔
248
                    $memoryDiff = '<gray>' . \str_pad($memoryDiff, 6, ' ', \STR_PAD_LEFT) . '</gray>';
42✔
249
                } else {
250
                    $memoryDiff = $profile['memory_usage_diff'] > 0
42✔
251
                        ? "<yellow>{$memoryDiff}</yellow>"
42✔
252
                        : "<green>{$memoryDiff}</green>";
36✔
253
                }
254

255
                $profilerData = [];
42✔
256
                if ($this instanceof Cron) {
42✔
257
                    $profilerData[] = $timeDiff;
30✔
258
                    $profilerData[] = $memoryDiff;
30✔
259
                } else {
260
                    if ($this->showMessage(OutputInterface::VERBOSITY_DEBUG)) {
12✔
261
                        $profilerData[] = $timeTotal;
6✔
262
                        $profilerData[] = $timeDiff;
6✔
263
                        $profilerData[] = $memoryDiff;
6✔
264
                        $profilerData[] = \str_pad(FS::format($profile['memory_usage'], 0), 7, ' ', \STR_PAD_LEFT);
6✔
265
                        $profilerData[] = 'P:' . FS::format($profile['memory_peak'], 0);
6✔
266
                    } elseif ($this->showMessage(OutputInterface::VERBOSITY_VERY_VERBOSE)) {
6✔
UNCOV
267
                        $profilerData[] = $timeTotal;
×
268
                        $profilerData[] = $timeDiff;
×
269
                        $profilerData[] = $memoryDiff;
×
NEW
270
                        $profilerData[] = \str_pad(FS::format($profile['memory_usage'], 0), 7, ' ', \STR_PAD_LEFT);
×
271
                    } elseif ($this->showMessage(OutputInterface::VERBOSITY_VERBOSE)) {
6✔
UNCOV
272
                        $profilerData[] = $timeDiff;
×
273
                        $profilerData[] = $memoryDiff;
×
NEW
274
                        $profilerData[] = \str_pad(FS::format($profile['memory_usage'], 0), 7, ' ', \STR_PAD_LEFT);
×
275
                    } else {
276
                        $profilerData[] = $timeDiff;
6✔
277
                        $profilerData[] = $memoryDiff;
6✔
278
                    }
279
                }
280

281
                $profilePrefix .= '<green>[</green>'
42✔
282
                    . \implode('<green>|</green>', $profilerData)
42✔
283
                    . '<green>]</green> ';
42✔
284
            }
285
            $printCallback($profilePrefix);
600✔
286
        }
287
    }
288

289
    private function showMessage(int $selectedVerbosity): bool
290
    {
291
        $verbosities = OutputInterface::VERBOSITY_QUIET
624✔
292
            | OutputInterface::VERBOSITY_NORMAL
624✔
293
            | OutputInterface::VERBOSITY_VERBOSE
624✔
294
            | OutputInterface::VERBOSITY_VERY_VERBOSE
624✔
295
            | OutputInterface::VERBOSITY_DEBUG;
624✔
296

297
        $verbosity = ($verbosities & $selectedVerbosity) > 0
624✔
298
            ? $verbosities & $selectedVerbosity
624✔
UNCOV
299
            : OutputInterface::VERBOSITY_NORMAL;
×
300

301
        $curVerbose = $this->getOutput()->getVerbosity();
624✔
302

303
        return $verbosity <= $curVerbose;
624✔
304
    }
305

306
    /**
307
     * Weird hack... Need to be fixed in the future.
308
     * @SuppressWarnings(PHPMD.Superglobals)
309
     */
310
    private static function isParallelExec(): bool
311
    {
312
        $argv = $_SERVER['argv'] ?? [];
624✔
313

314
        foreach ($argv as $arg) {
624✔
315
            if (\str_contains($arg, 'pm-max')) {
624✔
316
                return true;
138✔
317
            }
318
        }
319

320
        return false;
486✔
321
    }
322
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc