Issues (224)

src/Console/Command/Info.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Console\Command;
16
17
use Fidry\Console\Command\Command;
18
use Fidry\Console\Command\Configuration;
19
use Fidry\Console\ExitCode;
20
use Fidry\Console\IO;
21
use KevinGH\Box\Console\PharInfoRenderer;
22
use KevinGH\Box\Phar\PharInfo;
23
use Phar;
24
use Symfony\Component\Console\Input\InputArgument;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Filesystem\Path;
27
use function implode;
28
use function is_array;
29
use function realpath;
30
use function sprintf;
31
32
/**
33
 * @private
34
 */
35
final readonly class Info implements Command
0 ignored issues
show
A parse error occurred: Syntax error, unexpected T_READONLY, expecting T_CLASS on line 35 at column 6
Loading history...
36
{
37
    private const PHAR_ARG = 'phar';
38
    private const LIST_OPT = 'list';
39
    private const MODE_OPT = 'mode';
40
    private const DEPTH_OPT = 'depth';
41
42
    private const MODES = [
43
        'indent',
44
        'flat',
45
    ];
46
47
    public function __construct(private string $commandName = 'info')
48
    {
49
    }
50
51
    public function getConfiguration(): Configuration
52
    {
53
        return new Configuration(
54
            $this->commandName,
55
            '🔍  Displays information about the PHAR extension or file',
56
            <<<'HELP'
57
                The <info>%command.name%</info> command will display information about the Phar extension,
58
                or the Phar file if specified.
59
60
                If the <info>phar</info> argument <comment>(the PHAR file path)</comment> is provided, information
61
                about the PHAR file itself will be displayed.
62
63
                If the <info>--list|-l</info> option is used, the contents of the PHAR file will
64
                be listed. By default, the list is shown as an indented tree. You may
65
                instead choose to view a flat listing, by setting the <info>--mode|-m</info> option
66
                to <comment>flat</comment>.
67
                HELP,
68
            [
69
                new InputArgument(
70
                    self::PHAR_ARG,
71
                    InputArgument::OPTIONAL,
72
                    'The Phar file.',
73
                ),
74
            ],
75
            [
76
                new InputOption(
77
                    self::LIST_OPT,
78
                    'l',
79
                    InputOption::VALUE_NONE,
80
                    'List the contents of the Phar?',
81
                ),
82
                new InputOption(
83
                    self::MODE_OPT,
84
                    'm',
85
                    InputOption::VALUE_REQUIRED,
86
                    sprintf(
87
                        'The listing mode. Modes available: "%s"',
88
                        implode('", "', self::MODES),
89
                    ),
90
                    'indent',
91
                ),
92
                new InputOption(
93
                    self::DEPTH_OPT,
94
                    'd',
95
                    InputOption::VALUE_REQUIRED,
96
                    'The depth of the tree displayed',
97
                    '-1',
98
                ),
99
            ],
100
        );
101
    }
102
103
    public function execute(IO $io): int
104
    {
105
        $io->newLine();
106
107
        $file = $io->getTypedArgument(self::PHAR_ARG)->asNullableNonEmptyString();
108
109
        if (null === $file) {
110
            return self::showGlobalInfo($io);
111
        }
112
113
        $file = Path::canonicalize($file);
114
        $fileRealPath = realpath($file);
115
116
        if (false === $fileRealPath) {
117
            $io->error(
118
                sprintf(
119
                    'The file "%s" could not be found.',
120
                    $file,
121
                ),
122
            );
123
124
            return ExitCode::FAILURE;
125
        }
126
127
        return self::showInfo($fileRealPath, $io);
128
    }
129
130
    public static function showInfo(string $file, IO $io): int
131
    {
132
        $maxDepth = self::getMaxDepth($io);
133
        $mode = $io->getTypedOption(self::MODE_OPT)->asStringChoice(self::MODES);
134
135
        $pharInfo = new PharInfo($file);
136
137
        return self::showPharInfo(
138
            $pharInfo,
139
            $io->getTypedOption(self::LIST_OPT)->asBoolean(),
140
            -1 === $maxDepth ? false : $maxDepth,
141
            'indent' === $mode,
142
            $io,
143
        );
144
    }
145
146
    /**
147
     * @return -1|natural
148
     */
149
    private static function getMaxDepth(IO $io): int
150
    {
151
        $option = $io->getTypedOption(self::DEPTH_OPT);
152
153
        return '-1' === $option->asRaw()
154
            ? -1
155
            : $option->asNatural(sprintf(
156
                'Expected the depth to be a positive integer or -1: "%s".',
157
                $option->asRaw(),
158
            ));
159
    }
160
161
    private static function showGlobalInfo(IO $io): int
162
    {
163
        self::render(
164
            $io,
165
            [
166
                'API Version' => Phar::apiVersion(),
167
                'Supported Compression' => Phar::getSupportedCompression(),
168
                'Supported Signatures' => Phar::getSupportedSignatures(),
169
            ],
170
        );
171
172
        $io->newLine();
173
        $io->comment('Get a PHAR details by giving its path as an argument.');
174
175
        return ExitCode::SUCCESS;
176
    }
177
178
    private static function showPharInfo(
179
        PharInfo $pharInfo,
180
        bool $content,
181
        false|int $maxDepth,
182
        bool $indent,
183
        IO $io,
184
    ): int {
185
        PharInfoRenderer::renderVersion($pharInfo, $io);
186
187
        $io->newLine();
188
189
        PharInfoRenderer::renderBoxVersion($pharInfo, $io);
190
191
        PharInfoRenderer::renderShortSummary(
192
            $pharInfo,
193
            $io,
194
            static fn () => $io->newLine(),
195
        );
196
197
        if ($content) {
198
            PharInfoRenderer::renderContent(
199
                $io,
200
                $pharInfo,
201
                $maxDepth,
202
                $indent,
203
            );
204
        } else {
205
            $io->newLine();
206
            $io->comment('Use the <info>--list|-l</info> option to list the content of the PHAR.');
207
        }
208
209
        return ExitCode::SUCCESS;
210
    }
211
212
    private static function showPharMeta(PharInfo $pharInfo, IO $io): void
213
    {
214
        PharInfoRenderer::renderVersion($pharInfo, $io);
215
216
        $io->newLine();
217
218
        PharInfoRenderer::renderShortSummary(
219
            $pharInfo,
220
            $io,
221
            static fn () => $io->newLine(),
222
        );
223
    }
224
225
    private static function render(IO $io, array $attributes): void
226
    {
227
        $out = false;
228
229
        foreach ($attributes as $name => $value) {
230
            if ($out) {
231
                $io->writeln('');
232
            }
233
234
            $io->write("<comment>{$name}:</comment>");
235
236
            if (is_array($value)) {
237
                $io->writeln('');
238
239
                foreach ($value as $v) {
240
                    $io->writeln("  - {$v}");
241
                }
242
            } else {
243
                $io->writeln(" {$value}");
244
            }
245
246
            $out = true;
247
        }
248
    }
249
}
250