From 30c8b21479da13820a54b21ce99e46b3be0e4e0e Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Tue, 15 Jan 2019 17:43:35 +0200 Subject: [PATCH 1/9] Properly handle VALUE_NONE options --- src/Console/Input/Option.php | 17 +++++++++++++---- src/Executor/ParallelExecutor.php | 5 +++-- test/src/Console/Input/OptionTest.php | 15 +++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/Console/Input/Option.php b/src/Console/Input/Option.php index 4d58720d2..c8c75df30 100644 --- a/src/Console/Input/Option.php +++ b/src/Console/Input/Option.php @@ -12,6 +12,12 @@ final class Option { + /** + * @param InputInterface $input + * @param InputOption $option + * + * @return string + */ public static function toString( InputInterface $input, InputOption $option @@ -19,10 +25,9 @@ public static function toString( $name = $option->getName(); if (!$option->acceptValue()) { - return \sprintf( - '--%s', - $name - ); + return true === $input->getOption($name) + ? \sprintf('--%s', $name) + : ''; } if (!$option->isArray()) { @@ -53,7 +58,11 @@ public static function toString( } /** + * @param InputOption $option + * @param string $name * @param null|string $value + * + * @return string */ private static function generatePartialOption( InputOption $option, diff --git a/src/Executor/ParallelExecutor.php b/src/Executor/ParallelExecutor.php index b34307989..5442f598f 100644 --- a/src/Executor/ParallelExecutor.php +++ b/src/Executor/ParallelExecutor.php @@ -20,7 +20,6 @@ use Deployer\Task\Context; use Deployer\Task\Task; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; @@ -269,7 +268,9 @@ private function generateOptions(): string $inputs[] = Option::toString($this->input, $option); } - return implode(' ', $inputs); + return implode(' ', array_filter($inputs, function (string $item) { + return $item !== ''; + })); } private function generateArguments(): string diff --git a/test/src/Console/Input/OptionTest.php b/test/src/Console/Input/OptionTest.php index 1909c2972..6044e0e3b 100644 --- a/test/src/Console/Input/OptionTest.php +++ b/test/src/Console/Input/OptionTest.php @@ -17,13 +17,16 @@ public function toStringProvider(): \Generator { // InputOption::VALUE_NONE foreach ([ - ['--fooBar', 'fooBar'], - ['--0', '0'], - ['--1', '1'], - ['--foo\-%&Bar', 'foo\-%&Bar'], - ['--ù+ì', 'ù+ì'], - ] as list($expectedValue, $optionName)) { + ['--fooBar', 'fooBar', true], + ['--0', '0', true], + ['--1', '1', true], + ['--foo\-%&Bar', 'foo\-%&Bar', true], + ['--ù+ì', 'ù+ì', true], + ] as list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); + $input->expects($this->once()) + ->method('getOption') + ->willReturn($optionValue); $option = $this->createMock(InputOption::class); $option->expects($this->once()) From c312597e69bf1df0b70566277cf09e9b2c1e32da Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Tue, 15 Jan 2019 18:50:33 +0200 Subject: [PATCH 2/9] Add test-case for unset VALUE_NONE option --- test/src/Console/Input/OptionTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/src/Console/Input/OptionTest.php b/test/src/Console/Input/OptionTest.php index 6044e0e3b..db093a871 100644 --- a/test/src/Console/Input/OptionTest.php +++ b/test/src/Console/Input/OptionTest.php @@ -1,4 +1,6 @@ - * * For the full copyright and license information, please view the LICENSE @@ -22,6 +24,7 @@ public function toStringProvider(): \Generator ['--1', '1', true], ['--foo\-%&Bar', 'foo\-%&Bar', true], ['--ù+ì', 'ù+ì', true], + ['', 'value-none-unset', false], ] as list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) @@ -199,8 +202,6 @@ public function toStringProvider(): \Generator /** * @dataProvider toStringProvider - * - * @return void */ public function testToString( string $expectedValue, From 0575c6e53537e72ef583e855b82c1f8cacfc5cff Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 11:52:20 +0200 Subject: [PATCH 3/9] Fix null and empty string handling --- src/Console/Input/Option.php | 56 ++++----------------------- src/Executor/ParallelExecutor.php | 2 +- test/src/Console/Input/OptionTest.php | 2 + 3 files changed, 10 insertions(+), 50 deletions(-) diff --git a/src/Console/Input/Option.php b/src/Console/Input/Option.php index c8c75df30..d8905d45a 100644 --- a/src/Console/Input/Option.php +++ b/src/Console/Input/Option.php @@ -12,78 +12,36 @@ final class Option { - /** - * @param InputInterface $input - * @param InputOption $option - * - * @return string - */ public static function toString( InputInterface $input, InputOption $option ): string { $name = $option->getName(); + $values = $input->getOption($name); if (!$option->acceptValue()) { - return true === $input->getOption($name) + return true === $values ? \sprintf('--%s', $name) : ''; } if (!$option->isArray()) { - return self::generatePartialOption( - $option, - $name, - $input->getOption($name) - ); + $values = [$values]; } /** @var string[] $outputs */ $outputs = []; - foreach ($input->getOption($name) as $value) { - $value = self::generatePartialOption( - $option, + foreach ($values as $value) { + $value = sprintf( + '--%s%s%s', $name, + \null === $value ? '' : '=', $value ); - if ($value === '') { - continue; - } - $outputs[] = $value; } return \implode(' ', $outputs); } - - /** - * @param InputOption $option - * @param string $name - * @param null|string $value - * - * @return string - */ - private static function generatePartialOption( - InputOption $option, - string $name, - $value - ): string { - if (\null !== $value && \strlen($value) !== 0) { - return \sprintf( - '--%s=%s', - $name, - $value - ); - } - - if ($option->isValueOptional()) { - return \sprintf( - '--%s', - $name - ); - } - - return ''; - } } diff --git a/src/Executor/ParallelExecutor.php b/src/Executor/ParallelExecutor.php index 5442f598f..8033a9646 100644 --- a/src/Executor/ParallelExecutor.php +++ b/src/Executor/ParallelExecutor.php @@ -268,7 +268,7 @@ private function generateOptions(): string $inputs[] = Option::toString($this->input, $option); } - return implode(' ', array_filter($inputs, function (string $item) { + return implode(' ', array_filter($inputs, function (string $item): bool { return $item !== ''; })); } diff --git a/test/src/Console/Input/OptionTest.php b/test/src/Console/Input/OptionTest.php index db093a871..28c547edd 100644 --- a/test/src/Console/Input/OptionTest.php +++ b/test/src/Console/Input/OptionTest.php @@ -202,6 +202,8 @@ public function toStringProvider(): \Generator /** * @dataProvider toStringProvider + * + * @return void */ public function testToString( string $expectedValue, From efb027cc147bb377367dcb48e9b264c78e38b5ba Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 12:42:48 +0200 Subject: [PATCH 4/9] Better handle value-required options --- src/Console/Input/Option.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Console/Input/Option.php b/src/Console/Input/Option.php index d8905d45a..512cd8714 100644 --- a/src/Console/Input/Option.php +++ b/src/Console/Input/Option.php @@ -29,9 +29,13 @@ public static function toString( $values = [$values]; } + $isValueRequired = $option->isValueRequired(); /** @var string[] $outputs */ $outputs = []; foreach ($values as $value) { + if ((\null === $value || '' === $value) && $isValueRequired) { + continue; + } $value = sprintf( '--%s%s%s', $name, From 8ce9f92229c6a78e955673b01621b2b23d97e826 Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 12:43:46 +0200 Subject: [PATCH 5/9] Add test-case names for easier issue finding --- test/src/Console/Input/OptionTest.php | 100 +++++++++++++------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/test/src/Console/Input/OptionTest.php b/test/src/Console/Input/OptionTest.php index 28c547edd..945c6f6c2 100644 --- a/test/src/Console/Input/OptionTest.php +++ b/test/src/Console/Input/OptionTest.php @@ -1,6 +1,4 @@ - * * For the full copyright and license information, please view the LICENSE @@ -19,13 +17,13 @@ public function toStringProvider(): \Generator { // InputOption::VALUE_NONE foreach ([ - ['--fooBar', 'fooBar', true], - ['--0', '0', true], - ['--1', '1', true], - ['--foo\-%&Bar', 'foo\-%&Bar', true], - ['--ù+ì', 'ù+ì', true], - ['', 'value-none-unset', false], - ] as list($expectedValue, $optionName, $optionValue)) { + 'VALUE_NONE 1' => ['--fooBar', 'fooBar', true], + 'VALUE_NONE 2' => ['--0', '0', true], + 'VALUE_NONE 3' => ['--1', '1', true], + 'VALUE_NONE 4' => ['--foo\-%&Bar', 'foo\-%&Bar', true], + 'VALUE_NONE 5' => ['--ù+ì', 'ù+ì', true], + 'VALUE_NONE 6' => ['', 'value-none-unset', false], + ] as $key => list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) ->method('getOption') @@ -40,7 +38,7 @@ public function toStringProvider(): \Generator ->method('acceptValue') ->willReturn(\false); - yield [ + yield $key => [ $expectedValue, $input, $option, @@ -49,13 +47,13 @@ public function toStringProvider(): \Generator // InputOption::VALUE_REQUIRED foreach ([ - ['--fooBar=ciao', 'fooBar', 'ciao'], - ['', 'fooBar', \null], - ['', 'fooBar', ''], - ['--fooBar=0', 'fooBar', '0'], - ['--foo\-%&Bar=test', 'foo\-%&Bar', 'test'], - ['--ù+ì=omg', 'ù+ì', 'omg'], - ] as list($expectedValue, $optionName, $optionValue)) { + 'VALUE_REQUIRED 1' => ['--fooBar=ciao', 'fooBar', 'ciao'], + 'VALUE_REQUIRED 2' => ['', 'fooBar', \null], + 'VALUE_REQUIRED 3' => ['', 'fooBar', ''], + 'VALUE_REQUIRED 4' => ['--fooBar=0', 'fooBar', '0'], + 'VALUE_REQUIRED 5' => ['--foo\-%&Bar=test', 'foo\-%&Bar', 'test'], + 'VALUE_REQUIRED 6' => ['--ù+ì=omg', 'ù+ì', 'omg'], + ] as $key => list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) ->method('getOption') @@ -75,10 +73,10 @@ public function toStringProvider(): \Generator ->willReturn(\false); $option->expects($this->any()) - ->method('isValueOptional') - ->willReturn(\false); + ->method('isValueRequired') + ->willReturn(\true); - yield [ + yield $key => [ $expectedValue, $input, $option, @@ -87,13 +85,13 @@ public function toStringProvider(): \Generator // InputOption::VALUE_OPTIONAL foreach ([ - ['--fooBar=ciao', 'fooBar', 'ciao'], - ['--fooBar', 'fooBar', \null], - ['--fooBar', 'fooBar', ''], - ['--fooBar=0', 'fooBar', '0'], - ['--foo\-%&Bar=test', 'foo\-%&Bar', 'test'], - ['--ù+ì=omg', 'ù+ì', 'omg'], - ] as list($expectedValue, $optionName, $optionValue)) { + 'VALUE_OPTIONAL 1' => ['--fooBar=ciao', 'fooBar', 'ciao'], + 'VALUE_OPTIONAL 2' => ['--fooBar', 'fooBar', \null], + 'VALUE_OPTIONAL 3' => ['--fooBar=', 'fooBar', ''], + 'VALUE_OPTIONAL 4' => ['--fooBar=0', 'fooBar', '0'], + 'VALUE_OPTIONAL 5' => ['--foo\-%&Bar=test', 'foo\-%&Bar', 'test'], + 'VALUE_OPTIONAL 6' => ['--ù+ì=omg', 'ù+ì', 'omg'], + ] as $key => list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) ->method('getOption') @@ -113,10 +111,10 @@ public function toStringProvider(): \Generator ->willReturn(\false); $option->expects($this->any()) - ->method('isValueOptional') - ->willReturn(\true); + ->method('isValueRequired') + ->willReturn(\false); - yield [ + yield $key => [ $expectedValue, $input, $option, @@ -125,13 +123,13 @@ public function toStringProvider(): \Generator // InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY foreach ([ - ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', 'Привет']], - ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', \null, 'Привет']], - ['', 'fooBar', [\null, '']], - ['', 'fooBar', [\null]], - ['', 'fooBar', ['']], - ['--fooBar=0 --fooBar=1 --fooBar=2 --fooBar=...', 'fooBar', ['0', '1', '2', '...']], - ] as list($expectedValue, $optionName, $optionValue)) { + 'VALUE_ARRAY_REQUIRED 1' => ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', 'Привет']], + 'VALUE_ARRAY_REQUIRED 2' => ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', \null, 'Привет']], + 'VALUE_ARRAY_REQUIRED 3' => ['', 'fooBar', [\null, '']], + 'VALUE_ARRAY_REQUIRED 4' => ['', 'fooBar', [\null]], + 'VALUE_ARRAY_REQUIRED 5' => ['', 'fooBar', ['']], + 'VALUE_ARRAY_REQUIRED 6' => ['--fooBar=0 --fooBar=1 --fooBar=2 --fooBar=...', 'fooBar', ['0', '1', '2', '...']], + ] as $key => list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) ->method('getOption') @@ -151,10 +149,10 @@ public function toStringProvider(): \Generator ->willReturn(\true); $option->expects($this->any()) - ->method('isValueOptional') - ->willReturn(\false); + ->method('isValueRequired') + ->willReturn(\true); - yield [ + yield $key => [ $expectedValue, $input, $option, @@ -163,13 +161,13 @@ public function toStringProvider(): \Generator // InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY foreach ([ - ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', 'Привет']], - ['--fooBar=ciao --fooBar --fooBar=Привет', 'fooBar', ['ciao', \null, 'Привет']], - ['--fooBar --fooBar', 'fooBar', [\null, '']], - ['--fooBar', 'fooBar', [\null]], - ['--fooBar', 'fooBar', ['']], - ['--fooBar=0 --fooBar=1 --fooBar=2 --fooBar=...', 'fooBar', ['0', '1', '2', '...']], - ] as list($expectedValue, $optionName, $optionValue)) { + 'VALUE_ARRAY_OPTIONAL 1' => ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', 'Привет']], + 'VALUE_ARRAY_OPTIONAL 2' => ['--fooBar=ciao --fooBar --fooBar=Привет', 'fooBar', ['ciao', \null, 'Привет']], + 'VALUE_ARRAY_OPTIONAL 3' => ['--fooBar --fooBar=', 'fooBar', [\null, '']], + 'VALUE_ARRAY_OPTIONAL 4' => ['--fooBar', 'fooBar', [\null]], + 'VALUE_ARRAY_OPTIONAL 5' => ['--fooBar=', 'fooBar', ['']], + 'VALUE_ARRAY_OPTIONAL 6' => ['--fooBar=0 --fooBar=1 --fooBar=2 --fooBar=...', 'fooBar', ['0', '1', '2', '...']], + ] as $key => list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) ->method('getOption') @@ -189,10 +187,10 @@ public function toStringProvider(): \Generator ->willReturn(\true); $option->expects($this->any()) - ->method('isValueOptional') - ->willReturn(\true); + ->method('isValueRequired') + ->willReturn(\false); - yield [ + yield $key => [ $expectedValue, $input, $option, From 3a8e6013f0c19c9ca7813db8199effd760d13ed1 Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 13:45:20 +0200 Subject: [PATCH 6/9] Properly handle empty string values --- src/Console/Input/Option.php | 2 +- test/src/Console/Input/OptionTest.php | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Console/Input/Option.php b/src/Console/Input/Option.php index 512cd8714..69d33d0a7 100644 --- a/src/Console/Input/Option.php +++ b/src/Console/Input/Option.php @@ -33,7 +33,7 @@ public static function toString( /** @var string[] $outputs */ $outputs = []; foreach ($values as $value) { - if ((\null === $value || '' === $value) && $isValueRequired) { + if ($isValueRequired && \null === $value) { continue; } $value = sprintf( diff --git a/test/src/Console/Input/OptionTest.php b/test/src/Console/Input/OptionTest.php index 945c6f6c2..1c7c91059 100644 --- a/test/src/Console/Input/OptionTest.php +++ b/test/src/Console/Input/OptionTest.php @@ -49,7 +49,7 @@ public function toStringProvider(): \Generator foreach ([ 'VALUE_REQUIRED 1' => ['--fooBar=ciao', 'fooBar', 'ciao'], 'VALUE_REQUIRED 2' => ['', 'fooBar', \null], - 'VALUE_REQUIRED 3' => ['', 'fooBar', ''], + 'VALUE_REQUIRED 3' => ['--fooBar=', 'fooBar', ''], 'VALUE_REQUIRED 4' => ['--fooBar=0', 'fooBar', '0'], 'VALUE_REQUIRED 5' => ['--foo\-%&Bar=test', 'foo\-%&Bar', 'test'], 'VALUE_REQUIRED 6' => ['--ù+ì=omg', 'ù+ì', 'omg'], @@ -125,10 +125,11 @@ public function toStringProvider(): \Generator foreach ([ 'VALUE_ARRAY_REQUIRED 1' => ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', 'Привет']], 'VALUE_ARRAY_REQUIRED 2' => ['--fooBar=ciao --fooBar=Привет', 'fooBar', ['ciao', \null, 'Привет']], - 'VALUE_ARRAY_REQUIRED 3' => ['', 'fooBar', [\null, '']], + 'VALUE_ARRAY_REQUIRED 3' => ['--fooBar=', 'fooBar', [\null, '']], 'VALUE_ARRAY_REQUIRED 4' => ['', 'fooBar', [\null]], - 'VALUE_ARRAY_REQUIRED 5' => ['', 'fooBar', ['']], + 'VALUE_ARRAY_REQUIRED 5' => ['--fooBar=', 'fooBar', ['']], 'VALUE_ARRAY_REQUIRED 6' => ['--fooBar=0 --fooBar=1 --fooBar=2 --fooBar=...', 'fooBar', ['0', '1', '2', '...']], + 'VALUE_ARRAY_REQUIRED 7' => ['--fooBar=ciao --fooBar= --fooBar=Привет', 'fooBar', ['ciao', '', 'Привет']], ] as $key => list($expectedValue, $optionName, $optionValue)) { $input = $this->createMock(InputInterface::class); $input->expects($this->once()) From dc824d8ea6848a6a502b8c700eb1ea036e635d68 Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 13:51:06 +0200 Subject: [PATCH 7/9] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 393a0ba7a..8434d5aae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog +## master +[v6.4.2...master](https://github.com/deployphp/deployer/compare/v6.4.2...master) + +### Fixed +- Input option handling [#1793] + + ## v6.4.2 [v6.4.1...v6.4.2](https://github.com/deployphp/deployer/compare/v6.4.1...v6.4.2) @@ -442,6 +449,7 @@ - Fixed remove of shared dir on first deploy +[#1793]: https://github.com/deployphp/deployer/pull/1793 [#1792]: https://github.com/deployphp/deployer/pull/1792 [#1790]: https://github.com/deployphp/deployer/pull/1790 [#1778]: https://github.com/deployphp/deployer/issues/1778 From 5c80e83862819cbec92c756861f4c64de023034f Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 14:14:31 +0200 Subject: [PATCH 8/9] Minor test expectation improvement --- test/src/Console/Input/OptionTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/Console/Input/OptionTest.php b/test/src/Console/Input/OptionTest.php index 1c7c91059..e43691d98 100644 --- a/test/src/Console/Input/OptionTest.php +++ b/test/src/Console/Input/OptionTest.php @@ -72,7 +72,7 @@ public function toStringProvider(): \Generator ->method('isArray') ->willReturn(\false); - $option->expects($this->any()) + $option->expects($this->once()) ->method('isValueRequired') ->willReturn(\true); @@ -110,7 +110,7 @@ public function toStringProvider(): \Generator ->method('isArray') ->willReturn(\false); - $option->expects($this->any()) + $option->expects($this->once()) ->method('isValueRequired') ->willReturn(\false); @@ -149,7 +149,7 @@ public function toStringProvider(): \Generator ->method('isArray') ->willReturn(\true); - $option->expects($this->any()) + $option->expects($this->once()) ->method('isValueRequired') ->willReturn(\true); @@ -187,7 +187,7 @@ public function toStringProvider(): \Generator ->method('isArray') ->willReturn(\true); - $option->expects($this->any()) + $option->expects($this->once()) ->method('isValueRequired') ->willReturn(\false); From 8df53f782831f7c0df01eb14ad85ad47a27d5d01 Mon Sep 17 00:00:00 2001 From: Tomas Kmieliauskas Date: Wed, 16 Jan 2019 15:03:33 +0200 Subject: [PATCH 9/9] Make the input filtering anonymous function static --- src/Executor/ParallelExecutor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Executor/ParallelExecutor.php b/src/Executor/ParallelExecutor.php index 8033a9646..a64b025f9 100644 --- a/src/Executor/ParallelExecutor.php +++ b/src/Executor/ParallelExecutor.php @@ -268,7 +268,7 @@ private function generateOptions(): string $inputs[] = Option::toString($this->input, $option); } - return implode(' ', array_filter($inputs, function (string $item): bool { + return implode(' ', array_filter($inputs, static function (string $item): bool { return $item !== ''; })); }