Skip to content

Commit

Permalink
[Console] Prevent ArgvInput::getFirstArgument() from returning an opt…
Browse files Browse the repository at this point in the history
…ion value
  • Loading branch information
Robin Chalas committed Feb 18, 2019
1 parent ede6c9d commit 5076733
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 2 deletions.
7 changes: 7 additions & 0 deletions src/Symfony/Component/Console/Application.php
Expand Up @@ -202,6 +202,13 @@ public function doRun(InputInterface $input, OutputInterface $output)
return 0;
}

try {
// Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
$input->bind($this->getDefinition());
} catch (ExceptionInterface $e) {
// Errors must be ignored, full binding/validation happens later when the command is known.
}

$name = $this->getCommandName($input);
if (true === $input->hasParameterOption(['--help', '-h'], true)) {
if (!$name) {
Expand Down
19 changes: 18 additions & 1 deletion src/Symfony/Component/Console/Input/ArgvInput.php
Expand Up @@ -262,8 +262,25 @@ private function addLongOption($name, $value)
*/
public function getFirstArgument()
{
foreach ($this->tokens as $token) {
$isOption = false;
foreach ($this->tokens as $i => $token) {
if ($token && '-' === $token[0]) {
if (false !== strpos($token, '=') || !isset($this->tokens[$i + 1])) {
continue;
}

$name = '-' === $token[1] ? substr($token, 2) : substr($token, 1);
if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
// noop
} elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
$isOption = true;
}

continue;
}

if ($isOption) {
$isOption = false;
continue;
}

Expand Down
4 changes: 3 additions & 1 deletion src/Symfony/Component/Console/Input/InputDefinition.php
Expand Up @@ -338,8 +338,10 @@ public function getOptionDefaults()
* @return string The InputOption name
*
* @throws InvalidArgumentException When option given does not exist
*
* @internal
*/
private function shortcutToName($shortcut)
public function shortcutToName($shortcut)
{
if (!isset($this->shortcuts[$shortcut])) {
throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
Expand Down
13 changes: 13 additions & 0 deletions src/Symfony/Component/Console/Tests/ApplicationTest.php
Expand Up @@ -884,6 +884,19 @@ public function testRun()
$this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed');
}

public function testRunWithGlobalOptionAndNoCommand()
{
$application = new Application();
$application->setAutoExit(false);
$application->setCatchExceptions(false);
$application->getDefinition()->addOption(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL));

$output = new StreamOutput(fopen('php://memory', 'w', false));
$input = new ArgvInput(['cli.php', '--foo', 'bar']);

$this->assertSame(0, $application->run($input, $output));
}

/**
* Issue #9285.
*
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
Expand Up @@ -312,6 +312,10 @@ public function testGetFirstArgument()

$input = new ArgvInput(['cli.php', '-fbbar', 'foo']);
$this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input');

$input = new ArgvInput(['cli.php', '--foo', 'fooval', 'bar']);
$input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')]));
$this->assertSame('bar', $input->getFirstArgument());
}

public function testHasParameterOption()
Expand Down

0 comments on commit 5076733

Please sign in to comment.