From 9a16a1cb519da4c7fc4333aad490149c229373cd Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 5 May 2023 12:56:46 +0200 Subject: [PATCH 1/4] Remove usage of constant for better consistency across the codebase --- Command/CompleteCommand.php | 4 ++-- Command/DumpCompletionCommand.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Command/CompleteCommand.php b/Command/CompleteCommand.php index 11ada4e44..0e35143c3 100644 --- a/Command/CompleteCommand.php +++ b/Command/CompleteCommand.php @@ -155,10 +155,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int throw $e; } - return self::FAILURE; + return 2; } - return self::SUCCESS; + return 0; } private function createCompletionInput(InputInterface $input): CompletionInput diff --git a/Command/DumpCompletionCommand.php b/Command/DumpCompletionCommand.php index 6f809e2f1..eaf22be1a 100644 --- a/Command/DumpCompletionCommand.php +++ b/Command/DumpCompletionCommand.php @@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($input->getOption('debug')) { $this->tailDebugLog($commandName, $output); - return self::SUCCESS; + return 0; } $shell = $input->getArgument('shell') ?? self::guessShell(); @@ -102,12 +102,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } - return self::INVALID; + return 2; } $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], file_get_contents($completionFile))); - return self::SUCCESS; + return 0; } private static function guessShell(): string From a349882cfb8bd8a34c294d0dc2390efedbd77f4c Mon Sep 17 00:00:00 2001 From: Maximilian Beckers Date: Fri, 19 May 2023 11:40:46 +0200 Subject: [PATCH 2/4] [Console] Remove exec and replace it by shell_exec --- Helper/QuestionHelper.php | 6 ++---- Terminal.php | 8 +++----- Tests/Helper/QuestionHelperTest.php | 4 ++-- Tests/TerminalTest.php | 4 ++-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index 10602038c..ec5b418f2 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -500,13 +500,11 @@ private function isInteractiveInput($inputStream): bool return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r')); } - if (!\function_exists('exec')) { + if (!\function_exists('shell_exec')) { return self::$stdinIsInteractive = true; } - exec('stty 2> /dev/null', $output, $status); - - return self::$stdinIsInteractive = 1 !== $status; + return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } /** diff --git a/Terminal.php b/Terminal.php index 04653d3bd..b91e8afc5 100644 --- a/Terminal.php +++ b/Terminal.php @@ -64,14 +64,12 @@ public static function hasSttyAvailable(): bool return self::$stty; } - // skip check if exec function is disabled - if (!\function_exists('exec')) { + // skip check if shell_exec function is disabled + if (!\function_exists('shell_exec')) { return false; } - exec('stty 2>&1', $output, $exitcode); - - return self::$stty = 0 === $exitcode; + return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); } private static function initDimensions() diff --git a/Tests/Helper/QuestionHelperTest.php b/Tests/Helper/QuestionHelperTest.php index 9761e8f97..74315d898 100644 --- a/Tests/Helper/QuestionHelperTest.php +++ b/Tests/Helper/QuestionHelperTest.php @@ -430,7 +430,7 @@ public function testAskHiddenResponse() $this->assertEquals('8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("8AM\n")), $this->createOutputInterface(), $question)); } - public function testAskHiddenResponseTrimmed() + public function testAskHiddenResponseNotTrimmed() { if ('\\' === \DIRECTORY_SEPARATOR) { $this->markTestSkipped('This test is not supported on Windows'); @@ -442,7 +442,7 @@ public function testAskHiddenResponseTrimmed() $question->setHidden(true); $question->setTrimmable(false); - $this->assertEquals(' 8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream(' 8AM')), $this->createOutputInterface(), $question)); + $this->assertEquals(' 8AM'.\PHP_EOL, $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream(' 8AM'.\PHP_EOL)), $this->createOutputInterface(), $question)); } public function testAskMultilineResponseWithEOF() diff --git a/Tests/TerminalTest.php b/Tests/TerminalTest.php index c2d36fe0a..34d32b08e 100644 --- a/Tests/TerminalTest.php +++ b/Tests/TerminalTest.php @@ -77,8 +77,8 @@ public function testSttyOnWindows() $this->markTestSkipped('Must be on windows'); } - $sttyString = exec('(stty -a | grep columns) 2>&1', $output, $exitcode); - if (0 !== $exitcode) { + $sttyString = shell_exec('(stty -a | grep columns) 2> NUL'); + if (!$sttyString) { $this->markTestSkipped('Must have stty support'); } From 875ffc84207b3683888b8a89351f32bc26dc7b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 24 May 2023 17:11:52 +0200 Subject: [PATCH 3/4] [Console] Fix PHP Doc of InputArgument --- Input/InputArgument.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Input/InputArgument.php b/Input/InputArgument.php index ecfcdad58..8a64f7ac8 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -32,7 +32,7 @@ class InputArgument /** * @param string $name The argument name - * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY * @param string $description A description text * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * From 47ec02ae2fb766ccebd3771f386b072a7a50f4d4 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Thu, 25 May 2023 14:34:50 +0200 Subject: [PATCH 4/4] [Console] block input stream if needed When the input stream used in the question helper is not blocking, the default value is always used as the stream return false. In order to fix that, we force the stream to be in blocking state and go back to the old state after so other logic is not impacted by this change --- Helper/QuestionHelper.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index ec5b418f2..e236be92a 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -128,7 +128,18 @@ private function doAsk(OutputInterface $output, Question $question) } if (false === $ret) { + $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true; + + if (!$isBlocked) { + stream_set_blocking($inputStream, true); + } + $ret = $this->readInput($inputStream, $question); + + if (!$isBlocked) { + stream_set_blocking($inputStream, false); + } + if (false === $ret) { throw new MissingInputException('Aborted.'); }