Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
103 / 103 |
|
96.34% |
79 / 82 |
|
22.92% |
22 / 96 |
|
80.00% |
8 / 10 |
CRAP | |
0.00% |
0 / 1 |
| Runner | |
100.00% |
103 / 103 |
|
96.34% |
79 / 82 |
|
22.92% |
22 / 96 |
|
100.00% |
10 / 10 |
735.64 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| orderCommands | |
100.00% |
21 / 21 |
|
88.89% |
16 / 18 |
|
0.00% |
0 / 36 |
|
100.00% |
1 / 1 |
7 | |||
| showHelp | |
100.00% |
13 / 13 |
|
100.00% |
7 / 7 |
|
20.00% |
1 / 5 |
|
100.00% |
1 / 1 |
7.61 | |||
| showCommands | |
100.00% |
14 / 14 |
|
100.00% |
14 / 14 |
|
0.00% |
0 / 24 |
|
100.00% |
1 / 1 |
6 | |||
| run | |
100.00% |
27 / 27 |
|
100.00% |
17 / 17 |
|
90.00% |
9 / 10 |
|
100.00% |
1 / 1 |
9.08 | |||
| echoGroup | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| echoCommand | |
100.00% |
4 / 4 |
|
100.00% |
4 / 4 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| showAmbiguousMessage | |
100.00% |
7 / 7 |
|
100.00% |
4 / 4 |
|
33.33% |
1 / 3 |
|
100.00% |
1 / 1 |
3.19 | |||
| getCommand | |
100.00% |
9 / 9 |
|
92.31% |
12 / 13 |
|
41.67% |
5 / 12 |
|
100.00% |
1 / 1 |
13.15 | |||
| runCommand | |
100.00% |
4 / 4 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celemas\Cli; |
| 6 | |
| 7 | use Throwable; |
| 8 | use ValueError; |
| 9 | |
| 10 | /** |
| 11 | * @api |
| 12 | */ |
| 13 | final class Runner |
| 14 | { |
| 15 | protected const AMBIGUOUS = 1; |
| 16 | protected const NOTFOUND = 2; |
| 17 | |
| 18 | // The commands ordered by group and name |
| 19 | private array $toc = []; |
| 20 | |
| 21 | // The commands indexed by name only |
| 22 | private array $list = []; |
| 23 | private Output $output; |
| 24 | private int $longestName = 0; |
| 25 | |
| 26 | public function __construct( |
| 27 | Commands $commands, |
| 28 | string $output = 'php://output', |
| 29 | private bool $debug = false, |
| 30 | ) { |
| 31 | $this->output = new Output($output); |
| 32 | $this->orderCommands($commands); |
| 33 | } |
| 34 | |
| 35 | public function orderCommands(Commands $commands): void |
| 36 | { |
| 37 | $groups = []; |
| 38 | |
| 39 | foreach ($commands->get() as $command) { |
| 40 | $name = strtolower($command->name()); |
| 41 | $prefix = $command->prefix(); |
| 42 | |
| 43 | if (!array_key_exists($prefix, $groups)) { |
| 44 | $group = $command->group(); |
| 45 | $group = $group === '' ? 'General' : $group; |
| 46 | $groups[$prefix] = [ |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 48 | 'commands' => [], |
| 49 | ]; |
| 50 | } |
| 51 | |
| 52 | $groups[$prefix]['commands'][$name] = $command; |
| 53 | |
| 54 | $this->list[$name][] = $command; |
| 55 | |
| 56 | $len = strlen($prefix . ':' . $command->name()); |
| 57 | $this->longestName = $len > $this->longestName ? $len : $this->longestName; |
| 58 | } |
| 59 | |
| 60 | ksort($groups); |
| 61 | |
| 62 | foreach ($groups as $name => $group) { |
| 63 | $commands = $group['commands']; |
| 64 | ksort($commands); |
| 65 | $group['commands'] = $commands; |
| 66 | $this->toc[$name] = $group; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | public function showHelp(): int |
| 71 | { |
| 72 | $script = $_SERVER['argv'][0] ?? ''; |
| 73 | $this->output->echo($this->output->color('Usage:', 'brown') . "\n"); |
| 74 | $this->output->echo(" php {$script} [prefix:]command [arguments]\n\n"); |
| 75 | $this->output->echo("Prefixes are optional if the command is unambiguous.\n\n"); |
| 76 | $this->output->echo("Available commands:\n"); |
| 77 | $this->echoGroup('General'); |
| 78 | $this->echoCommand('', 'commands', 'Lists all available commands'); |
| 79 | $this->echoCommand('', 'help', 'Displays this overview'); |
| 80 | |
| 81 | foreach ($this->toc as $group) { |
| 82 | $this->echoGroup($group['title']); |
| 83 | |
| 84 | foreach ($group['commands'] as $name => $command) { |
| 85 | $this->echoCommand($command->prefix(), $name, $command->description()); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | return 0; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Displays a list of all available commands. |
| 94 | * |
| 95 | * With and without namespace/group. If a command appears in more than |
| 96 | * one namespace, e. g. foo:cmd and bar:cmd, only the namespaced ones |
| 97 | * will be displayed. |
| 98 | */ |
| 99 | public function showCommands(): int |
| 100 | { |
| 101 | $list = []; |
| 102 | |
| 103 | foreach ($this->toc as $group) { |
| 104 | foreach ($group['commands'] as $command) { |
| 105 | $prefix = $command->prefix(); |
| 106 | |
| 107 | if ($prefix) { |
| 108 | $key = "{$prefix}:" . $command->name(); |
| 109 | $list[$key] = ($list[$key] ?? 0) + 1; |
| 110 | } |
| 111 | |
| 112 | $name = $command->name(); |
| 113 | $list[$name] = ($list[$name] ?? 0) + 1; |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | ksort($list); |
| 118 | |
| 119 | foreach ($list as $name => $count) { |
| 120 | if ($count === 1) { |
| 121 | $this->output->echo("{$name}\n"); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | return 0; |
| 126 | } |
| 127 | |
| 128 | public function run(): int|string |
| 129 | { |
| 130 | try { |
| 131 | $argv = $_SERVER['argv'] ?? []; |
| 132 | |
| 133 | $arg = $argv[1] ?? null; |
| 134 | |
| 135 | if ($arg !== null) { |
| 136 | $cmd = strtolower($arg); |
| 137 | $isHelpCall = false; |
| 138 | |
| 139 | if ($cmd === 'help') { |
| 140 | $isHelpCall = true; |
| 141 | |
| 142 | $arg = $argv[2] ?? null; |
| 143 | |
| 144 | if ($arg === null) { |
| 145 | return $this->showHelp(); |
| 146 | } |
| 147 | |
| 148 | $cmd = strtolower($arg); |
| 149 | } |
| 150 | |
| 151 | if ($cmd === 'commands') { |
| 152 | return $this->showCommands(); |
| 153 | } |
| 154 | |
| 155 | try { |
| 156 | return $this->runCommand($this->getCommand($cmd), $isHelpCall); |
| 157 | } catch (ValueError $e) { |
| 158 | if ($e->getCode() === self::AMBIGUOUS) { |
| 159 | return $this->showAmbiguousMessage($cmd); |
| 160 | } |
| 161 | |
| 162 | throw $e; |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | return $this->showHelp(); |
| 167 | } catch (Throwable $e) { |
| 168 | $this->output->echo("Error while running command '"); |
| 169 | $this->output->echo($_SERVER['argv'][1] ?? '<no command given>'); |
| 170 | $this->output->echo("':\n\n" . $e->getMessage() . "\n"); |
| 171 | |
| 172 | if ($this->debug) { |
| 173 | $this->output->echoln("\nTraceback:", 'yellow'); |
| 174 | $this->output->echoln($e->getTraceAsString()); |
| 175 | } |
| 176 | |
| 177 | return 1; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | private function echoGroup(string $title): void |
| 182 | { |
| 183 | $g = $this->output->color($title, 'brown'); |
| 184 | $this->output->echo("\n{$g}\n"); |
| 185 | } |
| 186 | |
| 187 | private function echoCommand(string $prefix, string $name, string $desc): void |
| 188 | { |
| 189 | $prefix = $prefix ? $prefix . ':' : ''; |
| 190 | $name = $this->output->color($name, 'green'); |
| 191 | |
| 192 | // The added magic number takes colorization into |
| 193 | // account as it lengthens the string. |
| 194 | $prefixedName = str_pad($prefix . $name, $this->longestName + 13); |
| 195 | $this->output->echoln(" {$prefixedName}{$desc}"); |
| 196 | } |
| 197 | |
| 198 | private function showAmbiguousMessage(string $cmd): int |
| 199 | { |
| 200 | $this->output->echo("Ambiguous command. Please add the group name:\n\n"); |
| 201 | asort($this->list[$cmd]); |
| 202 | |
| 203 | foreach ($this->list[$cmd] as $command) { |
| 204 | $prefix = $this->output->color($command->prefix(), 'brown'); |
| 205 | $name = strtolower($command->name()); |
| 206 | $this->output->echoln(" {$prefix}:{$name}"); |
| 207 | } |
| 208 | |
| 209 | return 1; |
| 210 | } |
| 211 | |
| 212 | private function getCommand(string $cmd): Command |
| 213 | { |
| 214 | if (array_key_exists($cmd, $this->list)) { |
| 215 | if (count($this->list[$cmd]) === 1) { |
| 216 | return $this->list[$cmd][0]; |
| 217 | } |
| 218 | |
| 219 | throw new ValueError('Ambiguous command', self::AMBIGUOUS); |
| 220 | } |
| 221 | |
| 222 | if (str_contains($cmd, ':')) { |
| 223 | [$group, $name] = explode(':', $cmd); |
| 224 | |
| 225 | if ( |
| 226 | array_key_exists($group, $this->toc) && array_key_exists($name, $this->toc[$group]['commands']) |
| 227 | ) { |
| 228 | return $this->toc[$group]['commands'][$name]; |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | throw new ValueError('Command not found', self::NOTFOUND); |
| 233 | } |
| 234 | |
| 235 | private function runCommand(Command $command, bool $isHelpCall): int|string |
| 236 | { |
| 237 | if ($isHelpCall) { |
| 238 | $command->output($this->output)->help(); |
| 239 | |
| 240 | return 0; |
| 241 | } |
| 242 | |
| 243 | return $command->output($this->output)->run(); |
| 244 | } |
| 245 | } |
Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not
necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once.
Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 27 | Commands $commands, |
| 28 | string $output = 'php://output', |
| 29 | private bool $debug = false, |
| 30 | ) { |
| 31 | $this->output = new Output($output); |
| 32 | $this->orderCommands($commands); |
| 33 | } |
| 187 | private function echoCommand(string $prefix, string $name, string $desc): void |
| 188 | { |
| 189 | $prefix = $prefix ? $prefix . ':' : ''; |
| 189 | $prefix = $prefix ? $prefix . ':' : ''; |
| 189 | $prefix = $prefix ? $prefix . ':' : ''; |
| 189 | $prefix = $prefix ? $prefix . ':' : ''; |
| 190 | $name = $this->output->color($name, 'green'); |
| 191 | |
| 192 | // The added magic number takes colorization into |
| 193 | // account as it lengthens the string. |
| 194 | $prefixedName = str_pad($prefix . $name, $this->longestName + 13); |
| 195 | $this->output->echoln(" {$prefixedName}{$desc}"); |
| 196 | } |
| 181 | private function echoGroup(string $title): void |
| 182 | { |
| 183 | $g = $this->output->color($title, 'brown'); |
| 184 | $this->output->echo("\n{$g}\n"); |
| 185 | } |
| 212 | private function getCommand(string $cmd): Command |
| 213 | { |
| 214 | if (array_key_exists($cmd, $this->list)) { |
| 215 | if (count($this->list[$cmd]) === 1) { |
| 216 | return $this->list[$cmd][0]; |
| 219 | throw new ValueError('Ambiguous command', self::AMBIGUOUS); |
| 222 | if (str_contains($cmd, ':')) { |
| 222 | if (str_contains($cmd, ':')) { |
| 222 | if (str_contains($cmd, ':')) { |
| 222 | if (str_contains($cmd, ':')) { |
| 223 | [$group, $name] = explode(':', $cmd); |
| 224 | |
| 225 | if ( |
| 226 | array_key_exists($group, $this->toc) && array_key_exists($name, $this->toc[$group]['commands']) |
| 226 | array_key_exists($group, $this->toc) && array_key_exists($name, $this->toc[$group]['commands']) |
| 226 | array_key_exists($group, $this->toc) && array_key_exists($name, $this->toc[$group]['commands']) |
| 228 | return $this->toc[$group]['commands'][$name]; |
| 232 | throw new ValueError('Command not found', self::NOTFOUND); |
| 233 | } |
| 35 | public function orderCommands(Commands $commands): void |
| 36 | { |
| 37 | $groups = []; |
| 38 | |
| 39 | foreach ($commands->get() as $command) { |
| 39 | foreach ($commands->get() as $command) { |
| 40 | $name = strtolower($command->name()); |
| 41 | $prefix = $command->prefix(); |
| 42 | |
| 43 | if (!array_key_exists($prefix, $groups)) { |
| 44 | $group = $command->group(); |
| 45 | $group = $group === '' ? 'General' : $group; |
| 45 | $group = $group === '' ? 'General' : $group; |
| 45 | $group = $group === '' ? 'General' : $group; |
| 45 | $group = $group === '' ? 'General' : $group; |
| 46 | $groups[$prefix] = [ |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 48 | 'commands' => [], |
| 49 | ]; |
| 50 | } |
| 51 | |
| 52 | $groups[$prefix]['commands'][$name] = $command; |
| 52 | $groups[$prefix]['commands'][$name] = $command; |
| 53 | |
| 54 | $this->list[$name][] = $command; |
| 55 | |
| 56 | $len = strlen($prefix . ':' . $command->name()); |
| 57 | $this->longestName = $len > $this->longestName ? $len : $this->longestName; |
| 57 | $this->longestName = $len > $this->longestName ? $len : $this->longestName; |
| 57 | $this->longestName = $len > $this->longestName ? $len : $this->longestName; |
| 39 | foreach ($commands->get() as $command) { |
| 40 | $name = strtolower($command->name()); |
| 41 | $prefix = $command->prefix(); |
| 42 | |
| 43 | if (!array_key_exists($prefix, $groups)) { |
| 44 | $group = $command->group(); |
| 45 | $group = $group === '' ? 'General' : $group; |
| 46 | $groups[$prefix] = [ |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 48 | 'commands' => [], |
| 49 | ]; |
| 50 | } |
| 51 | |
| 52 | $groups[$prefix]['commands'][$name] = $command; |
| 53 | |
| 54 | $this->list[$name][] = $command; |
| 55 | |
| 56 | $len = strlen($prefix . ':' . $command->name()); |
| 57 | $this->longestName = $len > $this->longestName ? $len : $this->longestName; |
| 39 | foreach ($commands->get() as $command) { |
| 40 | $name = strtolower($command->name()); |
| 41 | $prefix = $command->prefix(); |
| 42 | |
| 43 | if (!array_key_exists($prefix, $groups)) { |
| 44 | $group = $command->group(); |
| 45 | $group = $group === '' ? 'General' : $group; |
| 46 | $groups[$prefix] = [ |
| 47 | 'title' => $prefix === '' ? 'General' : $group, |
| 48 | 'commands' => [], |
| 49 | ]; |
| 50 | } |
| 51 | |
| 52 | $groups[$prefix]['commands'][$name] = $command; |
| 53 | |
| 54 | $this->list[$name][] = $command; |
| 55 | |
| 56 | $len = strlen($prefix . ':' . $command->name()); |
| 57 | $this->longestName = $len > $this->longestName ? $len : $this->longestName; |
| 58 | } |
| 59 | |
| 60 | ksort($groups); |
| 61 | |
| 62 | foreach ($groups as $name => $group) { |
| 62 | foreach ($groups as $name => $group) { |
| 62 | foreach ($groups as $name => $group) { |
| 62 | foreach ($groups as $name => $group) { |
| 63 | $commands = $group['commands']; |
| 64 | ksort($commands); |
| 65 | $group['commands'] = $commands; |
| 66 | $this->toc[$name] = $group; |
| 67 | } |
| 68 | } |
| 130 | try { |
| 131 | $argv = $_SERVER['argv'] ?? []; |
| 132 | |
| 133 | $arg = $argv[1] ?? null; |
| 134 | |
| 135 | if ($arg !== null) { |
| 136 | $cmd = strtolower($arg); |
| 137 | $isHelpCall = false; |
| 138 | |
| 139 | if ($cmd === 'help') { |
| 140 | $isHelpCall = true; |
| 141 | |
| 142 | $arg = $argv[2] ?? null; |
| 143 | |
| 144 | if ($arg === null) { |
| 145 | return $this->showHelp(); |
| 148 | $cmd = strtolower($arg); |
| 149 | } |
| 150 | |
| 151 | if ($cmd === 'commands') { |
| 151 | if ($cmd === 'commands') { |
| 152 | return $this->showCommands(); |
| 155 | try { |
| 156 | return $this->runCommand($this->getCommand($cmd), $isHelpCall); |
| 157 | } catch (ValueError $e) { |
| 158 | if ($e->getCode() === self::AMBIGUOUS) { |
| 159 | return $this->showAmbiguousMessage($cmd); |
| 162 | throw $e; |
| 166 | return $this->showHelp(); |
| 167 | } catch (Throwable $e) { |
| 168 | $this->output->echo("Error while running command '"); |
| 169 | $this->output->echo($_SERVER['argv'][1] ?? '<no command given>'); |
| 170 | $this->output->echo("':\n\n" . $e->getMessage() . "\n"); |
| 171 | |
| 172 | if ($this->debug) { |
| 173 | $this->output->echoln("\nTraceback:", 'yellow'); |
| 174 | $this->output->echoln($e->getTraceAsString()); |
| 175 | } |
| 176 | |
| 177 | return 1; |
| 177 | return 1; |
| 178 | } |
| 179 | } |
| 235 | private function runCommand(Command $command, bool $isHelpCall): int|string |
| 236 | { |
| 237 | if ($isHelpCall) { |
| 238 | $command->output($this->output)->help(); |
| 239 | |
| 240 | return 0; |
| 243 | return $command->output($this->output)->run(); |
| 244 | } |
| 198 | private function showAmbiguousMessage(string $cmd): int |
| 199 | { |
| 200 | $this->output->echo("Ambiguous command. Please add the group name:\n\n"); |
| 201 | asort($this->list[$cmd]); |
| 202 | |
| 203 | foreach ($this->list[$cmd] as $command) { |
| 203 | foreach ($this->list[$cmd] as $command) { |
| 203 | foreach ($this->list[$cmd] as $command) { |
| 204 | $prefix = $this->output->color($command->prefix(), 'brown'); |
| 203 | foreach ($this->list[$cmd] as $command) { |
| 204 | $prefix = $this->output->color($command->prefix(), 'brown'); |
| 205 | $name = strtolower($command->name()); |
| 206 | $this->output->echoln(" {$prefix}:{$name}"); |
| 207 | } |
| 208 | |
| 209 | return 1; |
| 210 | } |
| 101 | $list = []; |
| 102 | |
| 103 | foreach ($this->toc as $group) { |
| 103 | foreach ($this->toc as $group) { |
| 104 | foreach ($group['commands'] as $command) { |
| 104 | foreach ($group['commands'] as $command) { |
| 105 | $prefix = $command->prefix(); |
| 106 | |
| 107 | if ($prefix) { |
| 108 | $key = "{$prefix}:" . $command->name(); |
| 109 | $list[$key] = ($list[$key] ?? 0) + 1; |
| 110 | } |
| 111 | |
| 112 | $name = $command->name(); |
| 104 | foreach ($group['commands'] as $command) { |
| 105 | $prefix = $command->prefix(); |
| 106 | |
| 107 | if ($prefix) { |
| 108 | $key = "{$prefix}:" . $command->name(); |
| 109 | $list[$key] = ($list[$key] ?? 0) + 1; |
| 110 | } |
| 111 | |
| 112 | $name = $command->name(); |
| 103 | foreach ($this->toc as $group) { |
| 104 | foreach ($group['commands'] as $command) { |
| 103 | foreach ($this->toc as $group) { |
| 104 | foreach ($group['commands'] as $command) { |
| 105 | $prefix = $command->prefix(); |
| 106 | |
| 107 | if ($prefix) { |
| 108 | $key = "{$prefix}:" . $command->name(); |
| 109 | $list[$key] = ($list[$key] ?? 0) + 1; |
| 110 | } |
| 111 | |
| 112 | $name = $command->name(); |
| 113 | $list[$name] = ($list[$name] ?? 0) + 1; |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | ksort($list); |
| 118 | |
| 119 | foreach ($list as $name => $count) { |
| 119 | foreach ($list as $name => $count) { |
| 119 | foreach ($list as $name => $count) { |
| 120 | if ($count === 1) { |
| 119 | foreach ($list as $name => $count) { |
| 120 | if ($count === 1) { |
| 121 | $this->output->echo("{$name}\n"); |
| 119 | foreach ($list as $name => $count) { |
| 119 | foreach ($list as $name => $count) { |
| 120 | if ($count === 1) { |
| 121 | $this->output->echo("{$name}\n"); |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | return 0; |
| 126 | } |
| 72 | $script = $_SERVER['argv'][0] ?? ''; |
| 73 | $this->output->echo($this->output->color('Usage:', 'brown') . "\n"); |
| 74 | $this->output->echo(" php {$script} [prefix:]command [arguments]\n\n"); |
| 75 | $this->output->echo("Prefixes are optional if the command is unambiguous.\n\n"); |
| 76 | $this->output->echo("Available commands:\n"); |
| 77 | $this->echoGroup('General'); |
| 78 | $this->echoCommand('', 'commands', 'Lists all available commands'); |
| 79 | $this->echoCommand('', 'help', 'Displays this overview'); |
| 80 | |
| 81 | foreach ($this->toc as $group) { |
| 81 | foreach ($this->toc as $group) { |
| 82 | $this->echoGroup($group['title']); |
| 83 | |
| 84 | foreach ($group['commands'] as $name => $command) { |
| 84 | foreach ($group['commands'] as $name => $command) { |
| 84 | foreach ($group['commands'] as $name => $command) { |
| 81 | foreach ($this->toc as $group) { |
| 82 | $this->echoGroup($group['title']); |
| 83 | |
| 84 | foreach ($group['commands'] as $name => $command) { |
| 81 | foreach ($this->toc as $group) { |
| 82 | $this->echoGroup($group['title']); |
| 83 | |
| 84 | foreach ($group['commands'] as $name => $command) { |
| 85 | $this->echoCommand($command->prefix(), $name, $command->description()); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | return 0; |
| 90 | } |