2012-01-16 13:14:15 +00:00
|
|
|
<?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\IO;
|
|
|
|
|
2017-11-06 15:29:55 +00:00
|
|
|
use Composer\Question\StrictConfirmationQuestion;
|
|
|
|
use Symfony\Component\Console\Helper\HelperSet;
|
2012-01-16 13:14:15 +00:00
|
|
|
use Symfony\Component\Console\Input\InputInterface;
|
2015-02-06 12:52:44 +00:00
|
|
|
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
2012-01-16 13:14:15 +00:00
|
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
2017-11-06 15:29:55 +00:00
|
|
|
use Symfony\Component\Console\Question\ChoiceQuestion;
|
2015-04-30 10:09:56 +00:00
|
|
|
use Symfony\Component\Console\Question\Question;
|
2012-01-16 13:14:15 +00:00
|
|
|
|
2012-01-17 22:07:33 +00:00
|
|
|
/**
|
|
|
|
* The Input/Output helper.
|
|
|
|
*
|
|
|
|
* @author François Pluchino <francois.pluchino@opendisplay.com>
|
2012-05-06 15:17:36 +00:00
|
|
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
2012-01-16 13:14:15 +00:00
|
|
|
*/
|
2013-08-18 13:32:34 +00:00
|
|
|
class ConsoleIO extends BaseIO
|
2012-01-16 13:14:15 +00:00
|
|
|
{
|
2016-04-07 21:12:23 +00:00
|
|
|
/** @var InputInterface */
|
2012-01-16 13:14:15 +00:00
|
|
|
protected $input;
|
2016-04-07 21:12:23 +00:00
|
|
|
/** @var OutputInterface */
|
2012-01-16 13:14:15 +00:00
|
|
|
protected $output;
|
2016-04-07 21:12:23 +00:00
|
|
|
/** @var HelperSet */
|
2012-01-16 13:14:15 +00:00
|
|
|
protected $helperSet;
|
2016-04-07 21:12:23 +00:00
|
|
|
/** @var string */
|
2012-03-06 18:08:15 +00:00
|
|
|
protected $lastMessage;
|
2016-04-07 21:12:23 +00:00
|
|
|
/** @var string */
|
2015-02-06 12:52:44 +00:00
|
|
|
protected $lastMessageErr;
|
2016-04-07 21:12:23 +00:00
|
|
|
|
|
|
|
/** @var float */
|
2013-03-05 14:21:54 +00:00
|
|
|
private $startTime;
|
2016-04-07 21:12:23 +00:00
|
|
|
/** @var array<int, int> */
|
2016-01-28 13:41:19 +00:00
|
|
|
private $verbosityMap;
|
2012-01-16 13:14:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
2012-01-17 09:29:54 +00:00
|
|
|
* @param InputInterface $input The input instance
|
|
|
|
* @param OutputInterface $output The output instance
|
|
|
|
* @param HelperSet $helperSet The helperSet instance
|
2012-01-16 13:14:15 +00:00
|
|
|
*/
|
2012-01-17 09:29:54 +00:00
|
|
|
public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
|
2012-01-16 13:14:15 +00:00
|
|
|
{
|
|
|
|
$this->input = $input;
|
|
|
|
$this->output = $output;
|
|
|
|
$this->helperSet = $helperSet;
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->verbosityMap = array(
|
|
|
|
self::QUIET => OutputInterface::VERBOSITY_QUIET,
|
|
|
|
self::NORMAL => OutputInterface::VERBOSITY_NORMAL,
|
|
|
|
self::VERBOSE => OutputInterface::VERBOSITY_VERBOSE,
|
|
|
|
self::VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE,
|
|
|
|
self::DEBUG => OutputInterface::VERBOSITY_DEBUG,
|
|
|
|
);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 21:12:23 +00:00
|
|
|
/**
|
|
|
|
* @param float $startTime
|
|
|
|
*/
|
2013-03-05 14:21:54 +00:00
|
|
|
public function enableDebugging($startTime)
|
|
|
|
{
|
|
|
|
$this->startTime = $startTime;
|
|
|
|
}
|
|
|
|
|
2012-01-16 13:14:15 +00:00
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function isInteractive()
|
|
|
|
{
|
|
|
|
return $this->input->isInteractive();
|
|
|
|
}
|
|
|
|
|
2012-04-26 12:54:34 +00:00
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function isDecorated()
|
|
|
|
{
|
|
|
|
return $this->output->isDecorated();
|
|
|
|
}
|
|
|
|
|
2012-04-01 02:32:00 +00:00
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function isVerbose()
|
|
|
|
{
|
2013-04-26 21:23:35 +00:00
|
|
|
return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function isVeryVerbose()
|
|
|
|
{
|
2015-04-30 10:10:17 +00:00
|
|
|
return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
|
2013-04-26 21:23:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function isDebug()
|
|
|
|
{
|
2015-04-30 10:10:17 +00:00
|
|
|
return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
|
2012-04-01 02:32:00 +00:00
|
|
|
}
|
|
|
|
|
2012-01-16 13:14:15 +00:00
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2016-01-28 13:41:19 +00:00
|
|
|
public function write($messages, $newline = true, $verbosity = self::NORMAL)
|
2015-02-06 12:52:44 +00:00
|
|
|
{
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite($messages, $newline, false, $verbosity);
|
2015-02-06 12:52:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2016-01-28 13:41:19 +00:00
|
|
|
public function writeError($messages, $newline = true, $verbosity = self::NORMAL)
|
2015-02-06 12:52:44 +00:00
|
|
|
{
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite($messages, $newline, true, $verbosity);
|
2015-02-06 12:52:44 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 09:03:45 +00:00
|
|
|
/**
|
2016-01-09 17:59:22 +00:00
|
|
|
* @param array|string $messages
|
|
|
|
* @param bool $newline
|
|
|
|
* @param bool $stderr
|
2016-01-28 13:41:19 +00:00
|
|
|
* @param int $verbosity
|
2015-02-18 09:03:45 +00:00
|
|
|
*/
|
2016-01-28 13:41:19 +00:00
|
|
|
private function doWrite($messages, $newline, $stderr, $verbosity)
|
2012-01-16 13:14:15 +00:00
|
|
|
{
|
2016-01-28 13:41:19 +00:00
|
|
|
$sfVerbosity = $this->verbosityMap[$verbosity];
|
|
|
|
if ($sfVerbosity > $this->output->getVerbosity()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-13 15:33:04 +00:00
|
|
|
// hack to keep our usage BC with symfony<2.8 versions
|
|
|
|
// this removes the quiet output but there is no way around it
|
|
|
|
// see https://github.com/composer/composer/pull/4913
|
|
|
|
if (OutputInterface::VERBOSITY_QUIET === 0) {
|
|
|
|
$sfVerbosity = OutputInterface::OUTPUT_NORMAL;
|
|
|
|
}
|
|
|
|
|
2013-03-05 14:21:54 +00:00
|
|
|
if (null !== $this->startTime) {
|
2015-01-28 13:43:58 +00:00
|
|
|
$memoryUsage = memory_get_usage() / 1024 / 1024;
|
|
|
|
$timeSpent = microtime(true) - $this->startTime;
|
|
|
|
$messages = array_map(function ($message) use ($memoryUsage, $timeSpent) {
|
|
|
|
return sprintf('[%.1fMB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
|
|
|
|
}, (array) $messages);
|
2013-03-05 14:21:54 +00:00
|
|
|
}
|
2015-02-06 12:52:44 +00:00
|
|
|
|
|
|
|
if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->output->getErrorOutput()->write($messages, $newline, $sfVerbosity);
|
2016-10-11 13:52:29 +00:00
|
|
|
$this->lastMessageErr = implode($newline ? "\n" : '', (array) $messages);
|
2015-04-15 00:21:03 +00:00
|
|
|
|
2015-02-06 12:52:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->output->write($messages, $newline, $sfVerbosity);
|
2016-10-11 13:52:29 +00:00
|
|
|
$this->lastMessage = implode($newline ? "\n" : '', (array) $messages);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2016-01-28 13:41:19 +00:00
|
|
|
public function overwrite($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
|
2012-01-16 13:14:15 +00:00
|
|
|
{
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doOverwrite($messages, $newline, $size, false, $verbosity);
|
2015-02-18 09:03:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2016-01-28 13:41:19 +00:00
|
|
|
public function overwriteError($messages, $newline = true, $size = null, $verbosity = self::NORMAL)
|
2015-02-18 09:03:45 +00:00
|
|
|
{
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doOverwrite($messages, $newline, $size, true, $verbosity);
|
2015-02-18 09:03:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-01-09 17:59:22 +00:00
|
|
|
* @param array|string $messages
|
|
|
|
* @param bool $newline
|
|
|
|
* @param int|null $size
|
|
|
|
* @param bool $stderr
|
2016-01-28 13:41:19 +00:00
|
|
|
* @param int $verbosity
|
2015-02-18 09:03:45 +00:00
|
|
|
*/
|
2016-01-28 13:41:19 +00:00
|
|
|
private function doOverwrite($messages, $newline, $size, $stderr, $verbosity)
|
2015-02-18 09:03:45 +00:00
|
|
|
{
|
2012-03-06 18:08:15 +00:00
|
|
|
// messages can be an array, let's convert it to string anyway
|
2016-10-11 13:52:29 +00:00
|
|
|
$messages = implode($newline ? "\n" : '', (array) $messages);
|
2012-03-06 18:08:15 +00:00
|
|
|
|
|
|
|
// since overwrite is supposed to overwrite last message...
|
|
|
|
if (!isset($size)) {
|
|
|
|
// removing possible formatting of lastMessage with strip_tags
|
2015-02-18 09:03:45 +00:00
|
|
|
$size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage));
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
2012-03-06 18:08:15 +00:00
|
|
|
// ...let's fill its length with backspaces
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite(str_repeat("\x08", $size), false, $stderr, $verbosity);
|
2012-01-16 13:14:15 +00:00
|
|
|
|
2012-03-06 18:08:15 +00:00
|
|
|
// write the new message
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite($messages, false, $stderr, $verbosity);
|
2012-01-16 13:14:15 +00:00
|
|
|
|
2016-11-06 17:16:45 +00:00
|
|
|
// In cmd.exe on Win8.1 (possibly 10?), the line can not be cleared, so we need to
|
|
|
|
// track the length of previous output and fill it with spaces to make sure the line is cleared.
|
|
|
|
// See https://github.com/composer/composer/pull/5836 for more details
|
2012-03-06 18:08:15 +00:00
|
|
|
$fill = $size - strlen(strip_tags($messages));
|
|
|
|
if ($fill > 0) {
|
|
|
|
// whitespace whatever has left
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite(str_repeat(' ', $fill), false, $stderr, $verbosity);
|
2012-03-06 18:08:15 +00:00
|
|
|
// move the cursor back
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite(str_repeat("\x08", $fill), false, $stderr, $verbosity);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($newline) {
|
2016-01-28 13:41:19 +00:00
|
|
|
$this->doWrite('', true, $stderr, $verbosity);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
2015-03-05 14:40:29 +00:00
|
|
|
|
|
|
|
if ($stderr) {
|
|
|
|
$this->lastMessageErr = $messages;
|
|
|
|
} else {
|
|
|
|
$this->lastMessage = $messages;
|
|
|
|
}
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function ask($question, $default = null)
|
|
|
|
{
|
2015-04-30 10:09:56 +00:00
|
|
|
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
|
|
|
$helper = $this->helperSet->get('question');
|
|
|
|
$question = new Question($question, $default);
|
2015-02-18 09:03:45 +00:00
|
|
|
|
2016-02-29 15:32:49 +00:00
|
|
|
return $helper->ask($this->input, $this->getErrorOutput(), $question);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function askConfirmation($question, $default = true)
|
|
|
|
{
|
2015-04-30 10:09:56 +00:00
|
|
|
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
|
|
|
$helper = $this->helperSet->get('question');
|
2017-04-10 20:21:53 +00:00
|
|
|
$question = new StrictConfirmationQuestion($question, $default);
|
2015-02-18 09:03:45 +00:00
|
|
|
|
2016-02-29 15:32:49 +00:00
|
|
|
return $helper->ask($this->input, $this->getErrorOutput(), $question);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
2012-01-17 22:07:33 +00:00
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2015-04-30 10:09:56 +00:00
|
|
|
public function askAndValidate($question, $validator, $attempts = null, $default = null)
|
2012-01-16 13:14:15 +00:00
|
|
|
{
|
2015-04-30 10:09:56 +00:00
|
|
|
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
|
|
|
$helper = $this->helperSet->get('question');
|
|
|
|
$question = new Question($question, $default);
|
|
|
|
$question->setValidator($validator);
|
|
|
|
$question->setMaxAttempts($attempts);
|
2015-02-18 09:03:45 +00:00
|
|
|
|
2016-02-29 15:32:49 +00:00
|
|
|
return $helper->ask($this->input, $this->getErrorOutput(), $question);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
|
|
|
public function askAndHideAnswer($question)
|
|
|
|
{
|
2015-05-01 14:46:34 +00:00
|
|
|
$this->writeError($question, false);
|
2012-01-16 13:14:15 +00:00
|
|
|
|
2015-05-01 14:46:34 +00:00
|
|
|
return \Seld\CliPrompt\CliPrompt::hiddenPrompt(true);
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|
2014-08-12 09:12:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritDoc}
|
|
|
|
*/
|
2016-02-29 15:32:49 +00:00
|
|
|
public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
|
|
|
|
{
|
2017-11-06 15:29:55 +00:00
|
|
|
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
|
|
|
$helper = $this->helperSet->get('question');
|
|
|
|
$question = new ChoiceQuestion($question, $choices, $default);
|
|
|
|
$question->setMaxAttempts($attempts ?: null); // IOInterface requires false, and Question requires null or int
|
|
|
|
$question->setErrorMessage($errorMessage);
|
|
|
|
$question->setMultiselect($multiselect);
|
2016-02-29 15:32:49 +00:00
|
|
|
|
2017-11-06 15:29:55 +00:00
|
|
|
return $helper->ask($this->input, $this->getErrorOutput(), $question);
|
2016-02-29 15:32:49 +00:00
|
|
|
}
|
|
|
|
|
2016-04-07 21:12:23 +00:00
|
|
|
/**
|
|
|
|
* @return OutputInterface
|
|
|
|
*/
|
2016-02-29 15:32:49 +00:00
|
|
|
private function getErrorOutput()
|
2014-08-12 09:12:07 +00:00
|
|
|
{
|
2016-02-29 15:32:49 +00:00
|
|
|
if ($this->output instanceof ConsoleOutputInterface) {
|
|
|
|
return $this->output->getErrorOutput();
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->output;
|
2014-08-12 09:12:07 +00:00
|
|
|
}
|
2012-01-16 13:14:15 +00:00
|
|
|
}
|