Browse Source

Merge pull request #3983 from alcohol/upgrade-dialoghelper

Upgrade DialogHelper to QuestionHelper
Jordi Boggiano 10 years ago
parent
commit
8a12e50a16

+ 0 - 36
src/Composer/Command/Helper/DialogHelper.php

@@ -1,36 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Command\Helper;
-
-use Symfony\Component\Console\Helper\DialogHelper as BaseDialogHelper;
-
-class DialogHelper extends BaseDialogHelper
-{
-    /**
-     * Build text for asking a question. For example:
-     *
-     *  "Do you want to continue [yes]:"
-     *
-     * @param string $question The question you want to ask
-     * @param mixed  $default  Default value to add to message, if false no default will be shown
-     * @param string $sep      Separation char for between message and user input
-     *
-     * @return string
-     */
-    public function getQuestion($question, $default = null, $sep = ':')
-    {
-        return $default !== null ?
-            sprintf('<info>%s</info> [<comment>%s</comment>]%s ', $question, $default, $sep) :
-            sprintf('<info>%s</info>%s ', $question, $sep);
-    }
-}

+ 81 - 68
src/Composer/Command/InitCommand.php

@@ -33,28 +33,18 @@ use Symfony\Component\Process\ExecutableFinder;
  */
 class InitCommand extends Command
 {
+    /** @var CompositeRepository */
     protected $repos;
 
+    /** @var array */
     private $gitConfig;
-    private $pool;
 
-    public function parseAuthorString($author)
-    {
-        if (preg_match('/^(?P<name>[- \.,\p{L}\p{N}\'’]+) <(?P<email>.+?)>$/u', $author, $match)) {
-            if ($this->isValidEmail($match['email'])) {
-                return array(
-                    'name'  => trim($match['name']),
-                    'email' => $match['email']
-                );
-            }
-        }
-
-        throw new \InvalidArgumentException(
-            'Invalid author string.  Must be in the format: '.
-            'John Smith <john@example.com>'
-        );
-    }
+    /** @var Pool */
+    private $pool;
 
+    /**
+     * {@inheritdoc}
+     */
     protected function configure()
     {
         $this
@@ -83,10 +73,11 @@ EOT
         ;
     }
 
+    /**
+     * {@inheritdoc}
+     */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $dialog = $this->getHelperSet()->get('dialog');
-
         $whitelist = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license');
 
         $options = array_filter(array_intersect_key($input->getOptions(), array_flip($whitelist)));
@@ -114,16 +105,11 @@ EOT
         }
 
         $file = new JsonFile('composer.json');
-
         $json = $file->encode($options);
 
         if ($input->isInteractive()) {
-            $this->getIO()->writeError(array(
-                '',
-                $json,
-                ''
-            ));
-            if (!$dialog->askConfirmation($output, $dialog->getQuestion('Do you confirm generation', 'yes', '?'), true)) {
+            $this->getIO()->writeError(array('', $json, ''));
+            if (!$this->getIO()->askConfirmation('Do you confirm generation [<comment>yes</comment>]? ', true)) {
                 $this->getIO()->writeError('<error>Command aborted</error>');
 
                 return 1;
@@ -140,21 +126,24 @@ EOT
             }
 
             if (!$this->hasVendorIgnore($ignoreFile)) {
-                $question = 'Would you like the <info>vendor</info> directory added to your <info>.gitignore</info> [<comment>yes</comment>]?';
+                $question = 'Would you like the <info>vendor</info> directory added to your <info>.gitignore</info> [<comment>yes</comment>]? ';
 
-                if ($dialog->askConfirmation($output, $question, true)) {
+                if ($this->getIO()->askConfirmation($question, true)) {
                     $this->addVendorIgnore($ignoreFile);
                 }
             }
         }
     }
 
+    /**
+     * {@inheritdoc}
+     */
     protected function interact(InputInterface $input, OutputInterface $output)
     {
         $git = $this->getGitConfig();
 
-        $dialog = $this->getHelperSet()->get('dialog');
         $formatter = $this->getHelperSet()->get('formatter');
+
         $this->getIO()->writeError(array(
             '',
             $formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
@@ -192,9 +181,8 @@ EOT
             }
         }
 
-        $name = $dialog->askAndValidate(
-            $output,
-            $dialog->getQuestion('Package name (<vendor>/<name>)', $name),
+        $name = $this->getIO()->askAndValidate(
+            'Package name (<vendor>/<name>) [<comment>'.$name.'</comment>]: ',
             function ($value) use ($name) {
                 if (null === $value) {
                     return $name;
@@ -207,14 +195,15 @@ EOT
                 }
 
                 return $value;
-            }
+            },
+            null,
+            $name
         );
         $input->setOption('name', $name);
 
         $description = $input->getOption('description') ?: false;
-        $description = $dialog->ask(
-            $output,
-            $dialog->getQuestion('Description', $description),
+        $description = $this->getIO()->ask(
+            'Description [<comment>'.$description.'</comment>]: ',
             $description
         );
         $input->setOption('description', $description);
@@ -226,22 +215,22 @@ EOT
         }
 
         $self = $this;
-        $author = $dialog->askAndValidate(
-            $output,
-            $dialog->getQuestion('Author', $author),
+        $author = $this->getIO()->askAndValidate(
+            'Author [<comment>'.$author.'</comment>]: ',
             function ($value) use ($self, $author) {
                 $value = $value ?: $author;
                 $author = $self->parseAuthorString($value);
 
                 return sprintf('%s <%s>', $author['name'], $author['email']);
-            }
+            },
+            null,
+            $author
         );
         $input->setOption('author', $author);
 
-        $minimumStability = $input->getOption('stability') ?: '';
-        $minimumStability = $dialog->askAndValidate(
-            $output,
-            $dialog->getQuestion('Minimum Stability', $minimumStability),
+        $minimumStability = $input->getOption('stability') ?: null;
+        $minimumStability = $this->getIO()->askAndValidate(
+            'Minimum Stability [<comment>'.$minimumStability.'</comment>]: ',
             function ($value) use ($self, $minimumStability) {
                 if (null === $value) {
                     return $minimumStability;
@@ -255,44 +244,65 @@ EOT
                 }
 
                 return $value;
-            }
+            },
+            null,
+            $minimumStability
         );
         $input->setOption('stability', $minimumStability);
 
         $type = $input->getOption('type') ?: false;
-        $type = $dialog->ask(
-            $output,
-            $dialog->getQuestion('Package Type', $type),
+        $type = $this->getIO()->ask(
+            'Package Type [<comment>'.$type.'</comment>]: ',
             $type
         );
         $input->setOption('type', $type);
 
         $license = $input->getOption('license') ?: false;
-        $license = $dialog->ask(
-            $output,
-            $dialog->getQuestion('License', $license),
+        $license = $this->getIO()->ask(
+            'License [<comment>'.$license.'</comment>]: ',
             $license
         );
         $input->setOption('license', $license);
 
-        $this->getIO()->writeError(array(
-            '',
-            'Define your dependencies.',
-            ''
-        ));
+        $this->getIO()->writeError(array('', 'Define your dependencies.', ''));
 
+        $question = 'Would you like to define your dependencies (require) interactively [<comment>yes</comment>]? ';
         $requirements = array();
-        if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dependencies (require) interactively', 'yes', '?'), true)) {
+        if ($this->getIO()->askConfirmation($question, true)) {
             $requirements = $this->determineRequirements($input, $output, $input->getOption('require'));
         }
         $input->setOption('require', $requirements);
+
+        $question = 'Would you like to define your dev dependencies (require-dev) interactively [<comment>yes</comment>]? ';
         $devRequirements = array();
-        if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dev dependencies (require-dev) interactively', 'yes', '?'), true)) {
+        if ($this->getIO()->askConfirmation($question, true)) {
             $devRequirements = $this->determineRequirements($input, $output, $input->getOption('require-dev'));
         }
         $input->setOption('require-dev', $devRequirements);
     }
 
+    /**
+     * @private
+     * @param string $author
+     * @return array
+     */
+    public function parseAuthorString($author)
+    {
+        if (preg_match('/^(?P<name>[- \.,\p{L}\p{N}\'’]+) <(?P<email>.+?)>$/u', $author, $match)) {
+            if ($this->isValidEmail($match['email'])) {
+                return array(
+                    'name'  => trim($match['name']),
+                    'email' => $match['email']
+                );
+            }
+        }
+
+        throw new \InvalidArgumentException(
+            'Invalid author string.  Must be in the format: '.
+            'John Smith <john@example.com>'
+        );
+    }
+
     protected function findPackages($name)
     {
         return $this->getRepos()->search($name);
@@ -312,9 +322,6 @@ EOT
 
     protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array())
     {
-        $dialog = $this->getHelperSet()->get('dialog');
-        $prompt = $dialog->getQuestion('Search for a package', false, ':');
-
         if ($requires) {
             $requires = $this->normalizeRequirements($requires);
             $result = array();
@@ -339,7 +346,7 @@ EOT
         }
 
         $versionParser = new VersionParser();
-        while (null !== $package = $dialog->ask($output, $prompt)) {
+        while (null !== $package = $this->getIO()->ask('Search for a package: ')) {
             $matches = $this->findPackages($package);
 
             if (count($matches)) {
@@ -392,7 +399,12 @@ EOT
                         throw new \Exception('Not a valid selection');
                     };
 
-                    $package = $dialog->askAndValidate($output, $dialog->getQuestion('Enter package # to add, or the complete package name if it is not listed', false, ':'), $validator, 3);
+                    $package = $this->getIO()->askAndValidate(
+                        'Enter package # to add, or the complete package name if it is not listed: ',
+                        $validator,
+                        3,
+                        false
+                    );
                 }
 
                 // no constraint yet, determine the best version automatically
@@ -403,12 +415,13 @@ EOT
                         return $input ?: false;
                     };
 
-                    $constraint = $dialog->askAndValidate(
-                        $output,
-                        $dialog->getQuestion('Enter the version constraint to require (or leave blank to use the latest version)', false, ':'),
+                    $constraint = $this->getIO()->askAndValidate(
+                        'Enter the version constraint to require (or leave blank to use the latest version): ',
                         $validator,
-                        3)
-                    ;
+                        3,
+                        false
+                    );
+
                     if (false === $constraint) {
                         $constraint = $this->findBestVersionForPackage($input, $package);
 

+ 1 - 2
src/Composer/Command/RemoveCommand.php

@@ -74,9 +74,8 @@ EOT
                 $json->removeLink($type, $package);
             } elseif (isset($composer[$altType][$package])) {
                 $this->getIO()->writeError('<warning>'.$package.' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
-                $dialog = $this->getHelperSet()->get('dialog');
                 if ($this->getIO()->isInteractive()) {
-                    if ($dialog->askConfirmation($output, $dialog->getQuestion('Do you want to remove it from '.$altType, 'yes', '?'), true)) {
+                    if ($this->getIO()->askConfirmation('Do you want to remove it from '.$altType.' [<comment>yes</comment>]? ', true)) {
                         $json->removeLink($altType, $package);
                     }
                 }

+ 0 - 12
src/Composer/Console/Application.php

@@ -20,7 +20,6 @@ use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Output\ConsoleOutput;
 use Symfony\Component\Console\Formatter\OutputFormatter;
 use Composer\Command;
-use Composer\Command\Helper\DialogHelper;
 use Composer\Composer;
 use Composer\Factory;
 use Composer\IO\IOInterface;
@@ -321,15 +320,4 @@ class Application extends BaseApplication
 
         return $definition;
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected function getDefaultHelperSet()
-    {
-        $helperSet = parent::getDefaultHelperSet();
-        $helperSet->set(new DialogHelper());
-
-        return $helperSet;
-    }
 }

+ 19 - 18
src/Composer/IO/ConsoleIO.php

@@ -16,6 +16,8 @@ use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\ConsoleOutputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Helper\HelperSet;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+use Symfony\Component\Console\Question\Question;
 use Symfony\Component\Process\ExecutableFinder;
 
 /**
@@ -81,7 +83,7 @@ class ConsoleIO extends BaseIO
      */
     public function isVeryVerbose()
     {
-        return $this->output->getVerbosity() >= 3; // OutputInterface::VERSOBITY_VERY_VERBOSE
+        return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
     }
 
     /**
@@ -89,7 +91,7 @@ class ConsoleIO extends BaseIO
      */
     public function isDebug()
     {
-        return $this->output->getVerbosity() >= 4; // OutputInterface::VERBOSITY_DEBUG
+        return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
     }
 
     /**
@@ -158,12 +160,6 @@ class ConsoleIO extends BaseIO
      */
     private function doOverwrite($messages, $newline, $size, $stderr)
     {
-        if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
-            $output = $this->output->getErrorOutput();
-        } else {
-            $output = $this->output;
-        }
-
         // messages can be an array, let's convert it to string anyway
         $messages = join($newline ? "\n" : '', (array) $messages);
 
@@ -208,10 +204,11 @@ class ConsoleIO extends BaseIO
             $output = $output->getErrorOutput();
         }
 
-        /** @var \Symfony\Component\Console\Helper\DialogHelper $dialog */
-        $dialog = $this->helperSet->get('dialog');
+        /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+        $helper = $this->helperSet->get('question');
+        $question = new Question($question, $default);
 
-        return $dialog->ask($output, $question, $default);
+        return $helper->ask($this->input, $output, $question);
     }
 
     /**
@@ -225,16 +222,17 @@ class ConsoleIO extends BaseIO
             $output = $output->getErrorOutput();
         }
 
-        /** @var \Symfony\Component\Console\Helper\DialogHelper $dialog */
-        $dialog = $this->helperSet->get('dialog');
+        /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+        $helper = $this->helperSet->get('question');
+        $question = new ConfirmationQuestion($question, $default);
 
-        return $dialog->askConfirmation($output, $question, $default);
+        return $helper->ask($this->input, $output, $question);
     }
 
     /**
      * {@inheritDoc}
      */
-    public function askAndValidate($question, $validator, $attempts = false, $default = null)
+    public function askAndValidate($question, $validator, $attempts = null, $default = null)
     {
         $output = $this->output;
 
@@ -242,10 +240,13 @@ class ConsoleIO extends BaseIO
             $output = $output->getErrorOutput();
         }
 
-        /** @var \Symfony\Component\Console\Helper\DialogHelper $dialog */
-        $dialog = $this->helperSet->get('dialog');
+        /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+        $helper = $this->helperSet->get('question');
+        $question = new Question($question, $default);
+        $question->setValidator($validator);
+        $question->setMaxAttempts($attempts);
 
-        return $dialog->askAndValidate($output, $question, $validator, $attempts, $default);
+        return $helper->ask($this->input, $output, $question);
     }
 
     /**

+ 2 - 2
src/Composer/IO/IOInterface.php

@@ -123,14 +123,14 @@ interface IOInterface
      *
      * @param string|array $question  The question to ask
      * @param callback     $validator A PHP callback
-     * @param bool|integer $attempts  Max number of times to ask before giving up (false by default, which means infinite)
+     * @param null|integer $attempts  Max number of times to ask before giving up (default of null means infinite)
      * @param string       $default   The default answer if none is given by the user
      *
      * @return mixed
      *
      * @throws \Exception When any of the validators return an error
      */
-    public function askAndValidate($question, $validator, $attempts = false, $default = null);
+    public function askAndValidate($question, $validator, $attempts = null, $default = null);
 
     /**
      * Asks a question to the user and hide the answer.

+ 55 - 36
tests/Composer/Test/IO/ConsoleIOTest.php

@@ -129,20 +129,27 @@ class ConsoleIOTest extends TestCase
     {
         $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
         $outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
-        $dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
-        $helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
+        $helperMock = $this->getMock('Symfony\Component\Console\Helper\QuestionHelper');
+        $setMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
 
-        $dialogMock->expects($this->once())
+        $helperMock
+            ->expects($this->once())
             ->method('ask')
-            ->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
-                $this->equalTo('Why?'),
-                $this->equalTo('default'));
-        $helperMock->expects($this->once())
+            ->with(
+                $this->isInstanceOf('Symfony\Component\Console\Input\InputInterface'),
+                $this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
+                $this->isInstanceOf('Symfony\Component\Console\Question\Question')
+            )
+        ;
+
+        $setMock
+            ->expects($this->once())
             ->method('get')
-            ->with($this->equalTo('dialog'))
-            ->will($this->returnValue($dialogMock));
+            ->with($this->equalTo('question'))
+            ->will($this->returnValue($helperMock))
+        ;
 
-        $consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
+        $consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock);
         $consoleIO->ask('Why?', 'default');
     }
 
@@ -150,20 +157,27 @@ class ConsoleIOTest extends TestCase
     {
         $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
         $outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
-        $dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
-        $helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
+        $helperMock = $this->getMock('Symfony\Component\Console\Helper\QuestionHelper');
+        $setMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
 
-        $dialogMock->expects($this->once())
-            ->method('askConfirmation')
-            ->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
-                $this->equalTo('Why?'),
-                $this->equalTo('default'));
-        $helperMock->expects($this->once())
+        $helperMock
+            ->expects($this->once())
+            ->method('ask')
+            ->with(
+                $this->isInstanceOf('Symfony\Component\Console\Input\InputInterface'),
+                $this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
+                $this->isInstanceOf('Symfony\Component\Console\Question\ConfirmationQuestion')
+            )
+        ;
+
+        $setMock
+            ->expects($this->once())
             ->method('get')
-            ->with($this->equalTo('dialog'))
-            ->will($this->returnValue($dialogMock));
+            ->with($this->equalTo('question'))
+            ->will($this->returnValue($helperMock))
+        ;
 
-        $consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
+        $consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock);
         $consoleIO->askConfirmation('Why?', 'default');
     }
 
@@ -171,22 +185,27 @@ class ConsoleIOTest extends TestCase
     {
         $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
         $outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
-        $dialogMock = $this->getMock('Symfony\Component\Console\Helper\DialogHelper');
-        $helperMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
+        $helperMock = $this->getMock('Symfony\Component\Console\Helper\QuestionHelper');
+        $setMock = $this->getMock('Symfony\Component\Console\Helper\HelperSet');
 
-        $dialogMock->expects($this->once())
-            ->method('askAndValidate')
-            ->with($this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
-                $this->equalTo('Why?'),
-                $this->equalTo('validator'),
-                $this->equalTo(10),
-                $this->equalTo('default'));
-        $helperMock->expects($this->once())
+        $helperMock
+            ->expects($this->once())
+            ->method('ask')
+            ->with(
+                $this->isInstanceOf('Symfony\Component\Console\Input\InputInterface'),
+                $this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'),
+                $this->isInstanceOf('Symfony\Component\Console\Question\Question')
+            )
+        ;
+
+        $setMock
+            ->expects($this->once())
             ->method('get')
-            ->with($this->equalTo('dialog'))
-            ->will($this->returnValue($dialogMock));
+            ->with($this->equalTo('question'))
+            ->will($this->returnValue($helperMock))
+        ;
 
-        $consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock);
+        $consoleIO = new ConsoleIO($inputMock, $outputMock, $setMock);
         $consoleIO->askAndValidate('Why?', 'validator', 10, 'default');
     }
 
@@ -205,7 +224,7 @@ class ConsoleIOTest extends TestCase
         );
     }
 
-    public function testgetAuthenticationWhenDidNotSet()
+    public function testGetAuthenticationWhenDidNotSet()
     {
         $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
         $outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
@@ -219,7 +238,7 @@ class ConsoleIOTest extends TestCase
         );
     }
 
-    public function testhasAuthentication()
+    public function testHasAuthentication()
     {
         $inputMock = $this->getMock('Symfony\Component\Console\Input\InputInterface');
         $outputMock = $this->getMock('Symfony\Component\Console\Output\OutputInterface');