diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index a9351a589720c..30ec89d966015 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -160,14 +160,14 @@ public function run(InputInterface $input = null, OutputInterface $output = null */ public function doRun(InputInterface $input, OutputInterface $output) { - if (true === $input->hasParameterOption(array('--version', '-V'))) { + if (true === $input->hasParameterOption(array('--version', '-V'), $input::OPTION_FLAG_POSIX)) { $output->writeln($this->getLongVersion()); return 0; } $name = $this->getCommandName($input); - if (true === $input->hasParameterOption(array('--help', '-h'))) { + if (true === $input->hasParameterOption(array('--help', '-h'), $input::OPTION_FLAG_POSIX)) { if (!$name) { $name = 'help'; $input = new ArrayInput(array('command' => 'help')); @@ -789,13 +789,13 @@ public function setTerminalDimensions($width, $height) */ protected function configureIO(InputInterface $input, OutputInterface $output) { - if (true === $input->hasParameterOption(array('--ansi'))) { + if (true === $input->hasParameterOption(array('--ansi'), $input::OPTION_FLAG_POSIX)) { $output->setDecorated(true); - } elseif (true === $input->hasParameterOption(array('--no-ansi'))) { + } elseif (true === $input->hasParameterOption(array('--no-ansi'), $input::OPTION_FLAG_POSIX)) { $output->setDecorated(false); } - if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) { + if (true === $input->hasParameterOption(array('--no-interaction', '-n'), $input::OPTION_FLAG_POSIX)) { $input->setInteractive(false); } elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) { $inputStream = $this->getHelperSet()->get('question')->getInputStream(); @@ -804,15 +804,15 @@ protected function configureIO(InputInterface $input, OutputInterface $output) } } - if (true === $input->hasParameterOption(array('--quiet', '-q'))) { + if (true === $input->hasParameterOption(array('--quiet', '-q'), $input::OPTION_FLAG_POSIX)) { $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); $input->setInteractive(false); } else { - if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) { + if ($input->hasParameterOption('-vvv', $input::OPTION_FLAG_POSIX) || $input->hasParameterOption('--verbose=3', $input::OPTION_FLAG_POSIX) || $input->getParameterOption('--verbose', false, $input::OPTION_FLAG_POSIX) === 3) { $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); - } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) { + } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2', $input::OPTION_FLAG_POSIX) || $input->getParameterOption('--verbose', false, $input::OPTION_FLAG_POSIX) === 2) { $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); - } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) { + } elseif ($input->hasParameterOption('-v', $input::OPTION_FLAG_POSIX) || $input->hasParameterOption('--verbose=1', $input::OPTION_FLAG_POSIX) || $input->hasParameterOption('--verbose', $input::OPTION_FLAG_POSIX) || $input->getParameterOption('--verbose', false, $input::OPTION_FLAG_POSIX)) { $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); } } diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index 119be49170853..4488de8013083 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -275,11 +275,14 @@ public function getFirstArgument() /** * {@inheritdoc} */ - public function hasParameterOption($values) + public function hasParameterOption($values, $flags = InputInterface::OPTION_FLAG_DEFAULT) { $values = (array) $values; foreach ($this->tokens as $token) { + if ($this->isEndOfOptions($token, $flags)) { + break; + } foreach ($values as $value) { if ($token === $value || 0 === strpos($token, $value.'=')) { return true; @@ -293,14 +296,16 @@ public function hasParameterOption($values) /** * {@inheritdoc} */ - public function getParameterOption($values, $default = false) + public function getParameterOption($values, $default = false, $flags = InputInterface::OPTION_FLAG_DEFAULT) { $values = (array) $values; $tokens = $this->tokens; while (0 < count($tokens)) { $token = array_shift($tokens); - + if ($this->isEndOfOptions($token, $flags)) { + break; + } foreach ($values as $value) { if ($token === $value || 0 === strpos($token, $value.'=')) { if (false !== $pos = strpos($token, '=')) { @@ -315,6 +320,23 @@ public function getParameterOption($values, $default = false) return $default; } + /** + * private helper method to detect end of options in command-line arguments, used + * to assist with a more POSIX compatible parsing of arguments. + * + * @param string $token + * @param int $flags + * + * @return bool + */ + private function isEndOfOptions($token, $flags = InputInterface::OPTION_FLAG_DEFAULT) + { + return + $flags & InputInterface::OPTION_FLAG_POSIX + && InputInterface::POSIX_OPTIONS_END === $token + ; + } + /** * Returns a stringified representation of the args passed to the command. * diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php index e9d4f8e842a9f..c70304fa91e04 100644 --- a/src/Symfony/Component/Console/Input/ArrayInput.php +++ b/src/Symfony/Component/Console/Input/ArrayInput.php @@ -54,7 +54,7 @@ public function getFirstArgument() /** * {@inheritdoc} */ - public function hasParameterOption($values) + public function hasParameterOption($values, $flags = InputInterface::OPTION_FLAG_DEFAULT) { $values = (array) $values; @@ -63,6 +63,10 @@ public function hasParameterOption($values) $v = $k; } + if ($this->isEndOfOptions($v, $flags)) { + break; + } + if (in_array($v, $values)) { return true; } @@ -74,11 +78,14 @@ public function hasParameterOption($values) /** * {@inheritdoc} */ - public function getParameterOption($values, $default = false) + public function getParameterOption($values, $default = false, $flags = InputInterface::OPTION_FLAG_DEFAULT) { $values = (array) $values; foreach ($this->parameters as $k => $v) { + if ($this->isEndOfOptions(is_int($k) ? $v : $k, $flags)) { + break; + } if (is_int($k)) { if (in_array($v, $values)) { return true; @@ -91,6 +98,23 @@ public function getParameterOption($values, $default = false) return $default; } + /** + * private helper method to detect end of options in command-line arguments, used + * to assist with a more POSIX compatible parsing of arguments. + * + * @param string $token + * @param int $flags + * + * @return bool + */ + private function isEndOfOptions($token, $flags = InputInterface::OPTION_FLAG_DEFAULT) + { + return + $flags & InputInterface::OPTION_FLAG_POSIX + && InputInterface::POSIX_OPTIONS_END === $token + ; + } + /** * Returns a stringified representation of the args passed to the command. * diff --git a/src/Symfony/Component/Console/Input/InputInterface.php b/src/Symfony/Component/Console/Input/InputInterface.php index 5ba1604048322..a8a548b6e1667 100644 --- a/src/Symfony/Component/Console/Input/InputInterface.php +++ b/src/Symfony/Component/Console/Input/InputInterface.php @@ -18,6 +18,13 @@ */ interface InputInterface { + /** + * @see hasParameterOption() + */ + const OPTION_FLAG_DEFAULT = 0; + const OPTION_FLAG_POSIX = 1; + const POSIX_OPTIONS_END = '--'; + /** * Returns the first argument from the raw parameters (not parsed). * @@ -32,10 +39,16 @@ public function getFirstArgument(); * before they have been validated. It must be used carefully. * * @param string|array $values The values to look for in the raw parameters (can be an array) + * @param int $flags Parse flags + * + * How far to look for options: + * + * OPTION_FLAG_DEFAULT: (default) scan all arguments incl. operands + * OPTION_FLAG_POSIX: Do not search for option(s) after POSIX_OPTIONS_END ("--") * * @return bool true if the value is contained in the raw parameters */ - public function hasParameterOption($values); + public function hasParameterOption($values, $flags = self::OPTION_FLAG_DEFAULT); /** * Returns the value of a raw option (not parsed). @@ -43,12 +56,15 @@ public function hasParameterOption($values); * This method is to be used to introspect the input parameters * before they have been validated. It must be used carefully. * + * @see hasParameterOption() for $flags + * * @param string|array $values The value(s) to look for in the raw parameters (can be an array) * @param mixed $default The default value to return if no result is found + * @param int $flags Parse flags * * @return mixed The option value */ - public function getParameterOption($values, $default = false); + public function getParameterOption($values, $default = false, $flags = self::OPTION_FLAG_DEFAULT); /** * Binds the current Input instance with the given arguments and options. diff --git a/src/Symfony/Component/Console/Tests/Input/ExtraInputsPosixOptionsTest.php b/src/Symfony/Component/Console/Tests/Input/ExtraInputsPosixOptionsTest.php new file mode 100644 index 0000000000000..2f68c3bd895d5 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Input/ExtraInputsPosixOptionsTest.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Input; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; + +/** + * Extra test-case to cover the introduction of $flags for InputInterface::hasParameterOption() + * and InputInterface::getParameterOption(). + */ +class ExtraInputsPosixOptionsTest extends TestCase +{ + public function testArrayInput() + { + $input = new ArrayInput(array('name' => 'Fabien', '--foo' => 'bar', '--', '--bar', '--baz' => 'foo')); + $this->hasParameterAssertions($input); + $this->getParameterAssertions($input); + } + + public function testArgvInput() + { + $input = new ArgvInput(array('Fabien', '--foo', 'bar', '--', '--bar', '--baz', 'foo')); + $this->hasParameterAssertions($input); + $this->getParameterAssertions($input); + } + + private function hasParameterAssertions(InputInterface $input) + { + $this->assertInputHasParameterOption($input, '--foo', '--foo always exists'); + $this->assertInputNeverHasParameterOption($input, '--zzz', '--zzz never exists'); + $this->assertInputHasParameterOption( + $input, + array('--zzz', '--foo'), + '--foo is found with --zzz that never exists' + ); + $this->assertInputHasOnlyNotParameterOption($input, '--bar', '--bar is not found'); + $this->assertInputHasParameterOption($input, array('--bar', '--foo'), '--foo is found even --bar is not found'); + $this->assertInputHasOnlyNotParameterOption($input, '--baz'); + + $this->assertTrue($input->hasParameterOption('--bar'), 'Default behaviour'); + $this->assertFalse($input->hasParameterOption('--bar', $input::OPTION_FLAG_POSIX), 'Posix flag'); + + $this->assertFalse($input->hasParameterOption(array('--bar'), $input::OPTION_FLAG_POSIX), 'Posix flag'); + $this->assertFalse( + $input->hasParameterOption(array('--bar', '--baz'), $input::OPTION_FLAG_POSIX), + 'Posix flag' + ); + $this->assertTrue( + $input->hasParameterOption(array('--bar', '--baz', '--foo'), $input::OPTION_FLAG_POSIX), + 'Posix flag' + ); + } + + /** + * Assert that regardless of flags, input never has an option. + * + * @param InputInterface $input + * @param $values + * @param null $message + */ + private function assertInputNeverHasParameterOption(InputInterface $input, $values, $message = null) + { + if (strlen($message)) { + $message = " ($message)"; + } + + $this->assertFalse($input->hasParameterOption($values), "default flag $message"); + $this->assertFalse($input->hasParameterOption($values, $input::OPTION_FLAG_POSIX), "posix flag $message"); + } + + /** + * Assert that regardless of the flag the values are available. + * + * @param InputInterface $input + * @param $values + * @param null $message + */ + private function assertInputHasParameterOption(InputInterface $input, $values, $message = null) + { + if (strlen($message)) { + $message = " ($message)"; + } + + $this->assertTrue($input->hasParameterOption($values), "default flag $message"); + $this->assertTrue($input->hasParameterOption($values, $input::OPTION_FLAG_POSIX), "posix flag $message"); + } + + /** + * Assert that with POSIX flag the values are not available, but are available by default. + * + * @param InputInterface $input + * @param $values + * @param null $message + */ + private function assertInputHasOnlyNotParameterOption(InputInterface $input, $values, $message = null) + { + if (strlen($message)) { + $message = " ($message)"; + } + + $this->assertTrue($input->hasParameterOption($values), "default flag $message"); + $this->assertFalse($input->hasParameterOption($values, $input::OPTION_FLAG_POSIX), "posix flag $message"); + } + + /** + * @param $input + */ + private function getParameterAssertions(InputInterface $input) + { + $this->assertEquals('bar', $input->getParameterOption('--foo')); + $this->assertSame('bar', $input->getParameterOption('--foo', false, $input::OPTION_FLAG_POSIX)); + + $this->assertEquals('foo', $input->getParameterOption('--baz')); + $this->assertSame(false, $input->getParameterOption('--baz', false, $input::OPTION_FLAG_POSIX)); + } +}