8000 [Console] do not leak hidden commands · symfony/symfony@afcdc6e · GitHub
[go: up one dir, main page]

Skip to content

Commit afcdc6e

Browse files
committed
[Console] do not leak hidden commands
Hidden commands... - should only be accepted if their names match exactly. - should not appear in suggestion lists. - should not interfere with abbreviating other commands (that would otherwise not be distinct).
1 parent ed2a5ce commit afcdc6e

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ public function getNamespaces()
557557
{
558558
$namespaces = [];
559559
foreach ($this->all() as $command) {
560+
if ($command->isHidden()) {
561+
continue;
562+
}
563+
560564
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
561565

562566
foreach ($command->getAliases() as $alias) {
@@ -644,6 +648,12 @@ public function find($name)
644648
$commands = preg_grep('{^'.$expr.'}i', $allCommands);
645649
}
646650

651+
// hidden commands can only be matched exactly and shall not appear otherwise
652+
$hiddenCommands = $this->removeHiddenCommands($commands);
653+
if (isset($hiddenCommands[$name])) {
654+
return $hiddenCommands[$name];
655+
}
656+
647657
// if no commands matched or we just matched namespaces
648658
if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) {
649659
if (false !== $pos = strrpos($name, ':')) {
@@ -654,6 +664,8 @@ public function find($name)
654664
$message = sprintf('Command "%s" is not defined.', $name);
655665

656666
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
667+
$this->removeHiddenCommands($alternatives);
668+
657669
if (1 == \count($alternatives)) {
658670
$message .= "\n\nDid you mean this?\n ";
659671
} else {
@@ -1101,6 +1113,38 @@ private function findAlternatives(string $name, iterable $collection): array
11011113
return array_keys($alternatives);
11021114
}
11031115

1116+
/**
1117+
* Removes hidden commands commands from a given array of command names and
1118+
* returns them as Command instances.
1119+
*
1120+
* @param string[] $commandNames The command names to filter
1121+
*
1122+
* @return Command[] An associative array of removed commands with
1123+
* command names and command aliases being the keys
1124+
*
1125+
* @internal
1126+
*/
1127+
private function removeHiddenCommands(array &$commandNames): array
1128+
{
1129+
$hiddenCommands = [];
1130+
foreach ($commandNames as $key => $commandName) {
1131+
$command = $this->has($commandName) ? $this->commands[$commandName] : $this->commandLoader->get($commandName);
1132+
1133+
if (!$command->isHidden()) {
1134+
continue;
1135+
}
1136+
1137+
$hiddenCommands[$commandName] = $command;
1138+
foreach ($command->getAliases() as $alias) {
1139+
$hiddenCommands[$alias] = $command;
1140+
}
1141+
1142+
unset($commandNames[$key]);
1143+
}
1144+
1145+
return $hiddenCommands;
1146+
}
1147+
11041148
/**
11051149
* Sets the default Command name.
11061150
*

0 commit comments

Comments
 (0)
0