From 006c3de54289c3703ca7ae397f824c48bf9a8660 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 31 Jan 2020 16:33:34 +0100 Subject: [PATCH] Fix tests and make TTY usage on ProcessExecutor cleaner --- .../EventDispatcher/EventDispatcher.php | 13 ++++++-- src/Composer/Util/ProcessExecutor.php | 32 +++++++++++++++++-- .../EventDispatcher/EventDispatcherTest.php | 4 +++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php index efd05d22c..b2ecdf023 100644 --- a/src/Composer/EventDispatcher/EventDispatcher.php +++ b/src/Composer/EventDispatcher/EventDispatcher.php @@ -174,7 +174,7 @@ class EventDispatcher $flags = $event->getFlags(); if (substr($callable, 0, 10) === '@composer ') { $exec = $this->getPhpExecCommand() . ' ' . ProcessExecutor::escape(getenv('COMPOSER_BINARY')) . ' ' . implode(' ', $args); - if (0 !== ($exitCode = $this->process->execute($exec, $ignoredOutput, null, $this->io->isInteractive()))) { + if (0 !== ($exitCode = $this->executeTty($exec))) { $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName()), true, IOInterface::QUIET); throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode); @@ -248,7 +248,7 @@ class EventDispatcher } } - if (0 !== ($exitCode = $this->process->execute($exec, $ignoredOutput, null, $this->io->isInteractive()))) { + if (0 !== ($exitCode = $this->executeTty($exec))) { $this->io->writeError(sprintf('Script %s handling the %s event returned with error code '.$exitCode.'', $callable, $event->getName()), true, IOInterface::QUIET); throw new ScriptExecutionException('Error Output: '.$this->process->getErrorOutput(), $exitCode); @@ -265,6 +265,15 @@ class EventDispatcher return $return; } + protected function executeTty($exec) + { + if ($this->io->isInteractive()) { + return $this->process->executeTty($exec); + } + + return $this->process->execute($exec); + } + protected function getPhpExecCommand() { $finder = new PhpExecutableFinder(); diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index 905d012e7..a30a04d15 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -15,6 +15,7 @@ namespace Composer\Util; use Composer\IO\IOInterface; use Symfony\Component\Process\Process; use Symfony\Component\Process\ProcessUtils; +use Symfony\Component\Process\Exception\RuntimeException; /** * @author Robert Schönthal @@ -41,7 +42,28 @@ class ProcessExecutor * @param string $cwd the working directory * @return int statuscode */ - public function execute($command, &$output = null, $cwd = null, $tty = false) + public function execute($command, &$output = null, $cwd = null) + { + if (func_num_args() > 1) { + return $this->doExecute($command, $cwd, false, $output); + } + + return $this->doExecute($command, $cwd, false); + } + + /** + * runs a process on the commandline in TTY mode + * + * @param string $command the command to execute + * @param string $cwd the working directory + * @return int statuscode + */ + public function executeTty($command, $cwd = null) + { + return $this->doExecute($command, $cwd, true); + } + + private function doExecute($command, $cwd, $tty, &$output = null) { if ($this->io && $this->io->isDebug()) { $safeCommand = preg_replace_callback('{://(?P[^:/\s]+):(?P[^@\s/]+)@}i', function ($m) { @@ -61,7 +83,7 @@ class ProcessExecutor $cwd = realpath(getcwd()); } - $this->captureOutput = func_num_args() > 1; + $this->captureOutput = func_num_args() > 3; $this->errorOutput = null; // TODO in v3, commands should be passed in as arrays of cmd + args @@ -71,7 +93,11 @@ class ProcessExecutor $process = new Process($command, $cwd, null, null, static::getTimeout()); } if (!Platform::isWindows() && $tty) { - $process->setTty(true); + try { + $process->setTty(true); + } catch (RuntimeException $e) { + // ignore TTY enabling errors + } } $callback = is_callable($output) ? $output : array($this, 'outputHandler'); diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php index 190d30f9d..1d6dcafe8 100644 --- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php +++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php @@ -538,6 +538,10 @@ class EventDispatcherTest extends TestCase ->willReturn('> exit 1'); $io->expects($this->at(2)) + ->method('isInteractive') + ->willReturn(1); + + $io->expects($this->at(3)) ->method('writeError') ->with($this->equalTo('Script '.$code.' handling the post-install-cmd event returned with error code 1'));