diff --git a/src/Composer/Command/Helper/DialogHelper.php b/src/Composer/Command/Helper/DialogHelper.php deleted file mode 100644 index 6fb64f27e..000000000 --- a/src/Composer/Command/Helper/DialogHelper.php +++ /dev/null @@ -1,36 +0,0 @@ - - * Jordi Boggiano - * - * 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('%s [%s]%s ', $question, $default, $sep) : - sprintf('%s%s ', $question, $sep); - } -} diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index ae3fc8330..70411736a 100644 --- a/src/Composer/Command/InitCommand.php +++ b/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; + + /** @var Pool */ private $pool; - public function parseAuthorString($author) - { - if (preg_match('/^(?P[- \.,\p{L}\p{N}\'’]+) <(?P.+?)>$/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 ' - ); - } - + /** + * {@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 [yes]? ', true)) { $this->getIO()->writeError('Command aborted'); return 1; @@ -140,21 +126,24 @@ EOT } if (!$this->hasVendorIgnore($ignoreFile)) { - $question = 'Would you like the vendor directory added to your .gitignore [yes]?'; + $question = 'Would you like the vendor directory added to your .gitignore [yes]? '; - 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 (/)', $name), + $name = $this->getIO()->askAndValidate( + 'Package name (/) ['.$name.']: ', 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 ['.$description.']: ', $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 ['.$author.']: ', 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 ['.$minimumStability.']: ', 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 ['.$type.']: ', $type ); $input->setOption('type', $type); $license = $input->getOption('license') ?: false; - $license = $dialog->ask( - $output, - $dialog->getQuestion('License', $license), + $license = $this->getIO()->ask( + 'License ['.$license.']: ', $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 [yes]? '; $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 [yes]? '; $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[- \.,\p{L}\p{N}\'’]+) <(?P.+?)>$/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 ' + ); + } + 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); diff --git a/src/Composer/Command/RemoveCommand.php b/src/Composer/Command/RemoveCommand.php index 8821bd991..3779b09e9 100644 --- a/src/Composer/Command/RemoveCommand.php +++ b/src/Composer/Command/RemoveCommand.php @@ -74,9 +74,8 @@ EOT $json->removeLink($type, $package); } elseif (isset($composer[$altType][$package])) { $this->getIO()->writeError(''.$package.' could not be found in '.$type.' but it is present in '.$altType.''); - $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.' [yes]? ', true)) { $json->removeLink($altType, $package); } } diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index 2ccaec890..b2f9d5e7b 100644 --- a/src/Composer/Console/Application.php +++ b/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; - } } diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index 9300befad..366c67483 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/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); } /** diff --git a/src/Composer/IO/IOInterface.php b/src/Composer/IO/IOInterface.php index 0fd63fe4a..7dc9f5a09 100644 --- a/src/Composer/IO/IOInterface.php +++ b/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. diff --git a/tests/Composer/Test/IO/ConsoleIOTest.php b/tests/Composer/Test/IO/ConsoleIOTest.php index d0af8cb42..a300350b9 100644 --- a/tests/Composer/Test/IO/ConsoleIOTest.php +++ b/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()) - ->method('get') - ->with($this->equalTo('dialog')) - ->will($this->returnValue($dialogMock)); + ->with( + $this->isInstanceOf('Symfony\Component\Console\Input\InputInterface'), + $this->isInstanceOf('Symfony\Component\Console\Output\OutputInterface'), + $this->isInstanceOf('Symfony\Component\Console\Question\Question') + ) + ; - $consoleIO = new ConsoleIO($inputMock, $outputMock, $helperMock); + $setMock + ->expects($this->once()) + ->method('get') + ->with($this->equalTo('question')) + ->will($this->returnValue($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');