bug #33748 [Console] Do not include hidden commands in suggested alternatives (m-vo)
This PR was merged into the 3.4 branch.
Discussion
----------
[Console] Do not include hidden commands in suggested alternatives
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | Fix #33398
| License | MIT
| Doc PR | n/a
Partially backports #33412 on 3.4, avoids leaking the names of hidden commands in suggested alternatives on command not found.
Commits
-------
8a9d173c36
Do not include hidden commands in suggested alternatives
This commit is contained in:
commit
944cda7969
@ -529,6 +529,10 @@ class Application
|
|||||||
{
|
{
|
||||||
$namespaces = [];
|
$namespaces = [];
|
||||||
foreach ($this->all() as $command) {
|
foreach ($this->all() as $command) {
|
||||||
|
if ($command->isHidden()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||||
|
|
||||||
foreach ($command->getAliases() as $alias) {
|
foreach ($command->getAliases() as $alias) {
|
||||||
@ -622,6 +626,11 @@ class Application
|
|||||||
$message = sprintf('Command "%s" is not defined.', $name);
|
$message = sprintf('Command "%s" is not defined.', $name);
|
||||||
|
|
||||||
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
|
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
|
||||||
|
// remove hidden commands
|
||||||
|
$alternatives = array_filter($alternatives, function ($name) {
|
||||||
|
return !$this->get($name)->isHidden();
|
||||||
|
});
|
||||||
|
|
||||||
if (1 == \count($alternatives)) {
|
if (1 == \count($alternatives)) {
|
||||||
$message .= "\n\nDid you mean this?\n ";
|
$message .= "\n\nDid you mean this?\n ";
|
||||||
} else {
|
} else {
|
||||||
@ -630,7 +639,7 @@ class Application
|
|||||||
$message .= implode("\n ", $alternatives);
|
$message .= implode("\n ", $alternatives);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new CommandNotFoundException($message, $alternatives);
|
throw new CommandNotFoundException($message, array_values($alternatives));
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter out aliases for commands which are already on the list
|
// filter out aliases for commands which are already on the list
|
||||||
@ -654,13 +663,18 @@ class Application
|
|||||||
}
|
}
|
||||||
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
|
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
|
||||||
if (!$commandList[$cmd] instanceof Command) {
|
if (!$commandList[$cmd] instanceof Command) {
|
||||||
return $cmd;
|
$commandList[$cmd] = $this->commandLoader->get($cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($commandList[$cmd]->isHidden()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
|
$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
|
||||||
|
|
||||||
return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
|
return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
|
||||||
}, array_values($commands));
|
}, array_values($commands));
|
||||||
$suggestions = $this->getAbbreviationSuggestions($abbrevs);
|
$suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));
|
||||||
|
|
||||||
throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands));
|
throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands));
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ class ApplicationTest extends TestCase
|
|||||||
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
|
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
|
||||||
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering.php';
|
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering.php';
|
||||||
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering2.php';
|
require_once self::$fixturesPath.'/TestAmbiguousCommandRegistering2.php';
|
||||||
|
require_once self::$fixturesPath.'/FooHiddenCommand.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function normalizeLineBreaks($text)
|
protected function normalizeLineBreaks($text)
|
||||||
@ -616,6 +617,7 @@ class ApplicationTest extends TestCase
|
|||||||
$application->add(new \Foo1Command());
|
$application->add(new \Foo1Command());
|
||||||
$application->add(new \Foo2Command());
|
$application->add(new \Foo2Command());
|
||||||
$application->add(new \Foo3Command());
|
$application->add(new \Foo3Command());
|
||||||
|
$application->add(new \FooHiddenCommand());
|
||||||
|
|
||||||
$expectedAlternatives = [
|
$expectedAlternatives = [
|
||||||
'afoobar',
|
'afoobar',
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class FooHiddenCommand extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('foo:hidden')
|
||||||
|
->setAliases(['afoohidden'])
|
||||||
|
->setHidden(true)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user