updated-packages
This commit is contained in:
378
vendor/symfony/console/Application.php
vendored
378
vendor/symfony/console/Application.php
vendored
@@ -36,14 +36,16 @@ use Symfony\Component\Console\Input\InputAwareInterface;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\StreamableInputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\ErrorHandler as LegacyErrorHandler;
|
||||
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
||||
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
|
||||
use Symfony\Contracts\Service\ResetInterface;
|
||||
|
||||
/**
|
||||
* An Application is the container for a collection of commands.
|
||||
@@ -60,9 +62,9 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Application
|
||||
class Application implements ResetInterface
|
||||
{
|
||||
private $commands = array();
|
||||
private $commands = [];
|
||||
private $wantHelps = false;
|
||||
private $runningCommand;
|
||||
private $name;
|
||||
@@ -75,7 +77,7 @@ class Application
|
||||
private $dispatcher;
|
||||
private $terminal;
|
||||
private $defaultCommand;
|
||||
private $singleCommand;
|
||||
private $singleCommand = false;
|
||||
private $initialized;
|
||||
|
||||
/**
|
||||
@@ -90,9 +92,12 @@ class Application
|
||||
$this->defaultCommand = 'list';
|
||||
}
|
||||
|
||||
/**
|
||||
* @final since Symfony 4.3, the type-hint will be updated to the interface from symfony/contracts in 5.0
|
||||
*/
|
||||
public function setDispatcher(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
|
||||
}
|
||||
|
||||
public function setCommandLoader(CommandLoaderInterface $commandLoader)
|
||||
@@ -109,8 +114,10 @@ class Application
|
||||
*/
|
||||
public function run(InputInterface $input = null, OutputInterface $output = null)
|
||||
{
|
||||
putenv('LINES='.$this->terminal->getHeight());
|
||||
putenv('COLUMNS='.$this->terminal->getWidth());
|
||||
if (\function_exists('putenv')) {
|
||||
@putenv('LINES='.$this->terminal->getHeight());
|
||||
@putenv('COLUMNS='.$this->terminal->getWidth());
|
||||
}
|
||||
|
||||
if (null === $input) {
|
||||
$input = new ArgvInput();
|
||||
@@ -120,22 +127,19 @@ class Application
|
||||
$output = new ConsoleOutput();
|
||||
}
|
||||
|
||||
$renderException = function ($e) use ($output) {
|
||||
if (!$e instanceof \Exception) {
|
||||
$e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
|
||||
}
|
||||
$renderException = function (\Throwable $e) use ($output) {
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$this->renderException($e, $output->getErrorOutput());
|
||||
$this->renderThrowable($e, $output->getErrorOutput());
|
||||
} else {
|
||||
$this->renderException($e, $output);
|
||||
$this->renderThrowable($e, $output);
|
||||
}
|
||||
};
|
||||
if ($phpHandler = set_exception_handler($renderException)) {
|
||||
restore_exception_handler();
|
||||
if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) {
|
||||
$debugHandler = true;
|
||||
} elseif ($debugHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
|
||||
$phpHandler[0]->setExceptionHandler($debugHandler);
|
||||
if (!\is_array($phpHandler) || (!$phpHandler[0] instanceof ErrorHandler && !$phpHandler[0] instanceof LegacyErrorHandler)) {
|
||||
$errorHandler = true;
|
||||
} elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) {
|
||||
$phpHandler[0]->setExceptionHandler($errorHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +157,7 @@ class Application
|
||||
$exitCode = $e->getCode();
|
||||
if (is_numeric($exitCode)) {
|
||||
$exitCode = (int) $exitCode;
|
||||
if (0 === $exitCode) {
|
||||
if ($exitCode <= 0) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
} else {
|
||||
@@ -167,7 +171,7 @@ class Application
|
||||
restore_exception_handler();
|
||||
}
|
||||
restore_exception_handler();
|
||||
} elseif (!$debugHandler) {
|
||||
} elseif (!$errorHandler) {
|
||||
$finalHandler = $phpHandler[0]->setExceptionHandler(null);
|
||||
if ($finalHandler !== $renderException) {
|
||||
$phpHandler[0]->setExceptionHandler($finalHandler);
|
||||
@@ -193,17 +197,24 @@ class Application
|
||||
*/
|
||||
public function doRun(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (true === $input->hasParameterOption(array('--version', '-V'), true)) {
|
||||
if (true === $input->hasParameterOption(['--version', '-V'], true)) {
|
||||
$output->writeln($this->getLongVersion());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
|
||||
$input->bind($this->getDefinition());
|
||||
} catch (ExceptionInterface $e) {
|
||||
// Errors must be ignored, full binding/validation happens later when the command is known.
|
||||
}
|
||||
|
||||
$name = $this->getCommandName($input);
|
||||
if (true === $input->hasParameterOption(array('--help', '-h'), true)) {
|
||||
if (true === $input->hasParameterOption(['--help', '-h'], true)) {
|
||||
if (!$name) {
|
||||
$name = 'help';
|
||||
$input = new ArrayInput(array('command_name' => $this->defaultCommand));
|
||||
$input = new ArrayInput(['command_name' => $this->defaultCommand]);
|
||||
} else {
|
||||
$this->wantHelps = true;
|
||||
}
|
||||
@@ -214,9 +225,9 @@ class Application
|
||||
$definition = $this->getDefinition();
|
||||
$definition->setArguments(array_merge(
|
||||
$definition->getArguments(),
|
||||
array(
|
||||
[
|
||||
'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
|
||||
)
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
@@ -228,7 +239,7 @@ class Application
|
||||
if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) {
|
||||
if (null !== $this->dispatcher) {
|
||||
$event = new ConsoleErrorEvent($input, $output, $e);
|
||||
$this->dispatcher->dispatch(ConsoleEvents::ERROR, $event);
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
|
||||
|
||||
if (0 === $event->getExitCode()) {
|
||||
return 0;
|
||||
@@ -243,11 +254,13 @@ class Application
|
||||
$alternative = $alternatives[0];
|
||||
|
||||
$style = new SymfonyStyle($input, $output);
|
||||
$style->block(sprintf("\nCommand \"%s\" is not defined.\n", $name), null, 'error');
|
||||
$output->writeln('');
|
||||
$formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true);
|
||||
$output->writeln($formattedBlock);
|
||||
if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) {
|
||||
if (null !== $this->dispatcher) {
|
||||
$event = new ConsoleErrorEvent($input, $output, $e);
|
||||
$this->dispatcher->dispatch(ConsoleEvents::ERROR, $event);
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
|
||||
|
||||
return $event->getExitCode();
|
||||
}
|
||||
@@ -265,6 +278,13 @@ class Application
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
}
|
||||
|
||||
public function setHelperSet(HelperSet $helperSet)
|
||||
{
|
||||
$this->helperSet = $helperSet;
|
||||
@@ -461,12 +481,11 @@ class Application
|
||||
if (!$command->isEnabled()) {
|
||||
$command->setApplication(null);
|
||||
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null === $command->getDefinition()) {
|
||||
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', \get_class($command)));
|
||||
}
|
||||
// Will throw if the command is not correctly initialized.
|
||||
$command->getDefinition();
|
||||
|
||||
if (!$command->getName()) {
|
||||
throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', \get_class($command)));
|
||||
@@ -498,6 +517,11 @@ class Application
|
||||
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
// When the command has a different name than the one used at the command loader level
|
||||
if (!isset($this->commands[$name])) {
|
||||
throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name));
|
||||
}
|
||||
|
||||
$command = $this->commands[$name];
|
||||
|
||||
if ($this->wantHelps) {
|
||||
@@ -535,8 +559,12 @@ class Application
|
||||
*/
|
||||
public function getNamespaces()
|
||||
{
|
||||
$namespaces = array();
|
||||
$namespaces = [];
|
||||
foreach ($this->all() as $command) {
|
||||
if ($command->isHidden()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$namespaces = array_merge($namespaces, $this->extractAllNamespaces($command->getName()));
|
||||
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
@@ -580,7 +608,7 @@ class Application
|
||||
|
||||
$exact = \in_array($namespace, $namespaces, true);
|
||||
if (\count($namespaces) > 1 && !$exact) {
|
||||
throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
|
||||
throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces));
|
||||
}
|
||||
|
||||
return $exact ? $namespace : reset($namespaces);
|
||||
@@ -602,7 +630,20 @@ class Application
|
||||
{
|
||||
$this->init();
|
||||
|
||||
$aliases = array();
|
||||
$aliases = [];
|
||||
|
||||
foreach ($this->commands as $command) {
|
||||
foreach ($command->getAliases() as $alias) {
|
||||
if (!$this->has($alias)) {
|
||||
$this->commands[$alias] = $command;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->has($name)) {
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
$allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
|
||||
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
|
||||
$commands = preg_grep('{^'.$expr.'}', $allCommands);
|
||||
@@ -621,6 +662,11 @@ class Application
|
||||
$message = sprintf('Command "%s" is not defined.', $name);
|
||||
|
||||
if ($alternatives = $this->findAlternatives($name, $allCommands)) {
|
||||
// remove hidden commands
|
||||
$alternatives = array_filter($alternatives, function ($name) {
|
||||
return !$this->get($name)->isHidden();
|
||||
});
|
||||
|
||||
if (1 == \count($alternatives)) {
|
||||
$message .= "\n\nDid you mean this?\n ";
|
||||
} else {
|
||||
@@ -629,42 +675,58 @@ class Application
|
||||
$message .= implode("\n ", $alternatives);
|
||||
}
|
||||
|
||||
throw new CommandNotFoundException($message, $alternatives);
|
||||
throw new CommandNotFoundException($message, array_values($alternatives));
|
||||
}
|
||||
|
||||
// filter out aliases for commands which are already on the list
|
||||
if (\count($commands) > 1) {
|
||||
$commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
|
||||
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands, &$aliases) {
|
||||
$commandName = $commandList[$nameOrAlias] instanceof Command ? $commandList[$nameOrAlias]->getName() : $nameOrAlias;
|
||||
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) {
|
||||
if (!$commandList[$nameOrAlias] instanceof Command) {
|
||||
$commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias);
|
||||
}
|
||||
|
||||
$commandName = $commandList[$nameOrAlias]->getName();
|
||||
|
||||
$aliases[$nameOrAlias] = $commandName;
|
||||
|
||||
return $commandName === $nameOrAlias || !\in_array($commandName, $commands);
|
||||
}));
|
||||
}
|
||||
|
||||
$exact = \in_array($name, $commands, true) || isset($aliases[$name]);
|
||||
if (\count($commands) > 1 && !$exact) {
|
||||
if (\count($commands) > 1) {
|
||||
$usableWidth = $this->terminal->getWidth() - 10;
|
||||
$abbrevs = array_values($commands);
|
||||
$maxLen = 0;
|
||||
foreach ($abbrevs as $abbrev) {
|
||||
$maxLen = max(Helper::strlen($abbrev), $maxLen);
|
||||
}
|
||||
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) {
|
||||
if (!$commandList[$cmd] instanceof Command) {
|
||||
return $cmd;
|
||||
$abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen, &$commands) {
|
||||
if ($commandList[$cmd]->isHidden()) {
|
||||
unset($commands[array_search($cmd, $commands)]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$abbrev = str_pad($cmd, $maxLen, ' ').' '.$commandList[$cmd]->getDescription();
|
||||
|
||||
return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3).'...' : $abbrev;
|
||||
}, array_values($commands));
|
||||
$suggestions = $this->getAbbreviationSuggestions($abbrevs);
|
||||
|
||||
throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands));
|
||||
if (\count($commands) > 1) {
|
||||
$suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs));
|
||||
|
||||
throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->get($exact ? $name : reset($commands));
|
||||
$command = $this->get(reset($commands));
|
||||
|
||||
if ($command->isHidden()) {
|
||||
@trigger_error(sprintf('Command "%s" is hidden, finding it using an abbreviation is deprecated since Symfony 4.4, use its full name instead.', $command->getName()), \E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,7 +757,7 @@ class Application
|
||||
return $commands;
|
||||
}
|
||||
|
||||
$commands = array();
|
||||
$commands = [];
|
||||
foreach ($this->commands as $name => $command) {
|
||||
if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
|
||||
$commands[$name] = $command;
|
||||
@@ -722,7 +784,7 @@ class Application
|
||||
*/
|
||||
public static function getAbbreviations($names)
|
||||
{
|
||||
$abbrevs = array();
|
||||
$abbrevs = [];
|
||||
foreach ($names as $name) {
|
||||
for ($len = \strlen($name); $len > 0; --$len) {
|
||||
$abbrev = substr($name, 0, $len);
|
||||
@@ -735,51 +797,107 @@ class Application
|
||||
|
||||
/**
|
||||
* Renders a caught exception.
|
||||
*
|
||||
* @deprecated since Symfony 4.4, use "renderThrowable()" instead
|
||||
*/
|
||||
public function renderException(\Exception $e, OutputInterface $output)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s::renderException()" method is deprecated since Symfony 4.4, use "renderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
|
||||
|
||||
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
|
||||
|
||||
$this->doRenderException($e, $output);
|
||||
|
||||
$this->finishRenderThrowableOrException($output);
|
||||
}
|
||||
|
||||
public function renderThrowable(\Throwable $e, OutputInterface $output): void
|
||||
{
|
||||
if (__CLASS__ !== static::class && __CLASS__ === (new \ReflectionMethod($this, 'renderThrowable'))->getDeclaringClass()->getName() && __CLASS__ !== (new \ReflectionMethod($this, 'renderException'))->getDeclaringClass()->getName()) {
|
||||
@trigger_error(sprintf('The "%s::renderException()" method is deprecated since Symfony 4.4, use "renderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
|
||||
|
||||
if (!$e instanceof \Exception) {
|
||||
$e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
|
||||
}
|
||||
|
||||
$this->renderException($e, $output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
|
||||
|
||||
$this->doRenderThrowable($e, $output);
|
||||
|
||||
$this->finishRenderThrowableOrException($output);
|
||||
}
|
||||
|
||||
private function finishRenderThrowableOrException(OutputInterface $output): void
|
||||
{
|
||||
if (null !== $this->runningCommand) {
|
||||
$output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())), OutputInterface::VERBOSITY_QUIET);
|
||||
$output->writeln(sprintf('<info>%s</info>', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET);
|
||||
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since Symfony 4.4, use "doRenderThrowable()" instead
|
||||
*/
|
||||
protected function doRenderException(\Exception $e, OutputInterface $output)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s::doRenderException()" method is deprecated since Symfony 4.4, use "doRenderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
|
||||
|
||||
$this->doActuallyRenderThrowable($e, $output);
|
||||
}
|
||||
|
||||
protected function doRenderThrowable(\Throwable $e, OutputInterface $output): void
|
||||
{
|
||||
if (__CLASS__ !== static::class && __CLASS__ === (new \ReflectionMethod($this, 'doRenderThrowable'))->getDeclaringClass()->getName() && __CLASS__ !== (new \ReflectionMethod($this, 'doRenderException'))->getDeclaringClass()->getName()) {
|
||||
@trigger_error(sprintf('The "%s::doRenderException()" method is deprecated since Symfony 4.4, use "doRenderThrowable()" instead.', __CLASS__), \E_USER_DEPRECATED);
|
||||
|
||||
if (!$e instanceof \Exception) {
|
||||
$e = class_exists(FatalThrowableError::class) ? new FatalThrowableError($e) : new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine());
|
||||
}
|
||||
|
||||
$this->doRenderException($e, $output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->doActuallyRenderThrowable($e, $output);
|
||||
}
|
||||
|
||||
private function doActuallyRenderThrowable(\Throwable $e, OutputInterface $output): void
|
||||
{
|
||||
do {
|
||||
$message = trim($e->getMessage());
|
||||
if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
|
||||
$class = \get_class($e);
|
||||
$class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
|
||||
$class = get_debug_type($e);
|
||||
$title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
|
||||
$len = Helper::strlen($title);
|
||||
} else {
|
||||
$len = 0;
|
||||
}
|
||||
|
||||
if (false !== strpos($message, "class@anonymous\0")) {
|
||||
$message = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
|
||||
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
|
||||
if (str_contains($message, "@anonymous\0")) {
|
||||
$message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
|
||||
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
|
||||
}, $message);
|
||||
}
|
||||
|
||||
$width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : PHP_INT_MAX;
|
||||
$lines = array();
|
||||
foreach ('' !== $message ? preg_split('/\r?\n/', $message) : array() as $line) {
|
||||
$width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX;
|
||||
$lines = [];
|
||||
foreach ('' !== $message ? preg_split('/\r?\n/', $message) : [] as $line) {
|
||||
foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
|
||||
// pre-format lines to get the right string length
|
||||
$lineLength = Helper::strlen($line) + 4;
|
||||
$lines[] = array($line, $lineLength);
|
||||
$lines[] = [$line, $lineLength];
|
||||
|
||||
$len = max($lineLength, $len);
|
||||
}
|
||||
}
|
||||
|
||||
$messages = array();
|
||||
$messages = [];
|
||||
if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
|
||||
$messages[] = sprintf('<comment>%s</comment>', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a')));
|
||||
}
|
||||
@@ -801,21 +919,21 @@ class Application
|
||||
// exception related properties
|
||||
$trace = $e->getTrace();
|
||||
|
||||
array_unshift($trace, array(
|
||||
array_unshift($trace, [
|
||||
'function' => '',
|
||||
'file' => $e->getFile() ?: 'n/a',
|
||||
'line' => $e->getLine() ?: 'n/a',
|
||||
'args' => array(),
|
||||
));
|
||||
'args' => [],
|
||||
]);
|
||||
|
||||
for ($i = 0, $count = \count($trace); $i < $count; ++$i) {
|
||||
$class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
|
||||
$type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
|
||||
$function = $trace[$i]['function'];
|
||||
$file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
|
||||
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
|
||||
$class = $trace[$i]['class'] ?? '';
|
||||
$type = $trace[$i]['type'] ?? '';
|
||||
$function = $trace[$i]['function'] ?? '';
|
||||
$file = $trace[$i]['file'] ?? 'n/a';
|
||||
$line = $trace[$i]['line'] ?? 'n/a';
|
||||
|
||||
$output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line), OutputInterface::VERBOSITY_QUIET);
|
||||
$output->writeln(sprintf(' %s%s at <info>%s:%s</info>', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET);
|
||||
}
|
||||
|
||||
$output->writeln('', OutputInterface::VERBOSITY_QUIET);
|
||||
@@ -828,35 +946,35 @@ class Application
|
||||
*/
|
||||
protected function configureIO(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if (true === $input->hasParameterOption(array('--ansi'), true)) {
|
||||
if (true === $input->hasParameterOption(['--ansi'], true)) {
|
||||
$output->setDecorated(true);
|
||||
} elseif (true === $input->hasParameterOption(array('--no-ansi'), true)) {
|
||||
} elseif (true === $input->hasParameterOption(['--no-ansi'], true)) {
|
||||
$output->setDecorated(false);
|
||||
}
|
||||
|
||||
if (true === $input->hasParameterOption(array('--no-interaction', '-n'), true)) {
|
||||
if (true === $input->hasParameterOption(['--no-interaction', '-n'], true)) {
|
||||
$input->setInteractive(false);
|
||||
} elseif (\function_exists('posix_isatty')) {
|
||||
$inputStream = null;
|
||||
|
||||
if ($input instanceof StreamableInputInterface) {
|
||||
$inputStream = $input->getStream();
|
||||
}
|
||||
|
||||
if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
|
||||
$input->setInteractive(false);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
|
||||
case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break;
|
||||
case 1: $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); break;
|
||||
case 2: $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); break;
|
||||
case 3: $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); break;
|
||||
default: $shellVerbosity = 0; break;
|
||||
case -1:
|
||||
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
|
||||
break;
|
||||
case 1:
|
||||
$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
|
||||
break;
|
||||
case 2:
|
||||
$output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
|
||||
break;
|
||||
case 3:
|
||||
$output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
|
||||
break;
|
||||
default:
|
||||
$shellVerbosity = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (true === $input->hasParameterOption(array('--quiet', '-q'), true)) {
|
||||
if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
|
||||
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
|
||||
$shellVerbosity = -1;
|
||||
} else {
|
||||
@@ -876,7 +994,9 @@ class Application
|
||||
$input->setInteractive(false);
|
||||
}
|
||||
|
||||
putenv('SHELL_VERBOSITY='.$shellVerbosity);
|
||||
if (\function_exists('putenv')) {
|
||||
@putenv('SHELL_VERBOSITY='.$shellVerbosity);
|
||||
}
|
||||
$_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
|
||||
$_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
|
||||
}
|
||||
@@ -913,7 +1033,7 @@ class Application
|
||||
$e = null;
|
||||
|
||||
try {
|
||||
$this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::COMMAND);
|
||||
|
||||
if ($event->commandShouldRun()) {
|
||||
$exitCode = $command->run($input, $output);
|
||||
@@ -922,7 +1042,7 @@ class Application
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$event = new ConsoleErrorEvent($input, $output, $e, $command);
|
||||
$this->dispatcher->dispatch(ConsoleEvents::ERROR, $event);
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::ERROR);
|
||||
$e = $event->getError();
|
||||
|
||||
if (0 === $exitCode = $event->getExitCode()) {
|
||||
@@ -931,7 +1051,7 @@ class Application
|
||||
}
|
||||
|
||||
$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
|
||||
$this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE);
|
||||
|
||||
if (null !== $e) {
|
||||
throw $e;
|
||||
@@ -943,7 +1063,7 @@ class Application
|
||||
/**
|
||||
* Gets the name of the command based on input.
|
||||
*
|
||||
* @return string The command name
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getCommandName(InputInterface $input)
|
||||
{
|
||||
@@ -957,7 +1077,7 @@ class Application
|
||||
*/
|
||||
protected function getDefaultInputDefinition()
|
||||
{
|
||||
return new InputDefinition(array(
|
||||
return new InputDefinition([
|
||||
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
|
||||
|
||||
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message'),
|
||||
@@ -967,7 +1087,7 @@ class Application
|
||||
new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output'),
|
||||
new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output'),
|
||||
new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'),
|
||||
));
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -977,7 +1097,7 @@ class Application
|
||||
*/
|
||||
protected function getDefaultCommands()
|
||||
{
|
||||
return array(new HelpCommand(), new ListCommand());
|
||||
return [new HelpCommand(), new ListCommand()];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -987,22 +1107,18 @@ class Application
|
||||
*/
|
||||
protected function getDefaultHelperSet()
|
||||
{
|
||||
return new HelperSet(array(
|
||||
return new HelperSet([
|
||||
new FormatterHelper(),
|
||||
new DebugFormatterHelper(),
|
||||
new ProcessHelper(),
|
||||
new QuestionHelper(),
|
||||
));
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns abbreviated suggestions in string format.
|
||||
*
|
||||
* @param array $abbrevs Abbreviated suggestions to convert
|
||||
*
|
||||
* @return string A formatted string of abbreviated suggestions
|
||||
*/
|
||||
private function getAbbreviationSuggestions($abbrevs)
|
||||
private function getAbbreviationSuggestions(array $abbrevs): string
|
||||
{
|
||||
return ' '.implode("\n ", $abbrevs);
|
||||
}
|
||||
@@ -1019,8 +1135,7 @@ class Application
|
||||
*/
|
||||
public function extractNamespace($name, $limit = null)
|
||||
{
|
||||
$parts = explode(':', $name);
|
||||
array_pop($parts);
|
||||
$parts = explode(':', $name, -1);
|
||||
|
||||
return implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit));
|
||||
}
|
||||
@@ -1029,17 +1144,14 @@ class Application
|
||||
* Finds alternative of $name among $collection,
|
||||
* if nothing is found in $collection, try in $abbrevs.
|
||||
*
|
||||
* @param string $name The string
|
||||
* @param iterable $collection The collection
|
||||
*
|
||||
* @return string[] A sorted array of similar string
|
||||
*/
|
||||
private function findAlternatives($name, $collection)
|
||||
private function findAlternatives(string $name, iterable $collection): array
|
||||
{
|
||||
$threshold = 1e3;
|
||||
$alternatives = array();
|
||||
$alternatives = [];
|
||||
|
||||
$collectionParts = array();
|
||||
$collectionParts = [];
|
||||
foreach ($collection as $item) {
|
||||
$collectionParts[$item] = explode(':', $item);
|
||||
}
|
||||
@@ -1055,7 +1167,7 @@ class Application
|
||||
}
|
||||
|
||||
$lev = levenshtein($subname, $parts[$i]);
|
||||
if ($lev <= \strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
|
||||
if ($lev <= \strlen($subname) / 3 || '' !== $subname && str_contains($parts[$i], $subname)) {
|
||||
$alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
|
||||
} elseif ($exists) {
|
||||
$alternatives[$collectionName] += $threshold;
|
||||
@@ -1065,13 +1177,13 @@ class Application
|
||||
|
||||
foreach ($collection as $item) {
|
||||
$lev = levenshtein($name, $item);
|
||||
if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
|
||||
if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) {
|
||||
$alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
|
||||
}
|
||||
}
|
||||
|
||||
$alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; });
|
||||
ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE);
|
||||
|
||||
return array_keys($alternatives);
|
||||
}
|
||||
@@ -1098,7 +1210,15 @@ class Application
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function splitStringByWidth($string, $width)
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function isSingleCommand(): bool
|
||||
{
|
||||
return $this->singleCommand;
|
||||
}
|
||||
|
||||
private function splitStringByWidth(string $string, int $width): array
|
||||
{
|
||||
// str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
|
||||
// additionally, array_slice() is not enough as some character has doubled width.
|
||||
@@ -1108,17 +1228,23 @@ class Application
|
||||
}
|
||||
|
||||
$utf8String = mb_convert_encoding($string, 'utf8', $encoding);
|
||||
$lines = array();
|
||||
$lines = [];
|
||||
$line = '';
|
||||
foreach (preg_split('//u', $utf8String) as $char) {
|
||||
// test if $char could be appended to current line
|
||||
if (mb_strwidth($line.$char, 'utf8') <= $width) {
|
||||
$line .= $char;
|
||||
continue;
|
||||
|
||||
$offset = 0;
|
||||
while (preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) {
|
||||
$offset += \strlen($m[0]);
|
||||
|
||||
foreach (preg_split('//u', $m[0]) as $char) {
|
||||
// test if $char could be appended to current line
|
||||
if (mb_strwidth($line.$char, 'utf8') <= $width) {
|
||||
$line .= $char;
|
||||
continue;
|
||||
}
|
||||
// if not, push current line to array and make new line
|
||||
$lines[] = str_pad($line, $width);
|
||||
$line = $char;
|
||||
}
|
||||
// if not, push current line to array and make new line
|
||||
$lines[] = str_pad($line, $width);
|
||||
$line = $char;
|
||||
}
|
||||
|
||||
$lines[] = \count($lines) ? str_pad($line, $width) : $line;
|
||||
@@ -1131,15 +1257,13 @@ class Application
|
||||
/**
|
||||
* Returns all namespaces of the command name.
|
||||
*
|
||||
* @param string $name The full name of the command
|
||||
*
|
||||
* @return string[] The namespaces of the command
|
||||
*/
|
||||
private function extractAllNamespaces($name)
|
||||
private function extractAllNamespaces(string $name): array
|
||||
{
|
||||
// -1 as third argument is needed to skip the command short name when exploding
|
||||
$parts = explode(':', $name, -1);
|
||||
$namespaces = array();
|
||||
$namespaces = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (\count($namespaces)) {
|
||||
|
60
vendor/symfony/console/CHANGELOG.md
vendored
60
vendor/symfony/console/CHANGELOG.md
vendored
@@ -1,10 +1,32 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* deprecated finding hidden commands using an abbreviation, use the full name instead
|
||||
* added `Question::setTrimmable` default to true to allow the answer to be trimmed
|
||||
* added method `minSecondsBetweenRedraws()` and `maxSecondsBetweenRedraws()` on `ProgressBar`
|
||||
* `Application` implements `ResetInterface`
|
||||
* marked all dispatched event classes as `@final`
|
||||
* added support for displaying table horizontally
|
||||
* deprecated returning `null` from `Command::execute()`, return `0` instead
|
||||
* Deprecated the `Application::renderException()` and `Application::doRenderException()` methods,
|
||||
use `renderThrowable()` and `doRenderThrowable()` instead.
|
||||
* added support for the `NO_COLOR` env var (https://no-color.org/)
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* added support for hyperlinks
|
||||
* added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating
|
||||
* added `Question::setAutocompleterCallback()` to provide a callback function
|
||||
that dynamically generates suggestions as the user types
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* allowed passing commands as `array($process, 'ENV_VAR' => 'value')` to
|
||||
* allowed passing commands as `[$process, 'ENV_VAR' => 'value']` to
|
||||
`ProcessHelper::run()` to pass environment variables
|
||||
* deprecated passing a command as a string to `ProcessHelper::run()`,
|
||||
pass it the command as an array of its arguments instead
|
||||
@@ -24,10 +46,10 @@ CHANGELOG
|
||||
|
||||
* `OutputFormatter` throws an exception when unknown options are used
|
||||
* removed `QuestionHelper::setInputStream()/getInputStream()`
|
||||
* removed `Application::getTerminalWidth()/getTerminalHeight()` and
|
||||
`Application::setTerminalDimensions()/getTerminalDimensions()`
|
||||
* removed `ConsoleExceptionEvent`
|
||||
* removed `ConsoleEvents::EXCEPTION`
|
||||
* removed `Application::getTerminalWidth()/getTerminalHeight()` and
|
||||
`Application::setTerminalDimensions()/getTerminalDimensions()`
|
||||
* removed `ConsoleExceptionEvent`
|
||||
* removed `ConsoleEvents::EXCEPTION`
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
@@ -44,29 +66,29 @@ CHANGELOG
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* added `ExceptionListener`
|
||||
* added `AddConsoleCommandPass` (originally in FrameworkBundle)
|
||||
* [BC BREAK] `Input::getOption()` no longer returns the default value for options
|
||||
with value optional explicitly passed empty
|
||||
* added console.error event to catch exceptions thrown by other listeners
|
||||
* deprecated console.exception event in favor of console.error
|
||||
* added ability to handle `CommandNotFoundException` through the
|
||||
`console.error` event
|
||||
* deprecated default validation in `SymfonyQuestionHelper::ask`
|
||||
* added `ExceptionListener`
|
||||
* added `AddConsoleCommandPass` (originally in FrameworkBundle)
|
||||
* [BC BREAK] `Input::getOption()` no longer returns the default value for options
|
||||
with value optional explicitly passed empty
|
||||
* added console.error event to catch exceptions thrown by other listeners
|
||||
* deprecated console.exception event in favor of console.error
|
||||
* added ability to handle `CommandNotFoundException` through the
|
||||
`console.error` event
|
||||
* deprecated default validation in `SymfonyQuestionHelper::ask`
|
||||
|
||||
3.2.0
|
||||
------
|
||||
|
||||
* added `setInputs()` method to CommandTester for ease testing of commands expecting inputs
|
||||
* added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface)
|
||||
* added StreamableInputInterface
|
||||
* added LockableTrait
|
||||
* added `setInputs()` method to CommandTester for ease testing of commands expecting inputs
|
||||
* added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface)
|
||||
* added StreamableInputInterface
|
||||
* added LockableTrait
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
|
||||
* added truncate method to FormatterHelper
|
||||
* added setColumnWidth(s) method to Table
|
||||
* added setColumnWidth(s) method to Table
|
||||
|
||||
2.8.3
|
||||
-----
|
||||
|
80
vendor/symfony/console/Command/Command.php
vendored
80
vendor/symfony/console/Command/Command.php
vendored
@@ -37,17 +37,17 @@ class Command
|
||||
private $application;
|
||||
private $name;
|
||||
private $processTitle;
|
||||
private $aliases = array();
|
||||
private $aliases = [];
|
||||
private $definition;
|
||||
private $hidden = false;
|
||||
private $help;
|
||||
private $description;
|
||||
private $help = '';
|
||||
private $description = '';
|
||||
private $ignoreValidationErrors = false;
|
||||
private $applicationDefinitionMerged = false;
|
||||
private $applicationDefinitionMergedWithArgs = false;
|
||||
private $code;
|
||||
private $synopsis = array();
|
||||
private $usages = array();
|
||||
private $synopsis = [];
|
||||
private $usages = [];
|
||||
private $helperSet;
|
||||
|
||||
/**
|
||||
@@ -55,7 +55,7 @@ class Command
|
||||
*/
|
||||
public static function getDefaultName()
|
||||
{
|
||||
$class = \get_called_class();
|
||||
$class = static::class;
|
||||
$r = new \ReflectionProperty($class, 'defaultName');
|
||||
|
||||
return $class === $r->class ? static::$defaultName : null;
|
||||
@@ -105,7 +105,7 @@ class Command
|
||||
/**
|
||||
* Gets the helper set.
|
||||
*
|
||||
* @return HelperSet A HelperSet instance
|
||||
* @return HelperSet|null A HelperSet instance
|
||||
*/
|
||||
public function getHelperSet()
|
||||
{
|
||||
@@ -115,7 +115,7 @@ class Command
|
||||
/**
|
||||
* Gets the application instance for this command.
|
||||
*
|
||||
* @return Application An Application instance
|
||||
* @return Application|null An Application instance
|
||||
*/
|
||||
public function getApplication()
|
||||
{
|
||||
@@ -150,7 +150,7 @@ class Command
|
||||
* execute() method, you set the code to execute by passing
|
||||
* a Closure to the setCode() method.
|
||||
*
|
||||
* @return int|null null or 0 if everything went fine, or an error code
|
||||
* @return int 0 if everything went fine, or an exit code
|
||||
*
|
||||
* @throws LogicException When this abstract method is not implemented
|
||||
*
|
||||
@@ -195,7 +195,7 @@ class Command
|
||||
*
|
||||
* @return int The command exit code
|
||||
*
|
||||
* @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}.
|
||||
* @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}.
|
||||
*
|
||||
* @see setCode()
|
||||
* @see execute()
|
||||
@@ -223,7 +223,7 @@ class Command
|
||||
if (null !== $this->processTitle) {
|
||||
if (\function_exists('cli_set_process_title')) {
|
||||
if (!@cli_set_process_title($this->processTitle)) {
|
||||
if ('Darwin' === PHP_OS) {
|
||||
if ('Darwin' === \PHP_OS) {
|
||||
$output->writeln('<comment>Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.</comment>', OutputInterface::VERBOSITY_VERY_VERBOSE);
|
||||
} else {
|
||||
cli_set_process_title($this->processTitle);
|
||||
@@ -250,9 +250,13 @@ class Command
|
||||
$input->validate();
|
||||
|
||||
if ($this->code) {
|
||||
$statusCode = \call_user_func($this->code, $input, $output);
|
||||
$statusCode = ($this->code)($input, $output);
|
||||
} else {
|
||||
$statusCode = $this->execute($input, $output);
|
||||
|
||||
if (!\is_int($statusCode)) {
|
||||
@trigger_error(sprintf('Return value of "%s::execute()" should always be of the type int since Symfony 4.4, %s returned.', static::class, \gettype($statusCode)), \E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
return is_numeric($statusCode) ? (int) $statusCode : 0;
|
||||
@@ -277,7 +281,14 @@ class Command
|
||||
if ($code instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($code);
|
||||
if (null === $r->getClosureThis()) {
|
||||
$code = \Closure::bind($code, $this);
|
||||
set_error_handler(static function () {});
|
||||
try {
|
||||
if ($c = \Closure::bind($code, $this)) {
|
||||
$code = $c;
|
||||
}
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +350,10 @@ class Command
|
||||
*/
|
||||
public function getDefinition()
|
||||
{
|
||||
if (null === $this->definition) {
|
||||
throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class));
|
||||
}
|
||||
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
@@ -360,10 +375,10 @@ class Command
|
||||
/**
|
||||
* Adds an argument.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param string|string[]|null $default The default value (for self::OPTIONAL mode only)
|
||||
* @param string $name The argument name
|
||||
* @param int|null $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (for InputArgument::OPTIONAL mode only)
|
||||
*
|
||||
* @throws InvalidArgumentException When argument mode is not valid
|
||||
*
|
||||
@@ -379,11 +394,11 @@ class Command
|
||||
/**
|
||||
* Adds an option.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
|
||||
* @param int|null $mode The option mode: One of the VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param string|string[]|int|bool|null $default The default value (must be null for self::VALUE_NONE)
|
||||
* @param string $name The option name
|
||||
* @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
|
||||
* @param int|null $mode The option mode: One of the InputOption::VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param mixed $default The default value (must be null for InputOption::VALUE_NONE)
|
||||
*
|
||||
* @throws InvalidArgumentException If option mode is invalid or incompatible
|
||||
*
|
||||
@@ -425,8 +440,6 @@ class Command
|
||||
* This feature should be used only when creating a long process command,
|
||||
* like a daemon.
|
||||
*
|
||||
* PHP 5.5+ or the proctitle PECL library is required
|
||||
*
|
||||
* @param string $title The process title
|
||||
*
|
||||
* @return $this
|
||||
@@ -441,7 +454,7 @@ class Command
|
||||
/**
|
||||
* Returns the command name.
|
||||
*
|
||||
* @return string The command name
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -451,7 +464,7 @@ class Command
|
||||
/**
|
||||
* @param bool $hidden Whether or not the command should be hidden from the list of commands
|
||||
*
|
||||
* @return Command The current instance
|
||||
* @return $this
|
||||
*/
|
||||
public function setHidden($hidden)
|
||||
{
|
||||
@@ -525,15 +538,16 @@ class Command
|
||||
public function getProcessedHelp()
|
||||
{
|
||||
$name = $this->name;
|
||||
$isSingleCommand = $this->application && $this->application->isSingleCommand();
|
||||
|
||||
$placeholders = array(
|
||||
$placeholders = [
|
||||
'%command.name%',
|
||||
'%command.full_name%',
|
||||
);
|
||||
$replacements = array(
|
||||
];
|
||||
$replacements = [
|
||||
$name,
|
||||
$_SERVER['PHP_SELF'].' '.$name,
|
||||
);
|
||||
$isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'].' '.$name,
|
||||
];
|
||||
|
||||
return str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription());
|
||||
}
|
||||
@@ -550,7 +564,7 @@ class Command
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
if (!\is_array($aliases) && !$aliases instanceof \Traversable) {
|
||||
throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
|
||||
throw new InvalidArgumentException('$aliases must be an array or an instance of \Traversable.');
|
||||
}
|
||||
|
||||
foreach ($aliases as $alias) {
|
||||
@@ -599,7 +613,7 @@ class Command
|
||||
*/
|
||||
public function addUsage($usage)
|
||||
{
|
||||
if (0 !== strpos($usage, $this->name)) {
|
||||
if (!str_starts_with($usage, $this->name)) {
|
||||
$usage = sprintf('%s %s', $this->name, $usage);
|
||||
}
|
||||
|
||||
|
12
vendor/symfony/console/Command/HelpCommand.php
vendored
12
vendor/symfony/console/Command/HelpCommand.php
vendored
@@ -35,12 +35,12 @@ class HelpCommand extends Command
|
||||
|
||||
$this
|
||||
->setName('help')
|
||||
->setDefinition(array(
|
||||
->setDefinition([
|
||||
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
|
||||
))
|
||||
->setDescription('Displays help for a command')
|
||||
])
|
||||
->setDescription('Display help for a command')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays help for a given command:
|
||||
|
||||
@@ -71,11 +71,13 @@ EOF
|
||||
}
|
||||
|
||||
$helper = new DescriptorHelper();
|
||||
$helper->describe($output, $this->command, array(
|
||||
$helper->describe($output, $this->command, [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
));
|
||||
]);
|
||||
|
||||
$this->command = null;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
17
vendor/symfony/console/Command/ListCommand.php
vendored
17
vendor/symfony/console/Command/ListCommand.php
vendored
@@ -33,7 +33,7 @@ class ListCommand extends Command
|
||||
$this
|
||||
->setName('list')
|
||||
->setDefinition($this->createDefinition())
|
||||
->setDescription('Lists commands')
|
||||
->setDescription('List commands')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command lists all commands:
|
||||
|
||||
@@ -69,22 +69,21 @@ EOF
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$helper = new DescriptorHelper();
|
||||
$helper->describe($output, $this->getApplication(), array(
|
||||
$helper->describe($output, $this->getApplication(), [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'namespace' => $input->getArgument('namespace'),
|
||||
));
|
||||
]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function createDefinition()
|
||||
private function createDefinition(): InputDefinition
|
||||
{
|
||||
return new InputDefinition(array(
|
||||
return new InputDefinition([
|
||||
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
|
||||
));
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -12,8 +12,8 @@
|
||||
namespace Symfony\Component\Console\Command;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Lock\Factory;
|
||||
use Symfony\Component\Lock\Lock;
|
||||
use Symfony\Component\Lock\LockFactory;
|
||||
use Symfony\Component\Lock\Store\FlockStore;
|
||||
use Symfony\Component\Lock\Store\SemaphoreStore;
|
||||
|
||||
@@ -29,10 +29,8 @@ trait LockableTrait
|
||||
|
||||
/**
|
||||
* Locks a command.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function lock($name = null, $blocking = false)
|
||||
private function lock(string $name = null, bool $blocking = false): bool
|
||||
{
|
||||
if (!class_exists(SemaphoreStore::class)) {
|
||||
throw new LogicException('To enable the locking feature you must install the symfony/lock component.');
|
||||
@@ -48,7 +46,7 @@ trait LockableTrait
|
||||
$store = new FlockStore();
|
||||
}
|
||||
|
||||
$this->lock = (new Factory($store))->createLock($name ?: $this->getName());
|
||||
$this->lock = (new LockFactory($store))->createLock($name ?: $this->getName());
|
||||
if (!$this->lock->acquire($blocking)) {
|
||||
$this->lock = null;
|
||||
|
||||
|
@@ -1,5 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\CommandLoader;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
@@ -1,5 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\CommandLoader;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
@@ -16,8 +25,7 @@ class ContainerCommandLoader implements CommandLoaderInterface
|
||||
private $commandMap;
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container A container from which to load command services
|
||||
* @param array $commandMap An array with command names as keys and service ids as values
|
||||
* @param array $commandMap An array with command names as keys and service ids as values
|
||||
*/
|
||||
public function __construct(ContainerInterface $container, array $commandMap)
|
||||
{
|
||||
|
8
vendor/symfony/console/ConsoleEvents.php
vendored
8
vendor/symfony/console/ConsoleEvents.php
vendored
@@ -21,11 +21,11 @@ final class ConsoleEvents
|
||||
/**
|
||||
* The COMMAND event allows you to attach listeners before any command is
|
||||
* executed by the console. It also allows you to modify the command, input and output
|
||||
* before they are handled to the command.
|
||||
* before they are handed to the command.
|
||||
*
|
||||
* @Event("Symfony\Component\Console\Event\ConsoleCommandEvent")
|
||||
*/
|
||||
const COMMAND = 'console.command';
|
||||
public const COMMAND = 'console.command';
|
||||
|
||||
/**
|
||||
* The TERMINATE event allows you to attach listeners after a command is
|
||||
@@ -33,7 +33,7 @@ final class ConsoleEvents
|
||||
*
|
||||
* @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent")
|
||||
*/
|
||||
const TERMINATE = 'console.terminate';
|
||||
public const TERMINATE = 'console.terminate';
|
||||
|
||||
/**
|
||||
* The ERROR event occurs when an uncaught exception or error appears.
|
||||
@@ -43,5 +43,5 @@ final class ConsoleEvents
|
||||
*
|
||||
* @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
|
||||
*/
|
||||
const ERROR = 'console.error';
|
||||
public const ERROR = 'console.error';
|
||||
}
|
||||
|
@@ -38,9 +38,9 @@ class AddConsoleCommandPass implements CompilerPassInterface
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$commandServices = $container->findTaggedServiceIds($this->commandTag, true);
|
||||
$lazyCommandMap = array();
|
||||
$lazyCommandRefs = array();
|
||||
$serviceIds = array();
|
||||
$lazyCommandMap = [];
|
||||
$lazyCommandRefs = [];
|
||||
$serviceIds = [];
|
||||
|
||||
foreach ($commandServices as $id => $tags) {
|
||||
$definition = $container->getDefinition($id);
|
||||
@@ -55,7 +55,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
|
||||
if (!$r->isSubclassOf(Command::class)) {
|
||||
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
|
||||
}
|
||||
$commandName = $class::getDefaultName();
|
||||
$commandName = null !== $class::getDefaultName() ? str_replace('%', '%%', $class::getDefaultName()) : null;
|
||||
}
|
||||
|
||||
if (null === $commandName) {
|
||||
@@ -72,7 +72,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
|
||||
unset($tags[0]);
|
||||
$lazyCommandMap[$commandName] = $id;
|
||||
$lazyCommandRefs[$id] = new TypedReference($id, $class);
|
||||
$aliases = array();
|
||||
$aliases = [];
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
if (isset($tag['command'])) {
|
||||
@@ -81,17 +81,17 @@ class AddConsoleCommandPass implements CompilerPassInterface
|
||||
}
|
||||
}
|
||||
|
||||
$definition->addMethodCall('setName', array($commandName));
|
||||
$definition->addMethodCall('setName', [$commandName]);
|
||||
|
||||
if ($aliases) {
|
||||
$definition->addMethodCall('setAliases', array($aliases));
|
||||
$definition->addMethodCall('setAliases', [$aliases]);
|
||||
}
|
||||
}
|
||||
|
||||
$container
|
||||
->register($this->commandLoaderServiceId, ContainerCommandLoader::class)
|
||||
->setPublic(true)
|
||||
->setArguments(array(ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap));
|
||||
->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
|
||||
|
||||
$container->setParameter('console.command.ids', $serviceIds);
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ use Symfony\Component\Console\Exception\CommandNotFoundException;
|
||||
*/
|
||||
class ApplicationDescription
|
||||
{
|
||||
const GLOBAL_NAMESPACE = '_global';
|
||||
public const GLOBAL_NAMESPACE = '_global';
|
||||
|
||||
private $application;
|
||||
private $namespace;
|
||||
@@ -50,10 +50,7 @@ class ApplicationDescription
|
||||
$this->showHidden = $showHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getNamespaces()
|
||||
public function getNamespaces(): array
|
||||
{
|
||||
if (null === $this->namespaces) {
|
||||
$this->inspectApplication();
|
||||
@@ -65,7 +62,7 @@ class ApplicationDescription
|
||||
/**
|
||||
* @return Command[]
|
||||
*/
|
||||
public function getCommands()
|
||||
public function getCommands(): array
|
||||
{
|
||||
if (null === $this->commands) {
|
||||
$this->inspectApplication();
|
||||
@@ -75,29 +72,25 @@ class ApplicationDescription
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Command
|
||||
*
|
||||
* @throws CommandNotFoundException
|
||||
*/
|
||||
public function getCommand($name)
|
||||
public function getCommand(string $name): Command
|
||||
{
|
||||
if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
|
||||
throw new CommandNotFoundException(sprintf('Command %s does not exist.', $name));
|
||||
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
|
||||
return $this->commands[$name] ?? $this->aliases[$name];
|
||||
}
|
||||
|
||||
private function inspectApplication()
|
||||
{
|
||||
$this->commands = array();
|
||||
$this->namespaces = array();
|
||||
$this->commands = [];
|
||||
$this->namespaces = [];
|
||||
|
||||
$all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
|
||||
foreach ($this->sortCommands($all) as $namespace => $commands) {
|
||||
$names = array();
|
||||
$names = [];
|
||||
|
||||
/** @var Command $command */
|
||||
foreach ($commands as $name => $command) {
|
||||
@@ -114,31 +107,37 @@ class ApplicationDescription
|
||||
$names[] = $name;
|
||||
}
|
||||
|
||||
$this->namespaces[$namespace] = array('id' => $namespace, 'commands' => $names);
|
||||
$this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names];
|
||||
}
|
||||
}
|
||||
|
||||
private function sortCommands(array $commands): array
|
||||
{
|
||||
$namespacedCommands = array();
|
||||
$globalCommands = array();
|
||||
$namespacedCommands = [];
|
||||
$globalCommands = [];
|
||||
$sortedCommands = [];
|
||||
foreach ($commands as $name => $command) {
|
||||
$key = $this->application->extractNamespace($name, 1);
|
||||
if (!$key) {
|
||||
$globalCommands['_global'][$name] = $command;
|
||||
if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) {
|
||||
$globalCommands[$name] = $command;
|
||||
} else {
|
||||
$namespacedCommands[$key][$name] = $command;
|
||||
}
|
||||
}
|
||||
ksort($namespacedCommands);
|
||||
$namespacedCommands = array_merge($globalCommands, $namespacedCommands);
|
||||
|
||||
foreach ($namespacedCommands as &$commandsSet) {
|
||||
ksort($commandsSet);
|
||||
if ($globalCommands) {
|
||||
ksort($globalCommands);
|
||||
$sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands;
|
||||
}
|
||||
// unset reference to keep scope clear
|
||||
unset($commandsSet);
|
||||
|
||||
return $namespacedCommands;
|
||||
if ($namespacedCommands) {
|
||||
ksort($namespacedCommands, \SORT_STRING);
|
||||
foreach ($namespacedCommands as $key => $commandsSet) {
|
||||
ksort($commandsSet);
|
||||
$sortedCommands[$key] = $commandsSet;
|
||||
}
|
||||
}
|
||||
|
||||
return $sortedCommands;
|
||||
}
|
||||
}
|
||||
|
22
vendor/symfony/console/Descriptor/Descriptor.php
vendored
22
vendor/symfony/console/Descriptor/Descriptor.php
vendored
@@ -34,7 +34,7 @@ abstract class Descriptor implements DescriptorInterface
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function describe(OutputInterface $output, $object, array $options = array())
|
||||
public function describe(OutputInterface $output, $object, array $options = [])
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
@@ -72,36 +72,26 @@ abstract class Descriptor implements DescriptorInterface
|
||||
|
||||
/**
|
||||
* Describes an InputArgument instance.
|
||||
*
|
||||
* @return string|mixed
|
||||
*/
|
||||
abstract protected function describeInputArgument(InputArgument $argument, array $options = array());
|
||||
abstract protected function describeInputArgument(InputArgument $argument, array $options = []);
|
||||
|
||||
/**
|
||||
* Describes an InputOption instance.
|
||||
*
|
||||
* @return string|mixed
|
||||
*/
|
||||
abstract protected function describeInputOption(InputOption $option, array $options = array());
|
||||
abstract protected function describeInputOption(InputOption $option, array $options = []);
|
||||
|
||||
/**
|
||||
* Describes an InputDefinition instance.
|
||||
*
|
||||
* @return string|mixed
|
||||
*/
|
||||
abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array());
|
||||
abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []);
|
||||
|
||||
/**
|
||||
* Describes a Command instance.
|
||||
*
|
||||
* @return string|mixed
|
||||
*/
|
||||
abstract protected function describeCommand(Command $command, array $options = array());
|
||||
abstract protected function describeCommand(Command $command, array $options = []);
|
||||
|
||||
/**
|
||||
* Describes an Application instance.
|
||||
*
|
||||
* @return string|mixed
|
||||
*/
|
||||
abstract protected function describeApplication(Application $application, array $options = array());
|
||||
abstract protected function describeApplication(Application $application, array $options = []);
|
||||
}
|
||||
|
@@ -23,9 +23,7 @@ interface DescriptorInterface
|
||||
/**
|
||||
* Describes an object if supported.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param object $object
|
||||
* @param array $options
|
||||
* @param object $object
|
||||
*/
|
||||
public function describe(OutputInterface $output, $object, array $options = array());
|
||||
public function describe(OutputInterface $output, $object, array $options = []);
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ class JsonDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = array())
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = [])
|
||||
{
|
||||
$this->writeData($this->getInputArgumentData($argument), $options);
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class JsonDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputOption(InputOption $option, array $options = array())
|
||||
protected function describeInputOption(InputOption $option, array $options = [])
|
||||
{
|
||||
$this->writeData($this->getInputOptionData($option), $options);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class JsonDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = array())
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
|
||||
{
|
||||
$this->writeData($this->getInputDefinitionData($definition), $options);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class JsonDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeCommand(Command $command, array $options = array())
|
||||
protected function describeCommand(Command $command, array $options = [])
|
||||
{
|
||||
$this->writeData($this->getCommandData($command), $options);
|
||||
}
|
||||
@@ -61,17 +61,17 @@ class JsonDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeApplication(Application $application, array $options = array())
|
||||
protected function describeApplication(Application $application, array $options = [])
|
||||
{
|
||||
$describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
|
||||
$describedNamespace = $options['namespace'] ?? null;
|
||||
$description = new ApplicationDescription($application, $describedNamespace, true);
|
||||
$commands = array();
|
||||
$commands = [];
|
||||
|
||||
foreach ($description->getCommands() as $command) {
|
||||
$commands[] = $this->getCommandData($command);
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data = [];
|
||||
if ('UNKNOWN' !== $application->getName()) {
|
||||
$data['application']['name'] = $application->getName();
|
||||
if ('UNKNOWN' !== $application->getVersion()) {
|
||||
@@ -92,77 +92,65 @@ class JsonDescriptor extends Descriptor
|
||||
|
||||
/**
|
||||
* Writes data as json.
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
private function writeData(array $data, array $options)
|
||||
{
|
||||
$this->write(json_encode($data, isset($options['json_encoding']) ? $options['json_encoding'] : 0));
|
||||
$flags = $options['json_encoding'] ?? 0;
|
||||
|
||||
$this->write(json_encode($data, $flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getInputArgumentData(InputArgument $argument)
|
||||
private function getInputArgumentData(InputArgument $argument): array
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'name' => $argument->getName(),
|
||||
'is_required' => $argument->isRequired(),
|
||||
'is_array' => $argument->isArray(),
|
||||
'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $argument->getDescription()),
|
||||
'default' => INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
|
||||
);
|
||||
'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getInputOptionData(InputOption $option)
|
||||
private function getInputOptionData(InputOption $option): array
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'name' => '--'.$option->getName(),
|
||||
'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
|
||||
'accept_value' => $option->acceptValue(),
|
||||
'is_value_required' => $option->isValueRequired(),
|
||||
'is_multiple' => $option->isArray(),
|
||||
'description' => preg_replace('/\s*[\r\n]\s*/', ' ', $option->getDescription()),
|
||||
'default' => INF === $option->getDefault() ? 'INF' : $option->getDefault(),
|
||||
);
|
||||
'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getInputDefinitionData(InputDefinition $definition)
|
||||
private function getInputDefinitionData(InputDefinition $definition): array
|
||||
{
|
||||
$inputArguments = array();
|
||||
$inputArguments = [];
|
||||
foreach ($definition->getArguments() as $name => $argument) {
|
||||
$inputArguments[$name] = $this->getInputArgumentData($argument);
|
||||
}
|
||||
|
||||
$inputOptions = array();
|
||||
$inputOptions = [];
|
||||
foreach ($definition->getOptions() as $name => $option) {
|
||||
$inputOptions[$name] = $this->getInputOptionData($option);
|
||||
}
|
||||
|
||||
return array('arguments' => $inputArguments, 'options' => $inputOptions);
|
||||
return ['arguments' => $inputArguments, 'options' => $inputOptions];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getCommandData(Command $command)
|
||||
private function getCommandData(Command $command): array
|
||||
{
|
||||
$command->getSynopsis();
|
||||
$command->mergeApplicationDefinition(false);
|
||||
|
||||
return array(
|
||||
return [
|
||||
'name' => $command->getName(),
|
||||
'usage' => array_merge(array($command->getSynopsis()), $command->getUsages(), $command->getAliases()),
|
||||
'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
|
||||
'description' => $command->getDescription(),
|
||||
'help' => $command->getProcessedHelp(),
|
||||
'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
|
||||
'hidden' => $command->isHidden(),
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function describe(OutputInterface $output, $object, array $options = array())
|
||||
public function describe(OutputInterface $output, $object, array $options = [])
|
||||
{
|
||||
$decorated = $output->isDecorated();
|
||||
$output->setDecorated(false);
|
||||
@@ -52,7 +52,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = array())
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = [])
|
||||
{
|
||||
$this->write(
|
||||
'#### `'.($argument->getName() ?: '<none>')."`\n\n"
|
||||
@@ -66,7 +66,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputOption(InputOption $option, array $options = array())
|
||||
protected function describeInputOption(InputOption $option, array $options = [])
|
||||
{
|
||||
$name = '--'.$option->getName();
|
||||
if ($option->getShortcut()) {
|
||||
@@ -86,7 +86,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = array())
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
|
||||
{
|
||||
if ($showArguments = \count($definition->getArguments()) > 0) {
|
||||
$this->write('### Arguments');
|
||||
@@ -112,7 +112,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeCommand(Command $command, array $options = array())
|
||||
protected function describeCommand(Command $command, array $options = [])
|
||||
{
|
||||
$command->getSynopsis();
|
||||
$command->mergeApplicationDefinition(false);
|
||||
@@ -122,7 +122,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
.str_repeat('-', Helper::strlen($command->getName()) + 2)."\n\n"
|
||||
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
|
||||
.'### Usage'."\n\n"
|
||||
.array_reduce(array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
|
||||
.array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
|
||||
return $carry.'* `'.$usage.'`'."\n";
|
||||
})
|
||||
);
|
||||
@@ -141,9 +141,9 @@ class MarkdownDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeApplication(Application $application, array $options = array())
|
||||
protected function describeApplication(Application $application, array $options = [])
|
||||
{
|
||||
$describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
|
||||
$describedNamespace = $options['namespace'] ?? null;
|
||||
$description = new ApplicationDescription($application, $describedNamespace);
|
||||
$title = $this->getApplicationTitle($application);
|
||||
|
||||
@@ -167,7 +167,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
}
|
||||
}
|
||||
|
||||
private function getApplicationTitle(Application $application)
|
||||
private function getApplicationTitle(Application $application): string
|
||||
{
|
||||
if ('UNKNOWN' !== $application->getName()) {
|
||||
if ('UNKNOWN' !== $application->getVersion()) {
|
||||
|
@@ -31,7 +31,7 @@ class TextDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = array())
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = [])
|
||||
{
|
||||
if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) {
|
||||
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($argument->getDefault()));
|
||||
@@ -39,7 +39,7 @@ class TextDescriptor extends Descriptor
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$totalWidth = isset($options['total_width']) ? $options['total_width'] : Helper::strlen($argument->getName());
|
||||
$totalWidth = $options['total_width'] ?? Helper::strlen($argument->getName());
|
||||
$spacingWidth = $totalWidth - \strlen($argument->getName());
|
||||
|
||||
$this->writeText(sprintf(' <info>%s</info> %s%s%s',
|
||||
@@ -54,7 +54,7 @@ class TextDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputOption(InputOption $option, array $options = array())
|
||||
protected function describeInputOption(InputOption $option, array $options = [])
|
||||
{
|
||||
if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) {
|
||||
$default = sprintf('<comment> [default: %s]</comment>', $this->formatDefaultValue($option->getDefault()));
|
||||
@@ -71,7 +71,7 @@ class TextDescriptor extends Descriptor
|
||||
}
|
||||
}
|
||||
|
||||
$totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions(array($option));
|
||||
$totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
|
||||
$synopsis = sprintf('%s%s',
|
||||
$option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ',
|
||||
sprintf('--%s%s', $option->getName(), $value)
|
||||
@@ -92,7 +92,7 @@ class TextDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = array())
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
|
||||
{
|
||||
$totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
|
||||
foreach ($definition->getArguments() as $argument) {
|
||||
@@ -103,7 +103,7 @@ class TextDescriptor extends Descriptor
|
||||
$this->writeText('<comment>Arguments:</comment>', $options);
|
||||
$this->writeText("\n");
|
||||
foreach ($definition->getArguments() as $argument) {
|
||||
$this->describeInputArgument($argument, array_merge($options, array('total_width' => $totalWidth)));
|
||||
$this->describeInputArgument($argument, array_merge($options, ['total_width' => $totalWidth]));
|
||||
$this->writeText("\n");
|
||||
}
|
||||
}
|
||||
@@ -113,20 +113,20 @@ class TextDescriptor extends Descriptor
|
||||
}
|
||||
|
||||
if ($definition->getOptions()) {
|
||||
$laterOptions = array();
|
||||
$laterOptions = [];
|
||||
|
||||
$this->writeText('<comment>Options:</comment>', $options);
|
||||
foreach ($definition->getOptions() as $option) {
|
||||
if (\strlen($option->getShortcut()) > 1) {
|
||||
if (\strlen($option->getShortcut() ?? '') > 1) {
|
||||
$laterOptions[] = $option;
|
||||
continue;
|
||||
}
|
||||
$this->writeText("\n");
|
||||
$this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
|
||||
$this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
|
||||
}
|
||||
foreach ($laterOptions as $option) {
|
||||
$this->writeText("\n");
|
||||
$this->describeInputOption($option, array_merge($options, array('total_width' => $totalWidth)));
|
||||
$this->describeInputOption($option, array_merge($options, ['total_width' => $totalWidth]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ class TextDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeCommand(Command $command, array $options = array())
|
||||
protected function describeCommand(Command $command, array $options = [])
|
||||
{
|
||||
$command->getSynopsis(true);
|
||||
$command->getSynopsis(false);
|
||||
@@ -148,7 +148,7 @@ class TextDescriptor extends Descriptor
|
||||
}
|
||||
|
||||
$this->writeText('<comment>Usage:</comment>', $options);
|
||||
foreach (array_merge(array($command->getSynopsis(true)), $command->getAliases(), $command->getUsages()) as $usage) {
|
||||
foreach (array_merge([$command->getSynopsis(true)], $command->getAliases(), $command->getUsages()) as $usage) {
|
||||
$this->writeText("\n");
|
||||
$this->writeText(' '.OutputFormatter::escape($usage), $options);
|
||||
}
|
||||
@@ -174,9 +174,9 @@ class TextDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeApplication(Application $application, array $options = array())
|
||||
protected function describeApplication(Application $application, array $options = [])
|
||||
{
|
||||
$describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
|
||||
$describedNamespace = $options['namespace'] ?? null;
|
||||
$description = new ApplicationDescription($application, $describedNamespace);
|
||||
|
||||
if (isset($options['raw_text']) && $options['raw_text']) {
|
||||
@@ -212,7 +212,7 @@ class TextDescriptor extends Descriptor
|
||||
// calculate max. width based on available commands per namespace
|
||||
$width = $this->getColumnWidth(array_merge(...array_values(array_map(function ($namespace) use ($commands) {
|
||||
return array_intersect($namespace['commands'], array_keys($commands));
|
||||
}, $namespaces))));
|
||||
}, array_values($namespaces)))));
|
||||
|
||||
if ($describedNamespace) {
|
||||
$this->writeText(sprintf('<comment>Available commands for the "%s" namespace:</comment>', $describedNamespace), $options);
|
||||
@@ -250,7 +250,7 @@ class TextDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function writeText($content, array $options = array())
|
||||
private function writeText(string $content, array $options = [])
|
||||
{
|
||||
$this->write(
|
||||
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
|
||||
@@ -280,7 +280,7 @@ class TextDescriptor extends Descriptor
|
||||
*/
|
||||
private function formatDefaultValue($default): string
|
||||
{
|
||||
if (INF === $default) {
|
||||
if (\INF === $default) {
|
||||
return 'INF';
|
||||
}
|
||||
|
||||
@@ -294,15 +294,15 @@ class TextDescriptor extends Descriptor
|
||||
}
|
||||
}
|
||||
|
||||
return str_replace('\\\\', '\\', json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||
return str_replace('\\\\', '\\', json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param (Command|string)[] $commands
|
||||
* @param array<Command|string> $commands
|
||||
*/
|
||||
private function getColumnWidth(array $commands): int
|
||||
{
|
||||
$widths = array();
|
||||
$widths = [];
|
||||
|
||||
foreach ($commands as $command) {
|
||||
if ($command instanceof Command) {
|
||||
|
@@ -26,10 +26,7 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
*/
|
||||
class XmlDescriptor extends Descriptor
|
||||
{
|
||||
/**
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public function getInputDefinitionDocument(InputDefinition $definition)
|
||||
public function getInputDefinitionDocument(InputDefinition $definition): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($definitionXML = $dom->createElement('definition'));
|
||||
@@ -47,10 +44,7 @@ class XmlDescriptor extends Descriptor
|
||||
return $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public function getCommandDocument(Command $command)
|
||||
public function getCommandDocument(Command $command): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($commandXML = $dom->createElement('command'));
|
||||
@@ -64,7 +58,7 @@ class XmlDescriptor extends Descriptor
|
||||
|
||||
$commandXML->appendChild($usagesXML = $dom->createElement('usages'));
|
||||
|
||||
foreach (array_merge(array($command->getSynopsis()), $command->getAliases(), $command->getUsages()) as $usage) {
|
||||
foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
|
||||
$usagesXML->appendChild($dom->createElement('usage', $usage));
|
||||
}
|
||||
|
||||
@@ -80,13 +74,7 @@ class XmlDescriptor extends Descriptor
|
||||
return $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Application $application
|
||||
* @param string|null $namespace
|
||||
*
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public function getApplicationDocument(Application $application, $namespace = null)
|
||||
public function getApplicationDocument(Application $application, string $namespace = null): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($rootXml = $dom->createElement('symfony'));
|
||||
@@ -130,7 +118,7 @@ class XmlDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = array())
|
||||
protected function describeInputArgument(InputArgument $argument, array $options = [])
|
||||
{
|
||||
$this->writeDocument($this->getInputArgumentDocument($argument));
|
||||
}
|
||||
@@ -138,7 +126,7 @@ class XmlDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputOption(InputOption $option, array $options = array())
|
||||
protected function describeInputOption(InputOption $option, array $options = [])
|
||||
{
|
||||
$this->writeDocument($this->getInputOptionDocument($option));
|
||||
}
|
||||
@@ -146,7 +134,7 @@ class XmlDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = array())
|
||||
protected function describeInputDefinition(InputDefinition $definition, array $options = [])
|
||||
{
|
||||
$this->writeDocument($this->getInputDefinitionDocument($definition));
|
||||
}
|
||||
@@ -154,7 +142,7 @@ class XmlDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeCommand(Command $command, array $options = array())
|
||||
protected function describeCommand(Command $command, array $options = [])
|
||||
{
|
||||
$this->writeDocument($this->getCommandDocument($command));
|
||||
}
|
||||
@@ -162,9 +150,9 @@ class XmlDescriptor extends Descriptor
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function describeApplication(Application $application, array $options = array())
|
||||
protected function describeApplication(Application $application, array $options = [])
|
||||
{
|
||||
$this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null));
|
||||
$this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,8 +167,6 @@ class XmlDescriptor extends Descriptor
|
||||
|
||||
/**
|
||||
* Writes DOM document.
|
||||
*
|
||||
* @return \DOMDocument|string
|
||||
*/
|
||||
private function writeDocument(\DOMDocument $dom)
|
||||
{
|
||||
@@ -200,7 +186,7 @@ class XmlDescriptor extends Descriptor
|
||||
$descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
|
||||
|
||||
$objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
$defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
|
||||
$defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [var_export($argument->getDefault(), true)] : ($argument->getDefault() ? [$argument->getDefault()] : []));
|
||||
foreach ($defaults as $default) {
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->appendChild($dom->createTextNode($default));
|
||||
@@ -215,7 +201,7 @@ class XmlDescriptor extends Descriptor
|
||||
|
||||
$dom->appendChild($objectXML = $dom->createElement('option'));
|
||||
$objectXML->setAttribute('name', '--'.$option->getName());
|
||||
$pos = strpos($option->getShortcut(), '|');
|
||||
$pos = strpos($option->getShortcut() ?? '', '|');
|
||||
if (false !== $pos) {
|
||||
$objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
|
||||
$objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
|
||||
@@ -229,7 +215,7 @@ class XmlDescriptor extends Descriptor
|
||||
$descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
|
||||
|
||||
if ($option->acceptValue()) {
|
||||
$defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
|
||||
$defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : []));
|
||||
$objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
|
||||
if (!empty($defaults)) {
|
||||
|
@@ -15,13 +15,15 @@ namespace Symfony\Component\Console\Event;
|
||||
* Allows to do things before the command is executed, like skipping the command or changing the input.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final since Symfony 4.4
|
||||
*/
|
||||
class ConsoleCommandEvent extends ConsoleEvent
|
||||
{
|
||||
/**
|
||||
* The return code for skipped commands, this will also be passed into the terminate event.
|
||||
*/
|
||||
const RETURN_CODE_DISABLED = 113;
|
||||
public const RETURN_CODE_DISABLED = 113;
|
||||
|
||||
/**
|
||||
* Indicates if the command should be run or skipped.
|
||||
|
@@ -53,6 +53,6 @@ final class ConsoleErrorEvent extends ConsoleEvent
|
||||
|
||||
public function getExitCode(): int
|
||||
{
|
||||
return null !== $this->exitCode ? $this->exitCode : (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
|
||||
return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1);
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class ConsoleEvent extends Event
|
||||
private $input;
|
||||
private $output;
|
||||
|
||||
public function __construct(Command $command = null, InputInterface $input, OutputInterface $output)
|
||||
public function __construct(?Command $command, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->command = $command;
|
||||
$this->input = $input;
|
||||
|
@@ -19,6 +19,8 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
* Allows to manipulate the exit code of a command after its execution.
|
||||
*
|
||||
* @author Francesco Levorato <git@flevour.net>
|
||||
*
|
||||
* @final since Symfony 4.4
|
||||
*/
|
||||
class ConsoleTerminateEvent extends ConsoleEvent
|
||||
{
|
||||
|
@@ -40,10 +40,12 @@ class ErrorListener implements EventSubscriberInterface
|
||||
$error = $event->getError();
|
||||
|
||||
if (!$inputString = $this->getInputString($event)) {
|
||||
return $this->logger->error('An error occurred while using the console. Message: "{message}"', array('exception' => $error, 'message' => $error->getMessage()));
|
||||
$this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->error('Error thrown while running command "{command}". Message: "{message}"', array('exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()));
|
||||
$this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]);
|
||||
}
|
||||
|
||||
public function onConsoleTerminate(ConsoleTerminateEvent $event)
|
||||
@@ -59,28 +61,30 @@ class ErrorListener implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
if (!$inputString = $this->getInputString($event)) {
|
||||
return $this->logger->debug('The console exited with code "{code}"', array('code' => $exitCode));
|
||||
$this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->debug('Command "{command}" exited with code "{code}"', array('command' => $inputString, 'code' => $exitCode));
|
||||
$this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
ConsoleEvents::ERROR => array('onConsoleError', -128),
|
||||
ConsoleEvents::TERMINATE => array('onConsoleTerminate', -128),
|
||||
);
|
||||
return [
|
||||
ConsoleEvents::ERROR => ['onConsoleError', -128],
|
||||
ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128],
|
||||
];
|
||||
}
|
||||
|
||||
private static function getInputString(ConsoleEvent $event)
|
||||
private static function getInputString(ConsoleEvent $event): ?string
|
||||
{
|
||||
$commandName = $event->getCommand() ? $event->getCommand()->getName() : null;
|
||||
$input = $event->getInput();
|
||||
|
||||
if (method_exists($input, '__toString')) {
|
||||
if ($commandName) {
|
||||
return str_replace(array("'$commandName'", "\"$commandName\""), $commandName, (string) $input);
|
||||
return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input);
|
||||
}
|
||||
|
||||
return (string) $input;
|
||||
|
@@ -21,12 +21,12 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce
|
||||
private $alternatives;
|
||||
|
||||
/**
|
||||
* @param string $message Exception message to throw
|
||||
* @param array $alternatives List of similar defined names
|
||||
* @param int $code Exception code
|
||||
* @param \Exception $previous Previous exception used for the exception chaining
|
||||
* @param string $message Exception message to throw
|
||||
* @param string[] $alternatives List of similar defined names
|
||||
* @param int $code Exception code
|
||||
* @param \Throwable|null $previous Previous exception used for the exception chaining
|
||||
*/
|
||||
public function __construct(string $message, array $alternatives = array(), int $code = 0, \Exception $previous = null)
|
||||
public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
@@ -34,7 +34,7 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array A list of similar defined names
|
||||
* @return string[] A list of similar defined names
|
||||
*/
|
||||
public function getAlternatives()
|
||||
{
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace Symfony\Component\Console\Exception;
|
||||
|
||||
/**
|
||||
* Represents an incorrect option name typed in the console.
|
||||
* Represents an incorrect option name or value typed in the console.
|
||||
*
|
||||
* @author Jérôme Tamarelle <jerome@tamarelle.net>
|
||||
*/
|
||||
|
21
vendor/symfony/console/Exception/MissingInputException.php
vendored
Normal file
21
vendor/symfony/console/Exception/MissingInputException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Exception;
|
||||
|
||||
/**
|
||||
* Represents failure to read input from stdin.
|
||||
*
|
||||
* @author Gabriel Ostrolucký <gabriel.ostrolucky@gmail.com>
|
||||
*/
|
||||
class MissingInputException extends RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
@@ -22,11 +22,19 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
{
|
||||
private $decorated;
|
||||
private $styles = array();
|
||||
private $styles = [];
|
||||
private $styleStack;
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->styleStack = clone $this->styleStack;
|
||||
foreach ($this->styles as $key => $value) {
|
||||
$this->styles[$key] = clone $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes "<" special char in given text.
|
||||
* Escapes "<" and ">" special chars in given text.
|
||||
*
|
||||
* @param string $text Text to escape
|
||||
*
|
||||
@@ -34,7 +42,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
*/
|
||||
public static function escape($text)
|
||||
{
|
||||
$text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
|
||||
$text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);
|
||||
|
||||
return self::escapeTrailingBackslash($text);
|
||||
}
|
||||
@@ -42,15 +50,11 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
/**
|
||||
* Escapes trailing "\" in given text.
|
||||
*
|
||||
* @param string $text Text to escape
|
||||
*
|
||||
* @return string Escaped text
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function escapeTrailingBackslash($text)
|
||||
public static function escapeTrailingBackslash(string $text): string
|
||||
{
|
||||
if ('\\' === substr($text, -1)) {
|
||||
if (str_ends_with($text, '\\')) {
|
||||
$len = \strlen($text);
|
||||
$text = rtrim($text, '\\');
|
||||
$text = str_replace("\0", '', $text);
|
||||
@@ -63,10 +67,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
/**
|
||||
* Initializes console output formatter.
|
||||
*
|
||||
* @param bool $decorated Whether this formatter should actually decorate strings
|
||||
* @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
|
||||
* @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
|
||||
*/
|
||||
public function __construct(bool $decorated = false, array $styles = array())
|
||||
public function __construct(bool $decorated = false, array $styles = [])
|
||||
{
|
||||
$this->decorated = $decorated;
|
||||
|
||||
@@ -120,7 +123,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
public function getStyle($name)
|
||||
{
|
||||
if (!$this->hasStyle($name)) {
|
||||
throw new InvalidArgumentException(sprintf('Undefined style: %s', $name));
|
||||
throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
|
||||
}
|
||||
|
||||
return $this->styles[strtolower($name)];
|
||||
@@ -141,9 +144,10 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
{
|
||||
$offset = 0;
|
||||
$output = '';
|
||||
$tagRegex = '[a-z][a-z0-9,_=;-]*+';
|
||||
$openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
|
||||
$closeTagRegex = '[a-z][^<>]*+';
|
||||
$currentLineLength = 0;
|
||||
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
|
||||
preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
|
||||
foreach ($matches[0] as $i => $match) {
|
||||
$pos = $match[1];
|
||||
$text = $match[0];
|
||||
@@ -160,13 +164,13 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
if ($open = '/' != $text[1]) {
|
||||
$tag = $matches[1][$i][0];
|
||||
} else {
|
||||
$tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
|
||||
$tag = $matches[3][$i][0] ?? '';
|
||||
}
|
||||
|
||||
if (!$open && !$tag) {
|
||||
// </>
|
||||
$this->styleStack->pop();
|
||||
} elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
|
||||
} elseif (null === $style = $this->createStyleFromString($tag)) {
|
||||
$output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
|
||||
} elseif ($open) {
|
||||
$this->styleStack->push($style);
|
||||
@@ -177,11 +181,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
|
||||
$output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength);
|
||||
|
||||
if (false !== strpos($output, "\0")) {
|
||||
return strtr($output, array("\0" => '\\', '\\<' => '<'));
|
||||
}
|
||||
|
||||
return str_replace('\\<', '<', $output);
|
||||
return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,35 +194,37 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
|
||||
/**
|
||||
* Tries to create new style instance from string.
|
||||
*
|
||||
* @return OutputFormatterStyle|false False if string is not format string
|
||||
*/
|
||||
private function createStyleFromString(string $string)
|
||||
private function createStyleFromString(string $string): ?OutputFormatterStyleInterface
|
||||
{
|
||||
if (isset($this->styles[$string])) {
|
||||
return $this->styles[$string];
|
||||
}
|
||||
|
||||
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, PREG_SET_ORDER)) {
|
||||
return false;
|
||||
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$style = new OutputFormatterStyle();
|
||||
foreach ($matches as $match) {
|
||||
array_shift($match);
|
||||
$match[0] = strtolower($match[0]);
|
||||
|
||||
if ('fg' == $match[0]) {
|
||||
$style->setForeground($match[1]);
|
||||
$style->setForeground(strtolower($match[1]));
|
||||
} elseif ('bg' == $match[0]) {
|
||||
$style->setBackground($match[1]);
|
||||
$style->setBackground(strtolower($match[1]));
|
||||
} elseif ('href' === $match[0]) {
|
||||
$url = preg_replace('{\\\\([<>])}', '$1', $match[1]);
|
||||
$style->setHref($url);
|
||||
} elseif ('options' === $match[0]) {
|
||||
preg_match_all('([^,;]+)', $match[1], $options);
|
||||
preg_match_all('([^,;]+)', strtolower($match[1]), $options);
|
||||
$options = array_shift($options);
|
||||
foreach ($options as $option) {
|
||||
$style->setOption($option);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,8 +264,12 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
||||
}
|
||||
|
||||
$lines = explode("\n", $text);
|
||||
if ($width === $currentLineLength = \strlen(end($lines))) {
|
||||
$currentLineLength = 0;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$currentLineLength += \strlen($line);
|
||||
if ($width <= $currentLineLength) {
|
||||
$currentLineLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isDecorated()) {
|
||||
|
@@ -35,8 +35,7 @@ interface OutputFormatterInterface
|
||||
/**
|
||||
* Sets a new style.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param OutputFormatterStyleInterface $style The style instance
|
||||
* @param string $name The style name
|
||||
*/
|
||||
public function setStyle($name, OutputFormatterStyleInterface $style);
|
||||
|
||||
|
@@ -20,48 +20,49 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
{
|
||||
private static $availableForegroundColors = array(
|
||||
'black' => array('set' => 30, 'unset' => 39),
|
||||
'red' => array('set' => 31, 'unset' => 39),
|
||||
'green' => array('set' => 32, 'unset' => 39),
|
||||
'yellow' => array('set' => 33, 'unset' => 39),
|
||||
'blue' => array('set' => 34, 'unset' => 39),
|
||||
'magenta' => array('set' => 35, 'unset' => 39),
|
||||
'cyan' => array('set' => 36, 'unset' => 39),
|
||||
'white' => array('set' => 37, 'unset' => 39),
|
||||
'default' => array('set' => 39, 'unset' => 39),
|
||||
);
|
||||
private static $availableBackgroundColors = array(
|
||||
'black' => array('set' => 40, 'unset' => 49),
|
||||
'red' => array('set' => 41, 'unset' => 49),
|
||||
'green' => array('set' => 42, 'unset' => 49),
|
||||
'yellow' => array('set' => 43, 'unset' => 49),
|
||||
'blue' => array('set' => 44, 'unset' => 49),
|
||||
'magenta' => array('set' => 45, 'unset' => 49),
|
||||
'cyan' => array('set' => 46, 'unset' => 49),
|
||||
'white' => array('set' => 47, 'unset' => 49),
|
||||
'default' => array('set' => 49, 'unset' => 49),
|
||||
);
|
||||
private static $availableOptions = array(
|
||||
'bold' => array('set' => 1, 'unset' => 22),
|
||||
'underscore' => array('set' => 4, 'unset' => 24),
|
||||
'blink' => array('set' => 5, 'unset' => 25),
|
||||
'reverse' => array('set' => 7, 'unset' => 27),
|
||||
'conceal' => array('set' => 8, 'unset' => 28),
|
||||
);
|
||||
private static $availableForegroundColors = [
|
||||
'black' => ['set' => 30, 'unset' => 39],
|
||||
'red' => ['set' => 31, 'unset' => 39],
|
||||
'green' => ['set' => 32, 'unset' => 39],
|
||||
'yellow' => ['set' => 33, 'unset' => 39],
|
||||
'blue' => ['set' => 34, 'unset' => 39],
|
||||
'magenta' => ['set' => 35, 'unset' => 39],
|
||||
'cyan' => ['set' => 36, 'unset' => 39],
|
||||
'white' => ['set' => 37, 'unset' => 39],
|
||||
'default' => ['set' => 39, 'unset' => 39],
|
||||
];
|
||||
private static $availableBackgroundColors = [
|
||||
'black' => ['set' => 40, 'unset' => 49],
|
||||
'red' => ['set' => 41, 'unset' => 49],
|
||||
'green' => ['set' => 42, 'unset' => 49],
|
||||
'yellow' => ['set' => 43, 'unset' => 49],
|
||||
'blue' => ['set' => 44, 'unset' => 49],
|
||||
'magenta' => ['set' => 45, 'unset' => 49],
|
||||
'cyan' => ['set' => 46, 'unset' => 49],
|
||||
'white' => ['set' => 47, 'unset' => 49],
|
||||
'default' => ['set' => 49, 'unset' => 49],
|
||||
];
|
||||
private static $availableOptions = [
|
||||
'bold' => ['set' => 1, 'unset' => 22],
|
||||
'underscore' => ['set' => 4, 'unset' => 24],
|
||||
'blink' => ['set' => 5, 'unset' => 25],
|
||||
'reverse' => ['set' => 7, 'unset' => 27],
|
||||
'conceal' => ['set' => 8, 'unset' => 28],
|
||||
];
|
||||
|
||||
private $foreground;
|
||||
private $background;
|
||||
private $options = array();
|
||||
private $href;
|
||||
private $options = [];
|
||||
private $handlesHrefGracefully;
|
||||
|
||||
/**
|
||||
* Initializes output formatter style.
|
||||
*
|
||||
* @param string|null $foreground The style foreground color name
|
||||
* @param string|null $background The style background color name
|
||||
* @param array $options The style options
|
||||
*/
|
||||
public function __construct(string $foreground = null, string $background = null, array $options = array())
|
||||
public function __construct(string $foreground = null, string $background = null, array $options = [])
|
||||
{
|
||||
if (null !== $foreground) {
|
||||
$this->setForeground($foreground);
|
||||
@@ -75,11 +76,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets style foreground color.
|
||||
*
|
||||
* @param string|null $color The color name
|
||||
*
|
||||
* @throws InvalidArgumentException When the color name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setForeground($color = null)
|
||||
{
|
||||
@@ -90,18 +87,14 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
if (!isset(static::$availableForegroundColors[$color])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableForegroundColors))));
|
||||
throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableForegroundColors))));
|
||||
}
|
||||
|
||||
$this->foreground = static::$availableForegroundColors[$color];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets style background color.
|
||||
*
|
||||
* @param string|null $color The color name
|
||||
*
|
||||
* @throws InvalidArgumentException When the color name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setBackground($color = null)
|
||||
{
|
||||
@@ -112,23 +105,24 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
if (!isset(static::$availableBackgroundColors[$color])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
|
||||
throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
|
||||
}
|
||||
|
||||
$this->background = static::$availableBackgroundColors[$color];
|
||||
}
|
||||
|
||||
public function setHref(string $url): void
|
||||
{
|
||||
$this->href = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @throws InvalidArgumentException When the option name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setOption($option)
|
||||
{
|
||||
if (!isset(static::$availableOptions[$option])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
|
||||
throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
|
||||
}
|
||||
|
||||
if (!\in_array(static::$availableOptions[$option], $this->options)) {
|
||||
@@ -137,16 +131,12 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets some specific style option.
|
||||
*
|
||||
* @param string $option The option name
|
||||
*
|
||||
* @throws InvalidArgumentException When the option name isn't defined
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unsetOption($option)
|
||||
{
|
||||
if (!isset(static::$availableOptions[$option])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
|
||||
throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
|
||||
}
|
||||
|
||||
$pos = array_search(static::$availableOptions[$option], $this->options);
|
||||
@@ -160,7 +150,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
$this->options = array();
|
||||
$this->options = [];
|
||||
|
||||
foreach ($options as $option) {
|
||||
$this->setOption($option);
|
||||
@@ -168,16 +158,17 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the style to a given text.
|
||||
*
|
||||
* @param string $text The text to style
|
||||
*
|
||||
* @return string
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($text)
|
||||
{
|
||||
$setCodes = array();
|
||||
$unsetCodes = array();
|
||||
$setCodes = [];
|
||||
$unsetCodes = [];
|
||||
|
||||
if (null === $this->handlesHrefGracefully) {
|
||||
$this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
|
||||
&& (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100);
|
||||
}
|
||||
|
||||
if (null !== $this->foreground) {
|
||||
$setCodes[] = $this->foreground['set'];
|
||||
@@ -187,11 +178,14 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
|
||||
$setCodes[] = $this->background['set'];
|
||||
$unsetCodes[] = $this->background['unset'];
|
||||
}
|
||||
if (\count($this->options)) {
|
||||
foreach ($this->options as $option) {
|
||||
$setCodes[] = $option['set'];
|
||||
$unsetCodes[] = $option['unset'];
|
||||
}
|
||||
|
||||
foreach ($this->options as $option) {
|
||||
$setCodes[] = $option['set'];
|
||||
$unsetCodes[] = $option['unset'];
|
||||
}
|
||||
|
||||
if (null !== $this->href && $this->handlesHrefGracefully) {
|
||||
$text = "\033]8;;$this->href\033\\$text\033]8;;\033\\";
|
||||
}
|
||||
|
||||
if (0 === \count($setCodes)) {
|
||||
|
@@ -21,7 +21,7 @@ interface OutputFormatterStyleInterface
|
||||
/**
|
||||
* Sets style foreground color.
|
||||
*
|
||||
* @param string $color The color name
|
||||
* @param string|null $color The color name
|
||||
*/
|
||||
public function setForeground($color = null);
|
||||
|
||||
|
@@ -28,7 +28,7 @@ class OutputFormatterStyleStack implements ResetInterface
|
||||
|
||||
public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
|
||||
{
|
||||
$this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
|
||||
$this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle();
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class OutputFormatterStyleStack implements ResetInterface
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->styles = array();
|
||||
$this->styles = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -20,8 +20,8 @@ namespace Symfony\Component\Console\Helper;
|
||||
*/
|
||||
class DebugFormatterHelper extends Helper
|
||||
{
|
||||
private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default');
|
||||
private $started = array();
|
||||
private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
|
||||
private $started = [];
|
||||
private $count = -1;
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ class DebugFormatterHelper extends Helper
|
||||
*/
|
||||
public function start($id, $message, $prefix = 'RUN')
|
||||
{
|
||||
$this->started[$id] = array('border' => ++$this->count % \count($this->colors));
|
||||
$this->started[$id] = ['border' => ++$this->count % \count($this->colors)];
|
||||
|
||||
return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
|
||||
}
|
||||
@@ -107,12 +107,7 @@ class DebugFormatterHelper extends Helper
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id The id of the formatting session
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getBorder($id)
|
||||
private function getBorder(string $id): string
|
||||
{
|
||||
return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ class DescriptorHelper extends Helper
|
||||
/**
|
||||
* @var DescriptorInterface[]
|
||||
*/
|
||||
private $descriptors = array();
|
||||
private $descriptors = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -48,18 +48,16 @@ class DescriptorHelper extends Helper
|
||||
* * format: string, the output format name
|
||||
* * raw_text: boolean, sets output type as raw
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param object $object
|
||||
* @param array $options
|
||||
* @param object $object
|
||||
*
|
||||
* @throws InvalidArgumentException when the given format is not supported
|
||||
*/
|
||||
public function describe(OutputInterface $output, $object, array $options = array())
|
||||
public function describe(OutputInterface $output, $object, array $options = [])
|
||||
{
|
||||
$options = array_merge(array(
|
||||
$options = array_merge([
|
||||
'raw_text' => false,
|
||||
'format' => 'txt',
|
||||
), $options);
|
||||
], $options);
|
||||
|
||||
if (!isset($this->descriptors[$options['format']])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
|
||||
@@ -72,8 +70,7 @@ class DescriptorHelper extends Helper
|
||||
/**
|
||||
* Registers a descriptor.
|
||||
*
|
||||
* @param string $format
|
||||
* @param DescriptorInterface $descriptor
|
||||
* @param string $format
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
64
vendor/symfony/console/Helper/Dumper.php
vendored
Normal file
64
vendor/symfony/console/Helper/Dumper.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
|
||||
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||
|
||||
/**
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
final class Dumper
|
||||
{
|
||||
private $output;
|
||||
private $dumper;
|
||||
private $cloner;
|
||||
private $handler;
|
||||
|
||||
public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null)
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->dumper = $dumper;
|
||||
$this->cloner = $cloner;
|
||||
|
||||
if (class_exists(CliDumper::class)) {
|
||||
$this->handler = function ($var): string {
|
||||
$dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR);
|
||||
$dumper->setColors($this->output->isDecorated());
|
||||
|
||||
return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true));
|
||||
};
|
||||
} else {
|
||||
$this->handler = function ($var): string {
|
||||
switch (true) {
|
||||
case null === $var:
|
||||
return 'null';
|
||||
case true === $var:
|
||||
return 'true';
|
||||
case false === $var:
|
||||
return 'false';
|
||||
case \is_string($var):
|
||||
return '"'.$var.'"';
|
||||
default:
|
||||
return rtrim(print_r($var, true));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke($var): string
|
||||
{
|
||||
return ($this->handler)($var);
|
||||
}
|
||||
}
|
@@ -46,20 +46,20 @@ class FormatterHelper extends Helper
|
||||
public function formatBlock($messages, $style, $large = false)
|
||||
{
|
||||
if (!\is_array($messages)) {
|
||||
$messages = array($messages);
|
||||
$messages = [$messages];
|
||||
}
|
||||
|
||||
$len = 0;
|
||||
$lines = array();
|
||||
$lines = [];
|
||||
foreach ($messages as $message) {
|
||||
$message = OutputFormatter::escape($message);
|
||||
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
|
||||
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
|
||||
$len = max(self::strlen($message) + ($large ? 4 : 2), $len);
|
||||
}
|
||||
|
||||
$messages = $large ? array(str_repeat(' ', $len)) : array();
|
||||
$messages = $large ? [str_repeat(' ', $len)] : [];
|
||||
for ($i = 0; isset($lines[$i]); ++$i) {
|
||||
$messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i]));
|
||||
$messages[] = $lines[$i].str_repeat(' ', $len - self::strlen($lines[$i]));
|
||||
}
|
||||
if ($large) {
|
||||
$messages[] = str_repeat(' ', $len);
|
||||
@@ -83,17 +83,13 @@ class FormatterHelper extends Helper
|
||||
*/
|
||||
public function truncate($message, $length, $suffix = '...')
|
||||
{
|
||||
$computedLength = $length - $this->strlen($suffix);
|
||||
$computedLength = $length - self::strlen($suffix);
|
||||
|
||||
if ($computedLength > $this->strlen($message)) {
|
||||
if ($computedLength > self::strlen($message)) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($message, null, true)) {
|
||||
return substr($message, 0, $length).$suffix;
|
||||
}
|
||||
|
||||
return mb_substr($message, 0, $length, $encoding).$suffix;
|
||||
return self::substr($message, 0, $length).$suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
|
28
vendor/symfony/console/Helper/Helper.php
vendored
28
vendor/symfony/console/Helper/Helper.php
vendored
@@ -47,6 +47,8 @@ abstract class Helper implements HelperInterface
|
||||
*/
|
||||
public static function strlen($string)
|
||||
{
|
||||
$string = (string) $string;
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string, null, true)) {
|
||||
return \strlen($string);
|
||||
}
|
||||
@@ -65,6 +67,8 @@ abstract class Helper implements HelperInterface
|
||||
*/
|
||||
public static function substr($string, $from, $length = null)
|
||||
{
|
||||
$string = (string) $string;
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string, null, true)) {
|
||||
return substr($string, $from, $length);
|
||||
}
|
||||
@@ -74,17 +78,17 @@ abstract class Helper implements HelperInterface
|
||||
|
||||
public static function formatTime($secs)
|
||||
{
|
||||
static $timeFormats = array(
|
||||
array(0, '< 1 sec'),
|
||||
array(1, '1 sec'),
|
||||
array(2, 'secs', 1),
|
||||
array(60, '1 min'),
|
||||
array(120, 'mins', 60),
|
||||
array(3600, '1 hr'),
|
||||
array(7200, 'hrs', 3600),
|
||||
array(86400, '1 day'),
|
||||
array(172800, 'days', 86400),
|
||||
);
|
||||
static $timeFormats = [
|
||||
[0, '< 1 sec'],
|
||||
[1, '1 sec'],
|
||||
[2, 'secs', 1],
|
||||
[60, '1 min'],
|
||||
[120, 'mins', 60],
|
||||
[3600, '1 hr'],
|
||||
[7200, 'hrs', 3600],
|
||||
[86400, '1 day'],
|
||||
[172800, 'days', 86400],
|
||||
];
|
||||
|
||||
foreach ($timeFormats as $index => $format) {
|
||||
if ($secs >= $format[0]) {
|
||||
@@ -131,6 +135,8 @@ abstract class Helper implements HelperInterface
|
||||
$string = $formatter->format($string);
|
||||
// remove already formatted characters
|
||||
$string = preg_replace("/\033\[[^m]*m/", '', $string);
|
||||
// remove terminal hyperlinks
|
||||
$string = preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string);
|
||||
$formatter->setDecorated($isDecorated);
|
||||
|
||||
return $string;
|
||||
|
10
vendor/symfony/console/Helper/HelperSet.php
vendored
10
vendor/symfony/console/Helper/HelperSet.php
vendored
@@ -24,13 +24,13 @@ class HelperSet implements \IteratorAggregate
|
||||
/**
|
||||
* @var Helper[]
|
||||
*/
|
||||
private $helpers = array();
|
||||
private $helpers = [];
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* @param Helper[] $helpers An array of helper
|
||||
*/
|
||||
public function __construct(array $helpers = array())
|
||||
public function __construct(array $helpers = [])
|
||||
{
|
||||
foreach ($helpers as $alias => $helper) {
|
||||
$this->set($helper, \is_int($alias) ? null : $alias);
|
||||
@@ -40,8 +40,7 @@ class HelperSet implements \IteratorAggregate
|
||||
/**
|
||||
* Sets a helper.
|
||||
*
|
||||
* @param HelperInterface $helper The helper instance
|
||||
* @param string $alias An alias
|
||||
* @param string $alias An alias
|
||||
*/
|
||||
public function set(HelperInterface $helper, $alias = null)
|
||||
{
|
||||
@@ -99,8 +98,9 @@ class HelperSet implements \IteratorAggregate
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Helper[]
|
||||
* @return \Traversable<Helper>
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->helpers);
|
||||
|
42
vendor/symfony/console/Helper/ProcessHelper.php
vendored
42
vendor/symfony/console/Helper/ProcessHelper.php
vendored
@@ -28,17 +28,20 @@ class ProcessHelper extends Helper
|
||||
/**
|
||||
* Runs an external process.
|
||||
*
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param array|Process $cmd An instance of Process or an array of the command and arguments
|
||||
* @param string|null $error An error message that must be displayed if something went wrong
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
* @param int $verbosity The threshold for verbosity
|
||||
* @param array|Process $cmd An instance of Process or an array of the command and arguments
|
||||
* @param string|null $error An error message that must be displayed if something went wrong
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
* @param int $verbosity The threshold for verbosity
|
||||
*
|
||||
* @return Process The process that ran
|
||||
*/
|
||||
public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
|
||||
{
|
||||
if (!class_exists(Process::class)) {
|
||||
throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
|
||||
}
|
||||
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
@@ -46,22 +49,22 @@ class ProcessHelper extends Helper
|
||||
$formatter = $this->getHelperSet()->get('debug_formatter');
|
||||
|
||||
if ($cmd instanceof Process) {
|
||||
$cmd = array($cmd);
|
||||
$cmd = [$cmd];
|
||||
}
|
||||
|
||||
if (!\is_array($cmd)) {
|
||||
@trigger_error(sprintf('Passing a command as a string to "%s()" is deprecated since Symfony 4.2, pass it the command as an array of arguments instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
$cmd = array(\method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd));
|
||||
@trigger_error(sprintf('Passing a command as a string to "%s()" is deprecated since Symfony 4.2, pass it the command as an array of arguments instead.', __METHOD__), \E_USER_DEPRECATED);
|
||||
$cmd = [method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd)];
|
||||
}
|
||||
|
||||
if (\is_string($cmd[0] ?? null)) {
|
||||
$process = new Process($cmd);
|
||||
$cmd = array();
|
||||
$cmd = [];
|
||||
} elseif (($cmd[0] ?? null) instanceof Process) {
|
||||
$process = $cmd[0];
|
||||
unset($cmd[0]);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should an array whose first is element is either the path to the binary to run of a "Process" object.', __METHOD__));
|
||||
throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__));
|
||||
}
|
||||
|
||||
if ($verbosity <= $output->getVerbosity()) {
|
||||
@@ -92,11 +95,10 @@ class ProcessHelper extends Helper
|
||||
* This is identical to run() except that an exception is thrown if the process
|
||||
* exits with a non-zero exit code.
|
||||
*
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param string|Process $cmd An instance of Process or a command to run
|
||||
* @param string|null $error An error message that must be displayed if something went wrong
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
* @param array|Process $cmd An instance of Process or a command to run
|
||||
* @param string|null $error An error message that must be displayed if something went wrong
|
||||
* @param callable|null $callback A PHP callback to run whenever there is some
|
||||
* output available on STDOUT or STDERR
|
||||
*
|
||||
* @return Process The process that ran
|
||||
*
|
||||
@@ -118,10 +120,6 @@ class ProcessHelper extends Helper
|
||||
/**
|
||||
* Wraps a Process callback to add debugging output.
|
||||
*
|
||||
* @param OutputInterface $output An OutputInterface interface
|
||||
* @param Process $process The Process
|
||||
* @param callable|null $callback A PHP callable
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null)
|
||||
@@ -136,12 +134,12 @@ class ProcessHelper extends Helper
|
||||
$output->write($formatter->progress(spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type));
|
||||
|
||||
if (null !== $callback) {
|
||||
\call_user_func($callback, $type, $buffer);
|
||||
$callback($type, $buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private function escapeString($str)
|
||||
private function escapeString(string $str): string
|
||||
{
|
||||
return str_replace('<', '\\<', $str);
|
||||
}
|
||||
|
151
vendor/symfony/console/Helper/ProgressBar.php
vendored
151
vendor/symfony/console/Helper/ProgressBar.php
vendored
@@ -32,6 +32,10 @@ final class ProgressBar
|
||||
private $format;
|
||||
private $internalFormat;
|
||||
private $redrawFreq = 1;
|
||||
private $writeCount;
|
||||
private $lastWriteTime;
|
||||
private $minSecondsBetweenRedraws = 0;
|
||||
private $maxSecondsBetweenRedraws = 1;
|
||||
private $output;
|
||||
private $step = 0;
|
||||
private $max;
|
||||
@@ -39,19 +43,18 @@ final class ProgressBar
|
||||
private $stepWidth;
|
||||
private $percent = 0.0;
|
||||
private $formatLineCount;
|
||||
private $messages = array();
|
||||
private $messages = [];
|
||||
private $overwrite = true;
|
||||
private $terminal;
|
||||
private $firstRun = true;
|
||||
private $previousMessage;
|
||||
|
||||
private static $formatters;
|
||||
private static $formats;
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param int $max Maximum steps (0 if unknown)
|
||||
* @param int $max Maximum steps (0 if unknown)
|
||||
*/
|
||||
public function __construct(OutputInterface $output, int $max = 0)
|
||||
public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 0.1)
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
@@ -61,12 +64,17 @@ final class ProgressBar
|
||||
$this->setMaxSteps($max);
|
||||
$this->terminal = new Terminal();
|
||||
|
||||
if (0 < $minSecondsBetweenRedraws) {
|
||||
$this->redrawFreq = null;
|
||||
$this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws;
|
||||
}
|
||||
|
||||
if (!$this->output->isDecorated()) {
|
||||
// disable overwrite when output does not support ANSI codes.
|
||||
$this->overwrite = false;
|
||||
|
||||
// set a reasonable redraw frequency so output isn't flooded
|
||||
$this->setRedrawFrequency($max / 10);
|
||||
$this->redrawFreq = null;
|
||||
}
|
||||
|
||||
$this->startTime = time();
|
||||
@@ -102,7 +110,7 @@ final class ProgressBar
|
||||
self::$formatters = self::initPlaceholderFormatters();
|
||||
}
|
||||
|
||||
return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
|
||||
return self::$formatters[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,7 +143,7 @@ final class ProgressBar
|
||||
self::$formats = self::initFormats();
|
||||
}
|
||||
|
||||
return isset(self::$formats[$name]) ? self::$formats[$name] : null;
|
||||
return self::$formats[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,6 +191,11 @@ final class ProgressBar
|
||||
return $this->percent;
|
||||
}
|
||||
|
||||
public function getBarOffset(): int
|
||||
{
|
||||
return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
|
||||
}
|
||||
|
||||
public function setBarWidth(int $size)
|
||||
{
|
||||
$this->barWidth = max(1, $size);
|
||||
@@ -236,11 +249,39 @@ final class ProgressBar
|
||||
/**
|
||||
* Sets the redraw frequency.
|
||||
*
|
||||
* @param int|float $freq The frequency in steps
|
||||
* @param int|null $freq The frequency in steps
|
||||
*/
|
||||
public function setRedrawFrequency(int $freq)
|
||||
public function setRedrawFrequency(?int $freq)
|
||||
{
|
||||
$this->redrawFreq = max($freq, 1);
|
||||
$this->redrawFreq = null !== $freq ? max(1, $freq) : null;
|
||||
}
|
||||
|
||||
public function minSecondsBetweenRedraws(float $seconds): void
|
||||
{
|
||||
$this->minSecondsBetweenRedraws = $seconds;
|
||||
}
|
||||
|
||||
public function maxSecondsBetweenRedraws(float $seconds): void
|
||||
{
|
||||
$this->maxSecondsBetweenRedraws = $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator that will automatically update the progress bar when iterated.
|
||||
*
|
||||
* @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable
|
||||
*/
|
||||
public function iterate(iterable $iterable, int $max = null): iterable
|
||||
{
|
||||
$this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0));
|
||||
|
||||
foreach ($iterable as $key => $value) {
|
||||
yield $key => $value;
|
||||
|
||||
$this->advance();
|
||||
}
|
||||
|
||||
$this->finish();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,11 +328,27 @@ final class ProgressBar
|
||||
$step = 0;
|
||||
}
|
||||
|
||||
$prevPeriod = (int) ($this->step / $this->redrawFreq);
|
||||
$currPeriod = (int) ($step / $this->redrawFreq);
|
||||
$redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10);
|
||||
$prevPeriod = (int) ($this->step / $redrawFreq);
|
||||
$currPeriod = (int) ($step / $redrawFreq);
|
||||
$this->step = $step;
|
||||
$this->percent = $this->max ? (float) $this->step / $this->max : 0;
|
||||
if ($prevPeriod !== $currPeriod || $this->max === $step) {
|
||||
$timeInterval = microtime(true) - $this->lastWriteTime;
|
||||
|
||||
// Draw regardless of other limits
|
||||
if ($this->max === $step) {
|
||||
$this->display();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Throttling
|
||||
if ($timeInterval < $this->minSecondsBetweenRedraws) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw each step period, but not too late
|
||||
if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) {
|
||||
$this->display();
|
||||
}
|
||||
}
|
||||
@@ -375,31 +432,43 @@ final class ProgressBar
|
||||
*/
|
||||
private function overwrite(string $message): void
|
||||
{
|
||||
if ($this->previousMessage === $message) {
|
||||
return;
|
||||
}
|
||||
|
||||
$originalMessage = $message;
|
||||
|
||||
if ($this->overwrite) {
|
||||
if (!$this->firstRun) {
|
||||
if (null !== $this->previousMessage) {
|
||||
if ($this->output instanceof ConsoleSectionOutput) {
|
||||
$lines = floor(Helper::strlen($message) / $this->terminal->getWidth()) + $this->formatLineCount + 1;
|
||||
$this->output->clear($lines);
|
||||
$messageLines = explode("\n", $message);
|
||||
$lineCount = \count($messageLines);
|
||||
foreach ($messageLines as $messageLine) {
|
||||
$messageLineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $messageLine);
|
||||
if ($messageLineLength > $this->terminal->getWidth()) {
|
||||
$lineCount += floor($messageLineLength / $this->terminal->getWidth());
|
||||
}
|
||||
}
|
||||
$this->output->clear($lineCount);
|
||||
} else {
|
||||
// Move the cursor to the beginning of the line
|
||||
$this->output->write("\x0D");
|
||||
|
||||
// Erase the line
|
||||
$this->output->write("\x1B[2K");
|
||||
|
||||
// Erase previous lines
|
||||
if ($this->formatLineCount > 0) {
|
||||
$this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount));
|
||||
$message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message;
|
||||
}
|
||||
|
||||
// Move the cursor to the beginning of the line and erase the line
|
||||
$message = "\x0D\x1B[2K$message";
|
||||
}
|
||||
}
|
||||
} elseif ($this->step > 0) {
|
||||
$this->output->writeln('');
|
||||
$message = \PHP_EOL.$message;
|
||||
}
|
||||
|
||||
$this->firstRun = false;
|
||||
$this->previousMessage = $originalMessage;
|
||||
$this->lastWriteTime = microtime(true);
|
||||
|
||||
$this->output->write($message);
|
||||
++$this->writeCount;
|
||||
}
|
||||
|
||||
private function determineBestFormat(): string
|
||||
@@ -419,9 +488,9 @@ final class ProgressBar
|
||||
|
||||
private static function initPlaceholderFormatters(): array
|
||||
{
|
||||
return array(
|
||||
'bar' => function (ProgressBar $bar, OutputInterface $output) {
|
||||
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
|
||||
return [
|
||||
'bar' => function (self $bar, OutputInterface $output) {
|
||||
$completeBars = $bar->getBarOffset();
|
||||
$display = str_repeat($bar->getBarCharacter(), $completeBars);
|
||||
if ($completeBars < $bar->getBarWidth()) {
|
||||
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
|
||||
@@ -430,10 +499,10 @@ final class ProgressBar
|
||||
|
||||
return $display;
|
||||
},
|
||||
'elapsed' => function (ProgressBar $bar) {
|
||||
'elapsed' => function (self $bar) {
|
||||
return Helper::formatTime(time() - $bar->getStartTime());
|
||||
},
|
||||
'remaining' => function (ProgressBar $bar) {
|
||||
'remaining' => function (self $bar) {
|
||||
if (!$bar->getMaxSteps()) {
|
||||
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
|
||||
}
|
||||
@@ -446,7 +515,7 @@ final class ProgressBar
|
||||
|
||||
return Helper::formatTime($remaining);
|
||||
},
|
||||
'estimated' => function (ProgressBar $bar) {
|
||||
'estimated' => function (self $bar) {
|
||||
if (!$bar->getMaxSteps()) {
|
||||
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
|
||||
}
|
||||
@@ -459,24 +528,24 @@ final class ProgressBar
|
||||
|
||||
return Helper::formatTime($estimated);
|
||||
},
|
||||
'memory' => function (ProgressBar $bar) {
|
||||
'memory' => function (self $bar) {
|
||||
return Helper::formatMemory(memory_get_usage(true));
|
||||
},
|
||||
'current' => function (ProgressBar $bar) {
|
||||
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
|
||||
'current' => function (self $bar) {
|
||||
return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT);
|
||||
},
|
||||
'max' => function (ProgressBar $bar) {
|
||||
'max' => function (self $bar) {
|
||||
return $bar->getMaxSteps();
|
||||
},
|
||||
'percent' => function (ProgressBar $bar) {
|
||||
'percent' => function (self $bar) {
|
||||
return floor($bar->getProgressPercent() * 100);
|
||||
},
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
private static function initFormats(): array
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
|
||||
'normal_nomax' => ' %current% [%bar%]',
|
||||
|
||||
@@ -488,7 +557,7 @@ final class ProgressBar
|
||||
|
||||
'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
|
||||
'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
private function buildLine(): string
|
||||
@@ -496,7 +565,7 @@ final class ProgressBar
|
||||
$regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i";
|
||||
$callback = function ($matches) {
|
||||
if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
|
||||
$text = \call_user_func($formatter, $this, $this->output);
|
||||
$text = $formatter($this, $this->output);
|
||||
} elseif (isset($this->messages[$matches[1]])) {
|
||||
$text = $this->messages[$matches[1]];
|
||||
} else {
|
||||
|
@@ -34,10 +34,9 @@ class ProgressIndicator
|
||||
private static $formats;
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output
|
||||
* @param string|null $format Indicator format
|
||||
* @param int $indicatorChangeInterval Change interval in milliseconds
|
||||
* @param array|null $indicatorValues Animated indicator characters
|
||||
* @param string|null $format Indicator format
|
||||
* @param int $indicatorChangeInterval Change interval in milliseconds
|
||||
* @param array|null $indicatorValues Animated indicator characters
|
||||
*/
|
||||
public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
|
||||
{
|
||||
@@ -48,7 +47,7 @@ class ProgressIndicator
|
||||
}
|
||||
|
||||
if (null === $indicatorValues) {
|
||||
$indicatorValues = array('-', '\\', '|', '/');
|
||||
$indicatorValues = ['-', '\\', '|', '/'];
|
||||
}
|
||||
|
||||
$indicatorValues = array_values($indicatorValues);
|
||||
@@ -150,7 +149,7 @@ class ProgressIndicator
|
||||
self::$formats = self::initFormats();
|
||||
}
|
||||
|
||||
return isset(self::$formats[$name]) ? self::$formats[$name] : null;
|
||||
return self::$formats[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,7 +182,7 @@ class ProgressIndicator
|
||||
self::$formatters = self::initPlaceholderFormatters();
|
||||
}
|
||||
|
||||
return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
|
||||
return self::$formatters[$name] ?? null;
|
||||
}
|
||||
|
||||
private function display()
|
||||
@@ -192,18 +191,16 @@ class ProgressIndicator
|
||||
return;
|
||||
}
|
||||
|
||||
$self = $this;
|
||||
|
||||
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
|
||||
if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
|
||||
return \call_user_func($formatter, $self);
|
||||
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
|
||||
if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
|
||||
return $formatter($this);
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}, $this->format));
|
||||
}, $this->format ?? ''));
|
||||
}
|
||||
|
||||
private function determineBestFormat()
|
||||
private function determineBestFormat(): string
|
||||
{
|
||||
switch ($this->output->getVerbosity()) {
|
||||
// OutputInterface::VERBOSITY_QUIET: display is disabled anyway
|
||||
@@ -230,32 +227,32 @@ class ProgressIndicator
|
||||
}
|
||||
}
|
||||
|
||||
private function getCurrentTimeInMilliseconds()
|
||||
private function getCurrentTimeInMilliseconds(): float
|
||||
{
|
||||
return round(microtime(true) * 1000);
|
||||
}
|
||||
|
||||
private static function initPlaceholderFormatters()
|
||||
private static function initPlaceholderFormatters(): array
|
||||
{
|
||||
return array(
|
||||
'indicator' => function (ProgressIndicator $indicator) {
|
||||
return [
|
||||
'indicator' => function (self $indicator) {
|
||||
return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
|
||||
},
|
||||
'message' => function (ProgressIndicator $indicator) {
|
||||
'message' => function (self $indicator) {
|
||||
return $indicator->message;
|
||||
},
|
||||
'elapsed' => function (ProgressIndicator $indicator) {
|
||||
'elapsed' => function (self $indicator) {
|
||||
return Helper::formatTime(time() - $indicator->startTime);
|
||||
},
|
||||
'memory' => function () {
|
||||
return Helper::formatMemory(memory_get_usage(true));
|
||||
},
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
private static function initFormats()
|
||||
private static function initFormats(): array
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
'normal' => ' %indicator% %message%',
|
||||
'normal_no_ansi' => ' %message%',
|
||||
|
||||
@@ -264,6 +261,6 @@ class ProgressIndicator
|
||||
|
||||
'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
|
||||
'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
|
||||
);
|
||||
];
|
||||
}
|
||||
}
|
||||
|
346
vendor/symfony/console/Helper/QuestionHelper.php
vendored
346
vendor/symfony/console/Helper/QuestionHelper.php
vendored
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\MissingInputException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
@@ -21,6 +22,7 @@ use Symfony\Component\Console\Output\ConsoleSectionOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Console\Terminal;
|
||||
|
||||
/**
|
||||
* The QuestionHelper class provides helpers to interact with the user.
|
||||
@@ -31,7 +33,8 @@ class QuestionHelper extends Helper
|
||||
{
|
||||
private $inputStream;
|
||||
private static $shell;
|
||||
private static $stty;
|
||||
private static $stty = true;
|
||||
private static $stdinIsInteractive;
|
||||
|
||||
/**
|
||||
* Asks a question to the user.
|
||||
@@ -47,38 +50,32 @@ class QuestionHelper extends Helper
|
||||
}
|
||||
|
||||
if (!$input->isInteractive()) {
|
||||
$default = $question->getDefault();
|
||||
|
||||
if (null !== $default && $question instanceof ChoiceQuestion) {
|
||||
$choices = $question->getChoices();
|
||||
|
||||
if (!$question->isMultiselect()) {
|
||||
return isset($choices[$default]) ? $choices[$default] : $default;
|
||||
}
|
||||
|
||||
$default = explode(',', $default);
|
||||
foreach ($default as $k => $v) {
|
||||
$v = trim($v);
|
||||
$default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
return $this->getDefaultAnswer($question);
|
||||
}
|
||||
|
||||
if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) {
|
||||
$this->inputStream = $stream;
|
||||
}
|
||||
|
||||
if (!$question->getValidator()) {
|
||||
return $this->doAsk($output, $question);
|
||||
try {
|
||||
if (!$question->getValidator()) {
|
||||
return $this->doAsk($output, $question);
|
||||
}
|
||||
|
||||
$interviewer = function () use ($output, $question) {
|
||||
return $this->doAsk($output, $question);
|
||||
};
|
||||
|
||||
return $this->validateAttempts($interviewer, $output, $question);
|
||||
} catch (MissingInputException $exception) {
|
||||
$input->setInteractive(false);
|
||||
|
||||
if (null === $fallbackOutput = $this->getDefaultAnswer($question)) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $fallbackOutput;
|
||||
}
|
||||
|
||||
$interviewer = function () use ($output, $question) {
|
||||
return $this->doAsk($output, $question);
|
||||
};
|
||||
|
||||
return $this->validateAttempts($interviewer, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,7 +97,7 @@ class QuestionHelper extends Helper
|
||||
/**
|
||||
* Asks the question to the user.
|
||||
*
|
||||
* @return bool|mixed|string|null
|
||||
* @return mixed
|
||||
*
|
||||
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
|
||||
*/
|
||||
@@ -108,14 +105,15 @@ class QuestionHelper extends Helper
|
||||
{
|
||||
$this->writePrompt($output, $question);
|
||||
|
||||
$inputStream = $this->inputStream ?: STDIN;
|
||||
$autocomplete = $question->getAutocompleterValues();
|
||||
$inputStream = $this->inputStream ?: \STDIN;
|
||||
$autocomplete = $question->getAutocompleterCallback();
|
||||
|
||||
if (null === $autocomplete || !$this->hasSttyAvailable()) {
|
||||
if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {
|
||||
$ret = false;
|
||||
if ($question->isHidden()) {
|
||||
try {
|
||||
$ret = trim($this->getHiddenResponse($output, $inputStream));
|
||||
$hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
|
||||
$ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;
|
||||
} catch (RuntimeException $e) {
|
||||
if (!$question->isHiddenFallback()) {
|
||||
throw $e;
|
||||
@@ -124,14 +122,19 @@ class QuestionHelper extends Helper
|
||||
}
|
||||
|
||||
if (false === $ret) {
|
||||
$cp = $this->setIOCodepage();
|
||||
$ret = fgets($inputStream, 4096);
|
||||
$ret = $this->resetIOCodepage($cp, $ret);
|
||||
if (false === $ret) {
|
||||
throw new RuntimeException('Aborted');
|
||||
throw new MissingInputException('Aborted.');
|
||||
}
|
||||
if ($question->isTrimmable()) {
|
||||
$ret = trim($ret);
|
||||
}
|
||||
$ret = trim($ret);
|
||||
}
|
||||
} else {
|
||||
$ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false)));
|
||||
$autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
|
||||
$ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;
|
||||
}
|
||||
|
||||
if ($output instanceof ConsoleSectionOutput) {
|
||||
@@ -147,6 +150,36 @@ class QuestionHelper extends Helper
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function getDefaultAnswer(Question $question)
|
||||
{
|
||||
$default = $question->getDefault();
|
||||
|
||||
if (null === $default) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ($validator = $question->getValidator()) {
|
||||
return \call_user_func($question->getValidator(), $default);
|
||||
} elseif ($question instanceof ChoiceQuestion) {
|
||||
$choices = $question->getChoices();
|
||||
|
||||
if (!$question->isMultiselect()) {
|
||||
return $choices[$default] ?? $default;
|
||||
}
|
||||
|
||||
$default = explode(',', $default);
|
||||
foreach ($default as $k => $v) {
|
||||
$v = $question->isTrimmable() ? trim($v) : $v;
|
||||
$default[$k] = $choices[$v] ?? $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the question prompt.
|
||||
*/
|
||||
@@ -155,15 +188,9 @@ class QuestionHelper extends Helper
|
||||
$message = $question->getQuestion();
|
||||
|
||||
if ($question instanceof ChoiceQuestion) {
|
||||
$maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices())));
|
||||
|
||||
$messages = (array) $question->getQuestion();
|
||||
foreach ($question->getChoices() as $key => $value) {
|
||||
$width = $maxWidth - $this->strlen($key);
|
||||
$messages[] = ' [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
|
||||
}
|
||||
|
||||
$output->writeln($messages);
|
||||
$output->writeln(array_merge([
|
||||
$question->getQuestion(),
|
||||
], $this->formatChoiceQuestionChoices($question, 'info')));
|
||||
|
||||
$message = $question->getPrompt();
|
||||
}
|
||||
@@ -171,6 +198,26 @@ class QuestionHelper extends Helper
|
||||
$output->write($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag)
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
$maxWidth = max(array_map([__CLASS__, 'strlen'], array_keys($choices = $question->getChoices())));
|
||||
|
||||
foreach ($choices as $key => $value) {
|
||||
$padding = str_repeat(' ', $maxWidth - self::strlen($key));
|
||||
|
||||
$messages[] = sprintf(" [<$tag>%s$padding</$tag>] %s", $key, $value);
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs an error message.
|
||||
*/
|
||||
@@ -188,17 +235,16 @@ class QuestionHelper extends Helper
|
||||
/**
|
||||
* Autocompletes a question.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param Question $question
|
||||
* @param resource $inputStream
|
||||
* @param resource $inputStream
|
||||
*/
|
||||
private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete): string
|
||||
private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string
|
||||
{
|
||||
$fullChoice = '';
|
||||
$ret = '';
|
||||
|
||||
$i = 0;
|
||||
$ofs = -1;
|
||||
$matches = $autocomplete;
|
||||
$matches = $autocomplete($ret);
|
||||
$numMatches = \count($matches);
|
||||
|
||||
$sttyMode = shell_exec('stty -g');
|
||||
@@ -213,24 +259,28 @@ class QuestionHelper extends Helper
|
||||
while (!feof($inputStream)) {
|
||||
$c = fread($inputStream, 1);
|
||||
|
||||
// Backspace Character
|
||||
if ("\177" === $c) {
|
||||
// as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
|
||||
if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
throw new MissingInputException('Aborted.');
|
||||
} elseif ("\177" === $c) { // Backspace Character
|
||||
if (0 === $numMatches && 0 !== $i) {
|
||||
--$i;
|
||||
$fullChoice = self::substr($fullChoice, 0, $i);
|
||||
// Move cursor backwards
|
||||
$output->write("\033[1D");
|
||||
}
|
||||
|
||||
if (0 === $i) {
|
||||
$ofs = -1;
|
||||
$matches = $autocomplete;
|
||||
$matches = $autocomplete($ret);
|
||||
$numMatches = \count($matches);
|
||||
} else {
|
||||
$numMatches = 0;
|
||||
}
|
||||
|
||||
// Pop the last character off the end of our string
|
||||
$ret = substr($ret, 0, $i);
|
||||
$ret = self::substr($ret, 0, $i);
|
||||
} elseif ("\033" === $c) {
|
||||
// Did we read an escape sequence?
|
||||
$c .= fread($inputStream, 2);
|
||||
@@ -251,10 +301,21 @@ class QuestionHelper extends Helper
|
||||
} elseif (\ord($c) < 32) {
|
||||
if ("\t" === $c || "\n" === $c) {
|
||||
if ($numMatches > 0 && -1 !== $ofs) {
|
||||
$ret = $matches[$ofs];
|
||||
$ret = (string) $matches[$ofs];
|
||||
// Echo out remaining chars for current match
|
||||
$output->write(substr($ret, $i));
|
||||
$i = \strlen($ret);
|
||||
$remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
|
||||
$output->write($remainingCharacters);
|
||||
$fullChoice .= $remainingCharacters;
|
||||
$i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding);
|
||||
|
||||
$matches = array_filter(
|
||||
$autocomplete($ret),
|
||||
function ($match) use ($ret) {
|
||||
return '' === $ret || str_starts_with($match, $ret);
|
||||
}
|
||||
);
|
||||
$numMatches = \count($matches);
|
||||
$ofs = -1;
|
||||
}
|
||||
|
||||
if ("\n" === $c) {
|
||||
@@ -267,16 +328,27 @@ class QuestionHelper extends Helper
|
||||
|
||||
continue;
|
||||
} else {
|
||||
if ("\x80" <= $c) {
|
||||
$c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]);
|
||||
}
|
||||
|
||||
$output->write($c);
|
||||
$ret .= $c;
|
||||
$fullChoice .= $c;
|
||||
++$i;
|
||||
|
||||
$tempRet = $ret;
|
||||
|
||||
if ($question instanceof ChoiceQuestion && $question->isMultiselect()) {
|
||||
$tempRet = $this->mostRecentlyEnteredValue($fullChoice);
|
||||
}
|
||||
|
||||
$numMatches = 0;
|
||||
$ofs = 0;
|
||||
|
||||
foreach ($autocomplete as $value) {
|
||||
foreach ($autocomplete($ret) as $value) {
|
||||
// If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
|
||||
if (0 === strpos($value, $ret)) {
|
||||
if (str_starts_with($value, $tempRet)) {
|
||||
$matches[$numMatches++] = $value;
|
||||
}
|
||||
}
|
||||
@@ -288,8 +360,9 @@ class QuestionHelper extends Helper
|
||||
if ($numMatches > 0 && -1 !== $ofs) {
|
||||
// Save cursor position
|
||||
$output->write("\0337");
|
||||
// Write highlighted text
|
||||
$output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).'</hl>');
|
||||
// Write highlighted text, complete the partially entered response
|
||||
$charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));
|
||||
$output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'</hl>');
|
||||
// Restore cursor position
|
||||
$output->write("\0338");
|
||||
}
|
||||
@@ -298,18 +371,33 @@ class QuestionHelper extends Helper
|
||||
// Reset stty so it behaves normally again
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
|
||||
return $ret;
|
||||
return $fullChoice;
|
||||
}
|
||||
|
||||
private function mostRecentlyEnteredValue(string $entered): string
|
||||
{
|
||||
// Determine the most recent value that the user entered
|
||||
if (!str_contains($entered, ',')) {
|
||||
return $entered;
|
||||
}
|
||||
|
||||
$choices = explode(',', $entered);
|
||||
if ('' !== $lastChoice = trim($choices[\count($choices) - 1])) {
|
||||
return $lastChoice;
|
||||
}
|
||||
|
||||
return $entered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a hidden response from user.
|
||||
*
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param resource $inputStream The handler resource
|
||||
* @param resource $inputStream The handler resource
|
||||
* @param bool $trimmable Is the answer trimmable
|
||||
*
|
||||
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
|
||||
*/
|
||||
private function getHiddenResponse(OutputInterface $output, $inputStream): string
|
||||
private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = true): string
|
||||
{
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
|
||||
@@ -321,7 +409,8 @@ class QuestionHelper extends Helper
|
||||
$exe = $tmpExe;
|
||||
}
|
||||
|
||||
$value = rtrim(shell_exec($exe));
|
||||
$sExec = shell_exec('"'.$exe.'"');
|
||||
$value = $trimmable ? rtrim($sExec) : $sExec;
|
||||
$output->writeln('');
|
||||
|
||||
if (isset($tmpExe)) {
|
||||
@@ -331,41 +420,34 @@ class QuestionHelper extends Helper
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($this->hasSttyAvailable()) {
|
||||
if (self::$stty && Terminal::hasSttyAvailable()) {
|
||||
$sttyMode = shell_exec('stty -g');
|
||||
|
||||
shell_exec('stty -echo');
|
||||
$value = fgets($inputStream, 4096);
|
||||
} elseif ($this->isInteractiveInput($inputStream)) {
|
||||
throw new RuntimeException('Unable to hide the response.');
|
||||
}
|
||||
|
||||
$value = fgets($inputStream, 4096);
|
||||
|
||||
if (self::$stty && Terminal::hasSttyAvailable()) {
|
||||
shell_exec(sprintf('stty %s', $sttyMode));
|
||||
}
|
||||
|
||||
if (false === $value) {
|
||||
throw new RuntimeException('Aborted');
|
||||
}
|
||||
|
||||
if (false === $value) {
|
||||
throw new MissingInputException('Aborted.');
|
||||
}
|
||||
if ($trimmable) {
|
||||
$value = trim($value);
|
||||
$output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
$output->writeln('');
|
||||
|
||||
if (false !== $shell = $this->getShell()) {
|
||||
$readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
|
||||
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
|
||||
$value = rtrim(shell_exec($command));
|
||||
$output->writeln('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
throw new RuntimeException('Unable to hide the response.');
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an attempt.
|
||||
*
|
||||
* @param callable $interviewer A callable that will ask for a question and return the result
|
||||
* @param OutputInterface $output An Output instance
|
||||
* @param Question $question A Question instance
|
||||
* @param callable $interviewer A callable that will ask for a question and return the result
|
||||
*
|
||||
* @return mixed The validated response
|
||||
*
|
||||
@@ -375,13 +457,14 @@ class QuestionHelper extends Helper
|
||||
{
|
||||
$error = null;
|
||||
$attempts = $question->getMaxAttempts();
|
||||
|
||||
while (null === $attempts || $attempts--) {
|
||||
if (null !== $error) {
|
||||
$this->writeError($output, $error);
|
||||
}
|
||||
|
||||
try {
|
||||
return \call_user_func($question->getValidator(), $interviewer());
|
||||
return $question->getValidator()($interviewer());
|
||||
} catch (RuntimeException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $error) {
|
||||
@@ -391,44 +474,67 @@ class QuestionHelper extends Helper
|
||||
throw $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a valid unix shell.
|
||||
*
|
||||
* @return string|bool The valid shell name, false in case no valid shell is found
|
||||
*/
|
||||
private function getShell()
|
||||
private function isInteractiveInput($inputStream): bool
|
||||
{
|
||||
if (null !== self::$shell) {
|
||||
return self::$shell;
|
||||
if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$shell = false;
|
||||
if (null !== self::$stdinIsInteractive) {
|
||||
return self::$stdinIsInteractive;
|
||||
}
|
||||
|
||||
if (file_exists('/usr/bin/env')) {
|
||||
// handle other OSs with bash/zsh/ksh/csh if available to hide the answer
|
||||
$test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
|
||||
foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
|
||||
if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
|
||||
self::$shell = $sh;
|
||||
break;
|
||||
}
|
||||
if (\function_exists('stream_isatty')) {
|
||||
return self::$stdinIsInteractive = @stream_isatty(fopen('php://stdin', 'r'));
|
||||
}
|
||||
|
||||
if (\function_exists('posix_isatty')) {
|
||||
return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r'));
|
||||
}
|
||||
|
||||
if (!\function_exists('exec')) {
|
||||
return self::$stdinIsInteractive = true;
|
||||
}
|
||||
|
||||
exec('stty 2> /dev/null', $output, $status);
|
||||
|
||||
return self::$stdinIsInteractive = 1 !== $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets console I/O to the host code page.
|
||||
*
|
||||
* @return int Previous code page in IBM/EBCDIC format
|
||||
*/
|
||||
private function setIOCodepage(): int
|
||||
{
|
||||
if (\function_exists('sapi_windows_cp_set')) {
|
||||
$cp = sapi_windows_cp_get();
|
||||
sapi_windows_cp_set(sapi_windows_cp_get('oem'));
|
||||
|
||||
return $cp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets console I/O to the specified code page and converts the user input.
|
||||
*
|
||||
* @param string|false $input
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
private function resetIOCodepage(int $cp, $input)
|
||||
{
|
||||
if (0 !== $cp) {
|
||||
sapi_windows_cp_set($cp);
|
||||
|
||||
if (false !== $input && '' !== $input) {
|
||||
$input = sapi_windows_cp_conv(sapi_windows_cp_get('oem'), $cp, $input);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$shell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether Stty is available or not.
|
||||
*/
|
||||
private function hasSttyAvailable(): bool
|
||||
{
|
||||
if (null !== self::$stty) {
|
||||
return self::$stty;
|
||||
}
|
||||
|
||||
exec('stty 2>&1', $output, $exitcode);
|
||||
|
||||
return self::$stty = 0 === $exitcode;
|
||||
return $input;
|
||||
}
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ class SymfonyQuestionHelper extends QuestionHelper
|
||||
|
||||
case $question instanceof ChoiceQuestion:
|
||||
$choices = $question->getChoices();
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default));
|
||||
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, OutputFormatter::escape($choices[$default] ?? $default));
|
||||
|
||||
break;
|
||||
|
||||
@@ -68,15 +68,15 @@ class SymfonyQuestionHelper extends QuestionHelper
|
||||
|
||||
$output->writeln($text);
|
||||
|
||||
if ($question instanceof ChoiceQuestion) {
|
||||
$width = max(array_map('strlen', array_keys($question->getChoices())));
|
||||
$prompt = ' > ';
|
||||
|
||||
foreach ($question->getChoices() as $key => $value) {
|
||||
$output->writeln(sprintf(" [<comment>%-${width}s</comment>] %s", $key, $value));
|
||||
}
|
||||
if ($question instanceof ChoiceQuestion) {
|
||||
$output->writeln($this->formatChoiceQuestionChoices($question, 'comment'));
|
||||
|
||||
$prompt = $question->getPrompt();
|
||||
}
|
||||
|
||||
$output->write(' > ');
|
||||
$output->write($prompt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
277
vendor/symfony/console/Helper/Table.php
vendored
277
vendor/symfony/console/Helper/Table.php
vendored
@@ -13,6 +13,7 @@ namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleSectionOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -41,17 +42,18 @@ class Table
|
||||
/**
|
||||
* Table headers.
|
||||
*/
|
||||
private $headers = array();
|
||||
private $headers = [];
|
||||
|
||||
/**
|
||||
* Table rows.
|
||||
*/
|
||||
private $rows = array();
|
||||
private $rows = [];
|
||||
private $horizontal = false;
|
||||
|
||||
/**
|
||||
* Column widths cache.
|
||||
*/
|
||||
private $effectiveColumnWidths = array();
|
||||
private $effectiveColumnWidths = [];
|
||||
|
||||
/**
|
||||
* Number of columns cache.
|
||||
@@ -73,15 +75,15 @@ class Table
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $columnStyles = array();
|
||||
private $columnStyles = [];
|
||||
|
||||
/**
|
||||
* User set column widths.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $columnWidths = array();
|
||||
private $columnMaxWidths = array();
|
||||
private $columnWidths = [];
|
||||
private $columnMaxWidths = [];
|
||||
|
||||
private static $styles;
|
||||
|
||||
@@ -101,8 +103,7 @@ class Table
|
||||
/**
|
||||
* Sets a style definition.
|
||||
*
|
||||
* @param string $name The style name
|
||||
* @param TableStyle $style A TableStyle instance
|
||||
* @param string $name The style name
|
||||
*/
|
||||
public static function setStyleDefinition($name, TableStyle $style)
|
||||
{
|
||||
@@ -206,13 +207,11 @@ class Table
|
||||
/**
|
||||
* Sets the minimum width of all columns.
|
||||
*
|
||||
* @param array $widths
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumnWidths(array $widths)
|
||||
{
|
||||
$this->columnWidths = array();
|
||||
$this->columnWidths = [];
|
||||
foreach ($widths as $index => $width) {
|
||||
$this->setColumnWidth($index, $width);
|
||||
}
|
||||
@@ -243,7 +242,7 @@ class Table
|
||||
{
|
||||
$headers = array_values($headers);
|
||||
if (!empty($headers) && !\is_array($headers[0])) {
|
||||
$headers = array($headers);
|
||||
$headers = [$headers];
|
||||
}
|
||||
|
||||
$this->headers = $headers;
|
||||
@@ -253,7 +252,7 @@ class Table
|
||||
|
||||
public function setRows(array $rows)
|
||||
{
|
||||
$this->rows = array();
|
||||
$this->rows = [];
|
||||
|
||||
return $this->addRows($rows);
|
||||
}
|
||||
@@ -324,6 +323,13 @@ class Table
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHorizontal(bool $horizontal = true): self
|
||||
{
|
||||
$this->horizontal = $horizontal;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders table to output.
|
||||
*
|
||||
@@ -339,40 +345,84 @@ class Table
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$rows = array_merge($this->headers, array($divider = new TableSeparator()), $this->rows);
|
||||
$this->calculateNumberOfColumns($rows);
|
||||
|
||||
$rows = $this->buildTableRows($rows);
|
||||
$this->calculateColumnsWidth($rows);
|
||||
|
||||
$isHeader = true;
|
||||
$isFirstRow = false;
|
||||
foreach ($rows as $row) {
|
||||
if ($divider === $row) {
|
||||
$isHeader = false;
|
||||
$isFirstRow = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
if ($row instanceof TableSeparator) {
|
||||
$this->renderRowSeparator();
|
||||
|
||||
continue;
|
||||
}
|
||||
if (!$row) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isHeader || $isFirstRow) {
|
||||
if ($isFirstRow) {
|
||||
$this->renderRowSeparator(self::SEPARATOR_TOP_BOTTOM);
|
||||
$isFirstRow = false;
|
||||
} else {
|
||||
$this->renderRowSeparator(self::SEPARATOR_TOP, $this->headerTitle, $this->style->getHeaderTitleFormat());
|
||||
$divider = new TableSeparator();
|
||||
if ($this->horizontal) {
|
||||
$rows = [];
|
||||
foreach ($this->headers[0] ?? [] as $i => $header) {
|
||||
$rows[$i] = [$header];
|
||||
foreach ($this->rows as $row) {
|
||||
if ($row instanceof TableSeparator) {
|
||||
continue;
|
||||
}
|
||||
if (isset($row[$i])) {
|
||||
$rows[$i][] = $row[$i];
|
||||
} elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) {
|
||||
// Noop, there is a "title"
|
||||
} else {
|
||||
$rows[$i][] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$rows = array_merge($this->headers, [$divider], $this->rows);
|
||||
}
|
||||
|
||||
$this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
|
||||
$this->calculateNumberOfColumns($rows);
|
||||
|
||||
$rowGroups = $this->buildTableRows($rows);
|
||||
$this->calculateColumnsWidth($rowGroups);
|
||||
|
||||
$isHeader = !$this->horizontal;
|
||||
$isFirstRow = $this->horizontal;
|
||||
$hasTitle = (bool) $this->headerTitle;
|
||||
|
||||
foreach ($rowGroups as $rowGroup) {
|
||||
$isHeaderSeparatorRendered = false;
|
||||
|
||||
foreach ($rowGroup as $row) {
|
||||
if ($divider === $row) {
|
||||
$isHeader = false;
|
||||
$isFirstRow = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($row instanceof TableSeparator) {
|
||||
$this->renderRowSeparator();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$row) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isHeader && !$isHeaderSeparatorRendered) {
|
||||
$this->renderRowSeparator(
|
||||
$isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
|
||||
$hasTitle ? $this->headerTitle : null,
|
||||
$hasTitle ? $this->style->getHeaderTitleFormat() : null
|
||||
);
|
||||
$hasTitle = false;
|
||||
$isHeaderSeparatorRendered = true;
|
||||
}
|
||||
|
||||
if ($isFirstRow) {
|
||||
$this->renderRowSeparator(
|
||||
$isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
|
||||
$hasTitle ? $this->headerTitle : null,
|
||||
$hasTitle ? $this->style->getHeaderTitleFormat() : null
|
||||
);
|
||||
$isFirstRow = false;
|
||||
$hasTitle = false;
|
||||
}
|
||||
|
||||
if ($this->horizontal) {
|
||||
$this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
|
||||
} else {
|
||||
$this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
|
||||
|
||||
@@ -400,13 +450,13 @@ class Table
|
||||
|
||||
$crossings = $this->style->getCrossingChars();
|
||||
if (self::SEPARATOR_MID === $type) {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = array($borders[2], $crossings[8], $crossings[0], $crossings[4]);
|
||||
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]];
|
||||
} elseif (self::SEPARATOR_TOP === $type) {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = array($borders[0], $crossings[1], $crossings[2], $crossings[3]);
|
||||
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]];
|
||||
} elseif (self::SEPARATOR_TOP_BOTTOM === $type) {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = array($borders[0], $crossings[9], $crossings[10], $crossings[11]);
|
||||
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]];
|
||||
} else {
|
||||
list($horizontal, $leftChar, $midChar, $rightChar) = array($borders[0], $crossings[7], $crossings[6], $crossings[5]);
|
||||
[$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]];
|
||||
}
|
||||
|
||||
$markup = $leftChar;
|
||||
@@ -424,7 +474,7 @@ class Table
|
||||
$formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');
|
||||
}
|
||||
|
||||
$titleStart = ($markupLength - $titleLength) / 2;
|
||||
$titleStart = intdiv($markupLength - $titleLength, 2);
|
||||
if (false === mb_detect_encoding($markup, null, true)) {
|
||||
$markup = substr_replace($markup, $formattedTitle, $titleStart, $titleLength);
|
||||
} else {
|
||||
@@ -438,7 +488,7 @@ class Table
|
||||
/**
|
||||
* Renders vertical column separator.
|
||||
*/
|
||||
private function renderColumnSeparator($type = self::BORDER_OUTSIDE)
|
||||
private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string
|
||||
{
|
||||
$borders = $this->style->getBorderChars();
|
||||
|
||||
@@ -452,13 +502,17 @@ class Table
|
||||
*
|
||||
* | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
||||
*/
|
||||
private function renderRow(array $row, string $cellFormat)
|
||||
private function renderRow(array $row, string $cellFormat, string $firstCellFormat = null)
|
||||
{
|
||||
$rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE);
|
||||
$columns = $this->getRowColumns($row);
|
||||
$last = \count($columns) - 1;
|
||||
foreach ($columns as $i => $column) {
|
||||
$rowContent .= $this->renderCell($row, $column, $cellFormat);
|
||||
if ($firstCellFormat && 0 === $i) {
|
||||
$rowContent .= $this->renderCell($row, $column, $firstCellFormat);
|
||||
} else {
|
||||
$rowContent .= $this->renderCell($row, $column, $cellFormat);
|
||||
}
|
||||
$rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE);
|
||||
}
|
||||
$this->output->writeln($rowContent);
|
||||
@@ -467,9 +521,9 @@ class Table
|
||||
/**
|
||||
* Renders table cell with padding.
|
||||
*/
|
||||
private function renderCell(array $row, int $column, string $cellFormat)
|
||||
private function renderCell(array $row, int $column, string $cellFormat): string
|
||||
{
|
||||
$cell = isset($row[$column]) ? $row[$column] : '';
|
||||
$cell = $row[$column] ?? '';
|
||||
$width = $this->effectiveColumnWidths[$column];
|
||||
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||
// add the width of the following columns(numbers of colspan).
|
||||
@@ -498,9 +552,9 @@ class Table
|
||||
/**
|
||||
* Calculate number of columns for this table.
|
||||
*/
|
||||
private function calculateNumberOfColumns($rows)
|
||||
private function calculateNumberOfColumns(array $rows)
|
||||
{
|
||||
$columns = array(0);
|
||||
$columns = [0];
|
||||
foreach ($rows as $row) {
|
||||
if ($row instanceof TableSeparator) {
|
||||
continue;
|
||||
@@ -512,58 +566,68 @@ class Table
|
||||
$this->numberOfColumns = max($columns);
|
||||
}
|
||||
|
||||
private function buildTableRows($rows)
|
||||
private function buildTableRows(array $rows): TableRows
|
||||
{
|
||||
/** @var WrappableOutputFormatterInterface $formatter */
|
||||
$formatter = $this->output->getFormatter();
|
||||
$unmergedRows = array();
|
||||
$unmergedRows = [];
|
||||
for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) {
|
||||
$rows = $this->fillNextRows($rows, $rowKey);
|
||||
|
||||
// Remove any new line breaks and replace it with a new line
|
||||
foreach ($rows[$rowKey] as $column => $cell) {
|
||||
$colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
|
||||
|
||||
if (isset($this->columnMaxWidths[$column]) && Helper::strlenWithoutDecoration($formatter, $cell) > $this->columnMaxWidths[$column]) {
|
||||
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column]);
|
||||
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
|
||||
}
|
||||
if (!strstr($cell, "\n")) {
|
||||
if (!strstr($cell ?? '', "\n")) {
|
||||
continue;
|
||||
}
|
||||
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
|
||||
$escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell)));
|
||||
$cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
|
||||
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default></>\n", $cell));
|
||||
foreach ($lines as $lineKey => $line) {
|
||||
if ($cell instanceof TableCell) {
|
||||
$line = new TableCell($line, array('colspan' => $cell->getColspan()));
|
||||
if ($colspan > 1) {
|
||||
$line = new TableCell($line, ['colspan' => $colspan]);
|
||||
}
|
||||
if (0 === $lineKey) {
|
||||
$rows[$rowKey][$column] = $line;
|
||||
} else {
|
||||
if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) {
|
||||
$unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey);
|
||||
}
|
||||
$unmergedRows[$rowKey][$lineKey][$column] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TableRows(function () use ($rows, $unmergedRows) {
|
||||
return new TableRows(function () use ($rows, $unmergedRows): \Traversable {
|
||||
foreach ($rows as $rowKey => $row) {
|
||||
yield $this->fillCells($row);
|
||||
$rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)];
|
||||
|
||||
if (isset($unmergedRows[$rowKey])) {
|
||||
foreach ($unmergedRows[$rowKey] as $row) {
|
||||
yield $row;
|
||||
$rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row);
|
||||
}
|
||||
}
|
||||
yield $rowGroup;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function calculateRowCount(): int
|
||||
{
|
||||
$numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, array(new TableSeparator()), $this->rows))));
|
||||
$numberOfRows = \count(iterator_to_array($this->buildTableRows(array_merge($this->headers, [new TableSeparator()], $this->rows))));
|
||||
|
||||
if ($this->headers) {
|
||||
++$numberOfRows; // Add row for header separator
|
||||
}
|
||||
|
||||
++$numberOfRows; // Add row for footer separator
|
||||
if (\count($this->rows) > 0) {
|
||||
++$numberOfRows; // Add row for footer separator
|
||||
}
|
||||
|
||||
return $numberOfRows;
|
||||
}
|
||||
@@ -575,27 +639,27 @@ class Table
|
||||
*/
|
||||
private function fillNextRows(array $rows, int $line): array
|
||||
{
|
||||
$unmergedRows = array();
|
||||
$unmergedRows = [];
|
||||
foreach ($rows[$line] as $column => $cell) {
|
||||
if (null !== $cell && !$cell instanceof TableCell && !is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
|
||||
throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing __toString, %s given.', \gettype($cell)));
|
||||
if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
|
||||
throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \gettype($cell)));
|
||||
}
|
||||
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
|
||||
$nbLines = $cell->getRowspan() - 1;
|
||||
$lines = array($cell);
|
||||
$lines = [$cell];
|
||||
if (strstr($cell, "\n")) {
|
||||
$lines = explode("\n", str_replace("\n", "<fg=default;bg=default>\n</>", $cell));
|
||||
$nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
|
||||
|
||||
$rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan()));
|
||||
$rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan()]);
|
||||
unset($lines[0]);
|
||||
}
|
||||
|
||||
// create a two dimensional array (rowspan x colspan)
|
||||
$unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, array()), $unmergedRows);
|
||||
$unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);
|
||||
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
|
||||
$value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
|
||||
$unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan()));
|
||||
$value = $lines[$unmergedRowKey - $line] ?? '';
|
||||
$unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan()]);
|
||||
if ($nbLines === $unmergedRowKey - $line) {
|
||||
break;
|
||||
}
|
||||
@@ -608,7 +672,7 @@ class Table
|
||||
if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
|
||||
foreach ($unmergedRow as $cellKey => $cell) {
|
||||
// insert cell into row at cellKey position
|
||||
array_splice($rows[$unmergedRowKey], $cellKey, 0, array($cell));
|
||||
array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]);
|
||||
}
|
||||
} else {
|
||||
$row = $this->copyRow($rows, $unmergedRowKey - 1);
|
||||
@@ -617,7 +681,7 @@ class Table
|
||||
$row[$column] = $unmergedRow[$column];
|
||||
}
|
||||
}
|
||||
array_splice($rows, $unmergedRowKey, 0, array($row));
|
||||
array_splice($rows, $unmergedRowKey, 0, [$row]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,9 +691,10 @@ class Table
|
||||
/**
|
||||
* fill cells for a row that contains colspan > 1.
|
||||
*/
|
||||
private function fillCells($row)
|
||||
private function fillCells(iterable $row)
|
||||
{
|
||||
$newRow = array();
|
||||
$newRow = [];
|
||||
|
||||
foreach ($row as $column => $cell) {
|
||||
$newRow[] = $cell;
|
||||
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||
@@ -649,7 +714,7 @@ class Table
|
||||
foreach ($row as $cellKey => $cellValue) {
|
||||
$row[$cellKey] = '';
|
||||
if ($cellValue instanceof TableCell) {
|
||||
$row[$cellKey] = new TableCell('', array('colspan' => $cellValue->getColspan()));
|
||||
$row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,29 +753,31 @@ class Table
|
||||
/**
|
||||
* Calculates columns widths.
|
||||
*/
|
||||
private function calculateColumnsWidth(iterable $rows)
|
||||
private function calculateColumnsWidth(iterable $groups)
|
||||
{
|
||||
for ($column = 0; $column < $this->numberOfColumns; ++$column) {
|
||||
$lengths = array();
|
||||
foreach ($rows as $row) {
|
||||
if ($row instanceof TableSeparator) {
|
||||
continue;
|
||||
}
|
||||
$lengths = [];
|
||||
foreach ($groups as $group) {
|
||||
foreach ($group as $row) {
|
||||
if ($row instanceof TableSeparator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($row as $i => $cell) {
|
||||
if ($cell instanceof TableCell) {
|
||||
$textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
|
||||
$textLength = Helper::strlen($textContent);
|
||||
if ($textLength > 0) {
|
||||
$contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
|
||||
foreach ($contentColumns as $position => $content) {
|
||||
$row[$i + $position] = $content;
|
||||
foreach ($row as $i => $cell) {
|
||||
if ($cell instanceof TableCell) {
|
||||
$textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
|
||||
$textLength = Helper::strlen($textContent);
|
||||
if ($textLength > 0) {
|
||||
$contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
|
||||
foreach ($contentColumns as $position => $content) {
|
||||
$row[$i + $position] = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$lengths[] = $this->getCellWidth($row, $column);
|
||||
$lengths[] = $this->getCellWidth($row, $column);
|
||||
}
|
||||
}
|
||||
|
||||
$this->effectiveColumnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
|
||||
@@ -731,7 +798,7 @@ class Table
|
||||
$cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
|
||||
}
|
||||
|
||||
$columnWidth = isset($this->columnWidths[$column]) ? $this->columnWidths[$column] : 0;
|
||||
$columnWidth = $this->columnWidths[$column] ?? 0;
|
||||
$cellWidth = max($cellWidth, $columnWidth);
|
||||
|
||||
return isset($this->columnMaxWidths[$column]) ? min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth;
|
||||
@@ -742,11 +809,11 @@ class Table
|
||||
*/
|
||||
private function cleanup()
|
||||
{
|
||||
$this->effectiveColumnWidths = array();
|
||||
$this->effectiveColumnWidths = [];
|
||||
$this->numberOfColumns = null;
|
||||
}
|
||||
|
||||
private static function initStyles()
|
||||
private static function initStyles(): array
|
||||
{
|
||||
$borderless = new TableStyle();
|
||||
$borderless
|
||||
@@ -758,9 +825,9 @@ class Table
|
||||
$compact = new TableStyle();
|
||||
$compact
|
||||
->setHorizontalBorderChars('')
|
||||
->setVerticalBorderChars(' ')
|
||||
->setVerticalBorderChars('')
|
||||
->setDefaultCrossingChar('')
|
||||
->setCellRowContentFormat('%s')
|
||||
->setCellRowContentFormat('%s ')
|
||||
;
|
||||
|
||||
$styleGuide = new TableStyle();
|
||||
@@ -783,17 +850,17 @@ class Table
|
||||
->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣')
|
||||
;
|
||||
|
||||
return array(
|
||||
return [
|
||||
'default' => new TableStyle(),
|
||||
'borderless' => $borderless,
|
||||
'compact' => $compact,
|
||||
'symfony-style-guide' => $styleGuide,
|
||||
'box' => $box,
|
||||
'box-double' => $boxDouble,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
private function resolveStyle($name)
|
||||
private function resolveStyle($name): TableStyle
|
||||
{
|
||||
if ($name instanceof TableStyle) {
|
||||
return $name;
|
||||
|
6
vendor/symfony/console/Helper/TableCell.php
vendored
6
vendor/symfony/console/Helper/TableCell.php
vendored
@@ -19,12 +19,12 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
class TableCell
|
||||
{
|
||||
private $value;
|
||||
private $options = array(
|
||||
private $options = [
|
||||
'rowspan' => 1,
|
||||
'colspan' => 1,
|
||||
);
|
||||
];
|
||||
|
||||
public function __construct(string $value = '', array $options = array())
|
||||
public function __construct(string $value = '', array $options = [])
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
|
2
vendor/symfony/console/Helper/TableRows.php
vendored
2
vendor/symfony/console/Helper/TableRows.php
vendored
@@ -23,7 +23,7 @@ class TableRows implements \IteratorAggregate
|
||||
$this->generator = $generator;
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
public function getIterator(): \Traversable
|
||||
{
|
||||
$g = $this->generator;
|
||||
|
||||
|
@@ -18,7 +18,7 @@ namespace Symfony\Component\Console\Helper;
|
||||
*/
|
||||
class TableSeparator extends TableCell
|
||||
{
|
||||
public function __construct(array $options = array())
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
parent::__construct('', $options);
|
||||
}
|
||||
|
26
vendor/symfony/console/Helper/TableStyle.php
vendored
26
vendor/symfony/console/Helper/TableStyle.php
vendored
@@ -46,7 +46,7 @@ class TableStyle
|
||||
private $cellRowFormat = '%s';
|
||||
private $cellRowContentFormat = ' %s ';
|
||||
private $borderFormat = '%s';
|
||||
private $padType = STR_PAD_RIGHT;
|
||||
private $padType = \STR_PAD_RIGHT;
|
||||
|
||||
/**
|
||||
* Sets padding character, used for cell padding.
|
||||
@@ -58,7 +58,7 @@ class TableStyle
|
||||
public function setPaddingChar($paddingChar)
|
||||
{
|
||||
if (!$paddingChar) {
|
||||
throw new LogicException('The padding char must not be empty');
|
||||
throw new LogicException('The padding char must not be empty.');
|
||||
}
|
||||
|
||||
$this->paddingChar = $paddingChar;
|
||||
@@ -112,7 +112,7 @@ class TableStyle
|
||||
*/
|
||||
public function setHorizontalBorderChar($horizontalBorderChar)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
|
||||
|
||||
return $this->setHorizontalBorderChars($horizontalBorderChar, $horizontalBorderChar);
|
||||
}
|
||||
@@ -126,7 +126,7 @@ class TableStyle
|
||||
*/
|
||||
public function getHorizontalBorderChar()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
|
||||
|
||||
return $this->horizontalOutsideBorderChar;
|
||||
}
|
||||
@@ -168,7 +168,7 @@ class TableStyle
|
||||
*/
|
||||
public function setVerticalBorderChar($verticalBorderChar)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
|
||||
|
||||
return $this->setVerticalBorderChars($verticalBorderChar, $verticalBorderChar);
|
||||
}
|
||||
@@ -182,7 +182,7 @@ class TableStyle
|
||||
*/
|
||||
public function getVerticalBorderChar()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
|
||||
|
||||
return $this->verticalOutsideBorderChar;
|
||||
}
|
||||
@@ -192,14 +192,14 @@ class TableStyle
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getBorderChars()
|
||||
public function getBorderChars(): array
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
$this->horizontalOutsideBorderChar,
|
||||
$this->verticalOutsideBorderChar,
|
||||
$this->horizontalInsideBorderChar,
|
||||
$this->verticalInsideBorderChar,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +270,7 @@ class TableStyle
|
||||
*/
|
||||
public function setCrossingChar($crossingChar)
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), \E_USER_DEPRECATED);
|
||||
|
||||
return $this->setDefaultCrossingChar($crossingChar);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ class TableStyle
|
||||
*/
|
||||
public function getCrossingChars(): array
|
||||
{
|
||||
return array(
|
||||
return [
|
||||
$this->crossingChar,
|
||||
$this->crossingTopLeftChar,
|
||||
$this->crossingTopMidChar,
|
||||
@@ -305,7 +305,7 @@ class TableStyle
|
||||
$this->crossingTopLeftBottomChar,
|
||||
$this->crossingTopMidBottomChar,
|
||||
$this->crossingTopRightBottomChar,
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -413,7 +413,7 @@ class TableStyle
|
||||
*/
|
||||
public function setPadType($padType)
|
||||
{
|
||||
if (!\in_array($padType, array(STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH), true)) {
|
||||
if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) {
|
||||
throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
|
||||
}
|
||||
|
||||
|
74
vendor/symfony/console/Input/ArgvInput.php
vendored
74
vendor/symfony/console/Input/ArgvInput.php
vendored
@@ -44,14 +44,11 @@ class ArgvInput extends Input
|
||||
private $parsed;
|
||||
|
||||
/**
|
||||
* @param array|null $argv An array of parameters from the CLI (in the argv format)
|
||||
* @param InputDefinition|null $definition A InputDefinition instance
|
||||
* @param array|null $argv An array of parameters from the CLI (in the argv format)
|
||||
*/
|
||||
public function __construct(array $argv = null, InputDefinition $definition = null)
|
||||
{
|
||||
if (null === $argv) {
|
||||
$argv = $_SERVER['argv'];
|
||||
}
|
||||
$argv = $argv ?? $_SERVER['argv'] ?? [];
|
||||
|
||||
// strip the application name
|
||||
array_shift($argv);
|
||||
@@ -78,7 +75,7 @@ class ArgvInput extends Input
|
||||
$this->parseArgument($token);
|
||||
} elseif ($parseOptions && '--' == $token) {
|
||||
$parseOptions = false;
|
||||
} elseif ($parseOptions && 0 === strpos($token, '--')) {
|
||||
} elseif ($parseOptions && str_starts_with($token, '--')) {
|
||||
$this->parseLongOption($token);
|
||||
} elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
|
||||
$this->parseShortOption($token);
|
||||
@@ -90,10 +87,8 @@ class ArgvInput extends Input
|
||||
|
||||
/**
|
||||
* Parses a short option.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
private function parseShortOption($token)
|
||||
private function parseShortOption(string $token)
|
||||
{
|
||||
$name = substr($token, 1);
|
||||
|
||||
@@ -112,11 +107,9 @@ class ArgvInput extends Input
|
||||
/**
|
||||
* Parses a short option set.
|
||||
*
|
||||
* @param string $name The current token
|
||||
*
|
||||
* @throws RuntimeException When option given doesn't exist
|
||||
*/
|
||||
private function parseShortOptionSet($name)
|
||||
private function parseShortOptionSet(string $name)
|
||||
{
|
||||
$len = \strlen($name);
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
@@ -138,15 +131,13 @@ class ArgvInput extends Input
|
||||
|
||||
/**
|
||||
* Parses a long option.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*/
|
||||
private function parseLongOption($token)
|
||||
private function parseLongOption(string $token)
|
||||
{
|
||||
$name = substr($token, 2);
|
||||
|
||||
if (false !== $pos = strpos($name, '=')) {
|
||||
if (0 === \strlen($value = substr($name, $pos + 1))) {
|
||||
if ('' === $value = substr($name, $pos + 1)) {
|
||||
array_unshift($this->parsed, $value);
|
||||
}
|
||||
$this->addLongOption(substr($name, 0, $pos), $value);
|
||||
@@ -158,18 +149,16 @@ class ArgvInput extends Input
|
||||
/**
|
||||
* Parses an argument.
|
||||
*
|
||||
* @param string $token The current token
|
||||
*
|
||||
* @throws RuntimeException When too many arguments are given
|
||||
*/
|
||||
private function parseArgument($token)
|
||||
private function parseArgument(string $token)
|
||||
{
|
||||
$c = \count($this->arguments);
|
||||
|
||||
// if input is expecting another argument, add it
|
||||
if ($this->definition->hasArgument($c)) {
|
||||
$arg = $this->definition->getArgument($c);
|
||||
$this->arguments[$arg->getName()] = $arg->isArray() ? array($token) : $token;
|
||||
$this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token;
|
||||
|
||||
// if last argument isArray(), append token to last argument
|
||||
} elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
|
||||
@@ -190,12 +179,9 @@ class ArgvInput extends Input
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws RuntimeException When option given doesn't exist
|
||||
*/
|
||||
private function addShortOption($shortcut, $value)
|
||||
private function addShortOption(string $shortcut, $value)
|
||||
{
|
||||
if (!$this->definition->hasShortcut($shortcut)) {
|
||||
throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
@@ -207,12 +193,9 @@ class ArgvInput extends Input
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws RuntimeException When option given doesn't exist
|
||||
*/
|
||||
private function addLongOption($name, $value)
|
||||
private function addLongOption(string $name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
|
||||
@@ -224,11 +207,11 @@ class ArgvInput extends Input
|
||||
throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
|
||||
}
|
||||
|
||||
if (\in_array($value, array('', null), true) && $option->acceptValue() && \count($this->parsed)) {
|
||||
if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) {
|
||||
// if option accepts an optional or mandatory argument
|
||||
// let's see if there is one provided
|
||||
$next = array_shift($this->parsed);
|
||||
if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, array('', null), true)) {
|
||||
if ((isset($next[0]) && '-' !== $next[0]) || \in_array($next, ['', null], true)) {
|
||||
$value = $next;
|
||||
} else {
|
||||
array_unshift($this->parsed, $next);
|
||||
@@ -257,13 +240,34 @@ class ArgvInput extends Input
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->tokens as $token) {
|
||||
$isOption = false;
|
||||
foreach ($this->tokens as $i => $token) {
|
||||
if ($token && '-' === $token[0]) {
|
||||
if (str_contains($token, '=') || !isset($this->tokens[$i + 1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's a long option, consider that everything after "--" is the option name.
|
||||
// Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
|
||||
$name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
|
||||
if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
|
||||
// noop
|
||||
} elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
|
||||
$isOption = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isOption) {
|
||||
$isOption = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,8 +285,8 @@ class ArgvInput extends Input
|
||||
// Options with values:
|
||||
// For long options, test for '--option=' at beginning
|
||||
// For short options, test for '-o' at beginning
|
||||
$leading = 0 === strpos($value, '--') ? $value.'=' : $value;
|
||||
if ($token === $value || '' !== $leading && 0 === strpos($token, $leading)) {
|
||||
$leading = str_starts_with($value, '--') ? $value.'=' : $value;
|
||||
if ($token === $value || '' !== $leading && str_starts_with($token, $leading)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -312,8 +316,8 @@ class ArgvInput extends Input
|
||||
// Options with values:
|
||||
// For long options, test for '--option=' at beginning
|
||||
// For short options, test for '-o' at beginning
|
||||
$leading = 0 === strpos($value, '--') ? $value.'=' : $value;
|
||||
if ('' !== $leading && 0 === strpos($token, $leading)) {
|
||||
$leading = str_starts_with($value, '--') ? $value.'=' : $value;
|
||||
if ('' !== $leading && str_starts_with($token, $leading)) {
|
||||
return substr($token, \strlen($leading));
|
||||
}
|
||||
}
|
||||
|
37
vendor/symfony/console/Input/ArrayInput.php
vendored
37
vendor/symfony/console/Input/ArrayInput.php
vendored
@@ -19,7 +19,7 @@ use Symfony\Component\Console\Exception\InvalidOptionException;
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $input = new ArrayInput(array('name' => 'foo', '--bar' => 'foobar'));
|
||||
* $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']);
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
@@ -39,13 +39,15 @@ class ArrayInput extends Input
|
||||
*/
|
||||
public function getFirstArgument()
|
||||
{
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
if ($key && '-' === $key[0]) {
|
||||
foreach ($this->parameters as $param => $value) {
|
||||
if ($param && \is_string($param) && '-' === $param[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,18 +105,19 @@ class ArrayInput extends Input
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$params = array();
|
||||
$params = [];
|
||||
foreach ($this->parameters as $param => $val) {
|
||||
if ($param && '-' === $param[0]) {
|
||||
if ($param && \is_string($param) && '-' === $param[0]) {
|
||||
$glue = ('-' === $param[1]) ? '=' : ' ';
|
||||
if (\is_array($val)) {
|
||||
foreach ($val as $v) {
|
||||
$params[] = $param.('' != $v ? '='.$this->escapeToken($v) : '');
|
||||
$params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');
|
||||
}
|
||||
} else {
|
||||
$params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
|
||||
$params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');
|
||||
}
|
||||
} else {
|
||||
$params[] = \is_array($val) ? implode(' ', array_map(array($this, 'escapeToken'), $val)) : $this->escapeToken($val);
|
||||
$params[] = \is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,9 +133,9 @@ class ArrayInput extends Input
|
||||
if ('--' === $key) {
|
||||
return;
|
||||
}
|
||||
if (0 === strpos($key, '--')) {
|
||||
if (str_starts_with($key, '--')) {
|
||||
$this->addLongOption(substr($key, 2), $value);
|
||||
} elseif ('-' === $key[0]) {
|
||||
} elseif (str_starts_with($key, '-')) {
|
||||
$this->addShortOption(substr($key, 1), $value);
|
||||
} else {
|
||||
$this->addArgument($key, $value);
|
||||
@@ -143,12 +146,9 @@ class ArrayInput extends Input
|
||||
/**
|
||||
* Adds a short option value.
|
||||
*
|
||||
* @param string $shortcut The short option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws InvalidOptionException When option given doesn't exist
|
||||
*/
|
||||
private function addShortOption($shortcut, $value)
|
||||
private function addShortOption(string $shortcut, $value)
|
||||
{
|
||||
if (!$this->definition->hasShortcut($shortcut)) {
|
||||
throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
@@ -160,13 +160,10 @@ class ArrayInput extends Input
|
||||
/**
|
||||
* Adds a long option value.
|
||||
*
|
||||
* @param string $name The long option key
|
||||
* @param mixed $value The value for the option
|
||||
*
|
||||
* @throws InvalidOptionException When option given doesn't exist
|
||||
* @throws InvalidOptionException When a required value is missing
|
||||
*/
|
||||
private function addLongOption($name, $value)
|
||||
private function addLongOption(string $name, $value)
|
||||
{
|
||||
if (!$this->definition->hasOption($name)) {
|
||||
throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
|
||||
@@ -190,8 +187,8 @@ class ArrayInput extends Input
|
||||
/**
|
||||
* Adds an argument value.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param mixed $value The value for the argument
|
||||
* @param string|int $name The argument name
|
||||
* @param mixed $value The value for the argument
|
||||
*
|
||||
* @throws InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
|
20
vendor/symfony/console/Input/Input.php
vendored
20
vendor/symfony/console/Input/Input.php
vendored
@@ -29,8 +29,8 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
{
|
||||
protected $definition;
|
||||
protected $stream;
|
||||
protected $options = array();
|
||||
protected $arguments = array();
|
||||
protected $options = [];
|
||||
protected $arguments = [];
|
||||
protected $interactive = true;
|
||||
|
||||
public function __construct(InputDefinition $definition = null)
|
||||
@@ -48,8 +48,8 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
*/
|
||||
public function bind(InputDefinition $definition)
|
||||
{
|
||||
$this->arguments = array();
|
||||
$this->options = array();
|
||||
$this->arguments = [];
|
||||
$this->options = [];
|
||||
$this->definition = $definition;
|
||||
|
||||
$this->parse();
|
||||
@@ -69,7 +69,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
$givenArguments = $this->arguments;
|
||||
|
||||
$missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
|
||||
return !array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
|
||||
return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
|
||||
});
|
||||
|
||||
if (\count($missingArguments) > 0) {
|
||||
@@ -106,11 +106,11 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
*/
|
||||
public function getArgument($name)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
if (!$this->definition->hasArgument((string) $name)) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
|
||||
return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +118,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
*/
|
||||
public function setArgument($name, $value)
|
||||
{
|
||||
if (!$this->definition->hasArgument($name)) {
|
||||
if (!$this->definition->hasArgument((string) $name)) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
*/
|
||||
public function hasArgument($name)
|
||||
{
|
||||
return $this->definition->hasArgument($name);
|
||||
return $this->definition->hasArgument((string) $name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +150,7 @@ abstract class Input implements InputInterface, StreamableInputInterface
|
||||
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
|
||||
}
|
||||
|
||||
return array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
22
vendor/symfony/console/Input/InputArgument.php
vendored
22
vendor/symfony/console/Input/InputArgument.php
vendored
@@ -21,9 +21,9 @@ use Symfony\Component\Console\Exception\LogicException;
|
||||
*/
|
||||
class InputArgument
|
||||
{
|
||||
const REQUIRED = 1;
|
||||
const OPTIONAL = 2;
|
||||
const IS_ARRAY = 4;
|
||||
public const REQUIRED = 1;
|
||||
public const OPTIONAL = 2;
|
||||
public const IS_ARRAY = 4;
|
||||
|
||||
private $name;
|
||||
private $mode;
|
||||
@@ -31,10 +31,10 @@ class InputArgument
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* @param string $name The argument name
|
||||
* @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param string|string[]|null $default The default value (for self::OPTIONAL mode only)
|
||||
* @param string $name The argument name
|
||||
* @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL
|
||||
* @param string $description A description text
|
||||
* @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only)
|
||||
*
|
||||
* @throws InvalidArgumentException When argument mode is not valid
|
||||
*/
|
||||
@@ -86,19 +86,19 @@ class InputArgument
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param string|string[]|null $default The default value
|
||||
* @param string|bool|int|float|array|null $default
|
||||
*
|
||||
* @throws LogicException When incorrect default value is given
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
if (self::REQUIRED === $this->mode && null !== $default) {
|
||||
if ($this->isRequired() && null !== $default) {
|
||||
throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
|
||||
}
|
||||
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = array();
|
||||
$default = [];
|
||||
} elseif (!\is_array($default)) {
|
||||
throw new LogicException('A default value for an array argument must be an array.');
|
||||
}
|
||||
@@ -110,7 +110,7 @@ class InputArgument
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return string|string[]|null The default value
|
||||
* @return string|bool|int|float|array|null
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
|
48
vendor/symfony/console/Input/InputDefinition.php
vendored
48
vendor/symfony/console/Input/InputDefinition.php
vendored
@@ -19,10 +19,10 @@ use Symfony\Component\Console\Exception\LogicException;
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $definition = new InputDefinition(array(
|
||||
* $definition = new InputDefinition([
|
||||
* new InputArgument('name', InputArgument::REQUIRED),
|
||||
* new InputOption('foo', 'f', InputOption::VALUE_REQUIRED),
|
||||
* ));
|
||||
* ]);
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
@@ -38,7 +38,7 @@ class InputDefinition
|
||||
/**
|
||||
* @param array $definition An array of InputArgument and InputOption instance
|
||||
*/
|
||||
public function __construct(array $definition = array())
|
||||
public function __construct(array $definition = [])
|
||||
{
|
||||
$this->setDefinition($definition);
|
||||
}
|
||||
@@ -48,8 +48,8 @@ class InputDefinition
|
||||
*/
|
||||
public function setDefinition(array $definition)
|
||||
{
|
||||
$arguments = array();
|
||||
$options = array();
|
||||
$arguments = [];
|
||||
$options = [];
|
||||
foreach ($definition as $item) {
|
||||
if ($item instanceof InputOption) {
|
||||
$options[] = $item;
|
||||
@@ -67,9 +67,9 @@ class InputDefinition
|
||||
*
|
||||
* @param InputArgument[] $arguments An array of InputArgument objects
|
||||
*/
|
||||
public function setArguments($arguments = array())
|
||||
public function setArguments($arguments = [])
|
||||
{
|
||||
$this->arguments = array();
|
||||
$this->arguments = [];
|
||||
$this->requiredCount = 0;
|
||||
$this->hasOptional = false;
|
||||
$this->hasAnArrayArgument = false;
|
||||
@@ -81,7 +81,7 @@ class InputDefinition
|
||||
*
|
||||
* @param InputArgument[] $arguments An array of InputArgument objects
|
||||
*/
|
||||
public function addArguments($arguments = array())
|
||||
public function addArguments($arguments = [])
|
||||
{
|
||||
if (null !== $arguments) {
|
||||
foreach ($arguments as $argument) {
|
||||
@@ -171,7 +171,7 @@ class InputDefinition
|
||||
*/
|
||||
public function getArgumentCount()
|
||||
{
|
||||
return $this->hasAnArrayArgument ? PHP_INT_MAX : \count($this->arguments);
|
||||
return $this->hasAnArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,13 +185,11 @@ class InputDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default values.
|
||||
*
|
||||
* @return array An array of default values
|
||||
* @return array<string|bool|int|float|array|null>
|
||||
*/
|
||||
public function getArgumentDefaults()
|
||||
{
|
||||
$values = array();
|
||||
$values = [];
|
||||
foreach ($this->arguments as $argument) {
|
||||
$values[$argument->getName()] = $argument->getDefault();
|
||||
}
|
||||
@@ -204,10 +202,10 @@ class InputDefinition
|
||||
*
|
||||
* @param InputOption[] $options An array of InputOption objects
|
||||
*/
|
||||
public function setOptions($options = array())
|
||||
public function setOptions($options = [])
|
||||
{
|
||||
$this->options = array();
|
||||
$this->shortcuts = array();
|
||||
$this->options = [];
|
||||
$this->shortcuts = [];
|
||||
$this->addOptions($options);
|
||||
}
|
||||
|
||||
@@ -216,7 +214,7 @@ class InputDefinition
|
||||
*
|
||||
* @param InputOption[] $options An array of InputOption objects
|
||||
*/
|
||||
public function addOptions($options = array())
|
||||
public function addOptions($options = [])
|
||||
{
|
||||
foreach ($options as $option) {
|
||||
$this->addOption($option);
|
||||
@@ -316,13 +314,11 @@ class InputDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of default values.
|
||||
*
|
||||
* @return array An array of all default values
|
||||
* @return array<string|bool|int|float|array|null>
|
||||
*/
|
||||
public function getOptionDefaults()
|
||||
{
|
||||
$values = array();
|
||||
$values = [];
|
||||
foreach ($this->options as $option) {
|
||||
$values[$option->getName()] = $option->getDefault();
|
||||
}
|
||||
@@ -333,13 +329,11 @@ class InputDefinition
|
||||
/**
|
||||
* Returns the InputOption name given a shortcut.
|
||||
*
|
||||
* @param string $shortcut The shortcut
|
||||
*
|
||||
* @return string The InputOption name
|
||||
*
|
||||
* @throws InvalidArgumentException When option given does not exist
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
private function shortcutToName($shortcut)
|
||||
public function shortcutToName(string $shortcut): string
|
||||
{
|
||||
if (!isset($this->shortcuts[$shortcut])) {
|
||||
throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
|
||||
@@ -357,7 +351,7 @@ class InputDefinition
|
||||
*/
|
||||
public function getSynopsis($short = false)
|
||||
{
|
||||
$elements = array();
|
||||
$elements = [];
|
||||
|
||||
if ($short && $this->getOptions()) {
|
||||
$elements[] = '[options]';
|
||||
|
24
vendor/symfony/console/Input/InputInterface.php
vendored
24
vendor/symfony/console/Input/InputInterface.php
vendored
@@ -51,9 +51,9 @@ interface InputInterface
|
||||
* Does not necessarily return the correct result for short options
|
||||
* when multiple flags are combined in the same option.
|
||||
*
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
* @param mixed $default The default value to return if no result is found
|
||||
* @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal
|
||||
* @param string|array $values The value(s) to look for in the raw parameters (can be an array)
|
||||
* @param string|bool|int|float|array|null $default The default value to return if no result is found
|
||||
* @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal
|
||||
*
|
||||
* @return mixed The option value
|
||||
*/
|
||||
@@ -76,7 +76,7 @@ interface InputInterface
|
||||
/**
|
||||
* Returns all the given arguments merged with the default values.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string|bool|int|float|array|null>
|
||||
*/
|
||||
public function getArguments();
|
||||
|
||||
@@ -85,7 +85,7 @@ interface InputInterface
|
||||
*
|
||||
* @param string $name The argument name
|
||||
*
|
||||
* @return string|string[]|null The argument value
|
||||
* @return mixed
|
||||
*
|
||||
* @throws InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
@@ -94,8 +94,8 @@ interface InputInterface
|
||||
/**
|
||||
* Sets an argument value by name.
|
||||
*
|
||||
* @param string $name The argument name
|
||||
* @param string|string[]|null $value The argument value
|
||||
* @param string $name The argument name
|
||||
* @param mixed $value The argument value
|
||||
*
|
||||
* @throws InvalidArgumentException When argument given doesn't exist
|
||||
*/
|
||||
@@ -104,7 +104,7 @@ interface InputInterface
|
||||
/**
|
||||
* Returns true if an InputArgument object exists by name or position.
|
||||
*
|
||||
* @param string|int $name The InputArgument name or position
|
||||
* @param string $name The argument name
|
||||
*
|
||||
* @return bool true if the InputArgument object exists, false otherwise
|
||||
*/
|
||||
@@ -113,7 +113,7 @@ interface InputInterface
|
||||
/**
|
||||
* Returns all the given options merged with the default values.
|
||||
*
|
||||
* @return array
|
||||
* @return array<string|bool|int|float|array|null>
|
||||
*/
|
||||
public function getOptions();
|
||||
|
||||
@@ -122,7 +122,7 @@ interface InputInterface
|
||||
*
|
||||
* @param string $name The option name
|
||||
*
|
||||
* @return string|string[]|bool|null The option value
|
||||
* @return mixed
|
||||
*
|
||||
* @throws InvalidArgumentException When option given doesn't exist
|
||||
*/
|
||||
@@ -131,8 +131,8 @@ interface InputInterface
|
||||
/**
|
||||
* Sets an option value by name.
|
||||
*
|
||||
* @param string $name The option name
|
||||
* @param string|string[]|bool|null $value The option value
|
||||
* @param string $name The option name
|
||||
* @param mixed $value The option value
|
||||
*
|
||||
* @throws InvalidArgumentException When option given doesn't exist
|
||||
*/
|
||||
|
47
vendor/symfony/console/Input/InputOption.php
vendored
47
vendor/symfony/console/Input/InputOption.php
vendored
@@ -21,10 +21,25 @@ use Symfony\Component\Console\Exception\LogicException;
|
||||
*/
|
||||
class InputOption
|
||||
{
|
||||
const VALUE_NONE = 1;
|
||||
const VALUE_REQUIRED = 2;
|
||||
const VALUE_OPTIONAL = 4;
|
||||
const VALUE_IS_ARRAY = 8;
|
||||
/**
|
||||
* Do not accept input for the option (e.g. --yell). This is the default behavior of options.
|
||||
*/
|
||||
public const VALUE_NONE = 1;
|
||||
|
||||
/**
|
||||
* A value must be passed when the option is used (e.g. --iterations=5 or -i5).
|
||||
*/
|
||||
public const VALUE_REQUIRED = 2;
|
||||
|
||||
/**
|
||||
* The option may or may not have a value (e.g. --yell or --yell=loud).
|
||||
*/
|
||||
public const VALUE_OPTIONAL = 4;
|
||||
|
||||
/**
|
||||
* The option accepts multiple values (e.g. --dir=/foo --dir=/bar).
|
||||
*/
|
||||
public const VALUE_IS_ARRAY = 8;
|
||||
|
||||
private $name;
|
||||
private $shortcut;
|
||||
@@ -33,17 +48,17 @@ class InputOption
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* @param string $name The option name
|
||||
* @param string|array $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
|
||||
* @param int|null $mode The option mode: One of the VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param string|string[]|int|bool|null $default The default value (must be null for self::VALUE_NONE)
|
||||
* @param string $name The option name
|
||||
* @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
|
||||
* @param int|null $mode The option mode: One of the VALUE_* constants
|
||||
* @param string $description A description text
|
||||
* @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE)
|
||||
*
|
||||
* @throws InvalidArgumentException If option mode is invalid or incompatible
|
||||
*/
|
||||
public function __construct(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null)
|
||||
{
|
||||
if (0 === strpos($name, '--')) {
|
||||
if (str_starts_with($name, '--')) {
|
||||
$name = substr($name, 2);
|
||||
}
|
||||
|
||||
@@ -89,7 +104,7 @@ class InputOption
|
||||
/**
|
||||
* Returns the option shortcut.
|
||||
*
|
||||
* @return string The shortcut
|
||||
* @return string|null The shortcut
|
||||
*/
|
||||
public function getShortcut()
|
||||
{
|
||||
@@ -147,11 +162,7 @@ class InputOption
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param string|string[]|int|bool|null $default The default value
|
||||
*
|
||||
* @throws LogicException When incorrect default value is given
|
||||
* @param string|bool|int|float|array|null $default
|
||||
*/
|
||||
public function setDefault($default = null)
|
||||
{
|
||||
@@ -161,7 +172,7 @@ class InputOption
|
||||
|
||||
if ($this->isArray()) {
|
||||
if (null === $default) {
|
||||
$default = array();
|
||||
$default = [];
|
||||
} elseif (!\is_array($default)) {
|
||||
throw new LogicException('A default value for an array option must be an array.');
|
||||
}
|
||||
@@ -173,7 +184,7 @@ class InputOption
|
||||
/**
|
||||
* Returns the default value.
|
||||
*
|
||||
* @return string|string[]|int|bool|null The default value
|
||||
* @return string|bool|int|float|array|null
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
|
46
vendor/symfony/console/Input/StringInput.php
vendored
46
vendor/symfony/console/Input/StringInput.php
vendored
@@ -24,15 +24,16 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class StringInput extends ArgvInput
|
||||
{
|
||||
const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
|
||||
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
|
||||
public const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
|
||||
public const REGEX_UNQUOTED_STRING = '([^\s\\\\]+?)';
|
||||
public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
|
||||
|
||||
/**
|
||||
* @param string $input A string representing the parameters from the CLI
|
||||
*/
|
||||
public function __construct(string $input)
|
||||
{
|
||||
parent::__construct(array());
|
||||
parent::__construct([]);
|
||||
|
||||
$this->setTokens($this->tokenize($input));
|
||||
}
|
||||
@@ -40,33 +41,44 @@ class StringInput extends ArgvInput
|
||||
/**
|
||||
* Tokenizes a string.
|
||||
*
|
||||
* @param string $input The input to tokenize
|
||||
*
|
||||
* @return array An array of tokens
|
||||
*
|
||||
* @throws InvalidArgumentException When unable to parse input (should never happen)
|
||||
*/
|
||||
private function tokenize($input)
|
||||
private function tokenize(string $input): array
|
||||
{
|
||||
$tokens = array();
|
||||
$tokens = [];
|
||||
$length = \strlen($input);
|
||||
$cursor = 0;
|
||||
$token = null;
|
||||
while ($cursor < $length) {
|
||||
if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
|
||||
} elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, \strlen($match[3]) - 2)));
|
||||
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = stripcslashes(substr($match[0], 1, \strlen($match[0]) - 2));
|
||||
} elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
|
||||
$tokens[] = stripcslashes($match[1]);
|
||||
if ('\\' === $input[$cursor]) {
|
||||
$token .= $input[++$cursor] ?? '';
|
||||
++$cursor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/\s+/A', $input, $match, 0, $cursor)) {
|
||||
if (null !== $token) {
|
||||
$tokens[] = $token;
|
||||
$token = null;
|
||||
}
|
||||
} elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, 0, $cursor)) {
|
||||
$token .= $match[1].$match[2].stripcslashes(str_replace(['"\'', '\'"', '\'\'', '""'], '', substr($match[3], 1, -1)));
|
||||
} elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
|
||||
$token .= stripcslashes(substr($match[0], 1, -1));
|
||||
} elseif (preg_match('/'.self::REGEX_UNQUOTED_STRING.'/A', $input, $match, 0, $cursor)) {
|
||||
$token .= $match[1];
|
||||
} else {
|
||||
// should never happen
|
||||
throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
|
||||
throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10)));
|
||||
}
|
||||
|
||||
$cursor += \strlen($match[0]);
|
||||
}
|
||||
|
||||
if (null !== $token) {
|
||||
$tokens[] = $token;
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
}
|
||||
|
2
vendor/symfony/console/LICENSE
vendored
2
vendor/symfony/console/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2018 Fabien Potencier
|
||||
Copyright (c) 2004-2022 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
26
vendor/symfony/console/Logger/ConsoleLogger.php
vendored
26
vendor/symfony/console/Logger/ConsoleLogger.php
vendored
@@ -22,15 +22,15 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*
|
||||
* @see http://www.php-fig.org/psr/psr-3/
|
||||
* @see https://www.php-fig.org/psr/psr-3/
|
||||
*/
|
||||
class ConsoleLogger extends AbstractLogger
|
||||
{
|
||||
const INFO = 'info';
|
||||
const ERROR = 'error';
|
||||
public const INFO = 'info';
|
||||
public const ERROR = 'error';
|
||||
|
||||
private $output;
|
||||
private $verbosityLevelMap = array(
|
||||
private $verbosityLevelMap = [
|
||||
LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
|
||||
LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
|
||||
LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
|
||||
@@ -39,8 +39,8 @@ class ConsoleLogger extends AbstractLogger
|
||||
LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
|
||||
LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
|
||||
LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
|
||||
);
|
||||
private $formatLevelMap = array(
|
||||
];
|
||||
private $formatLevelMap = [
|
||||
LogLevel::EMERGENCY => self::ERROR,
|
||||
LogLevel::ALERT => self::ERROR,
|
||||
LogLevel::CRITICAL => self::ERROR,
|
||||
@@ -49,10 +49,10 @@ class ConsoleLogger extends AbstractLogger
|
||||
LogLevel::NOTICE => self::INFO,
|
||||
LogLevel::INFO => self::INFO,
|
||||
LogLevel::DEBUG => self::INFO,
|
||||
);
|
||||
];
|
||||
private $errored = false;
|
||||
|
||||
public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array())
|
||||
public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = [])
|
||||
{
|
||||
$this->output = $output;
|
||||
$this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
|
||||
@@ -61,8 +61,10 @@ class ConsoleLogger extends AbstractLogger
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function log($level, $message, array $context = array())
|
||||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
if (!isset($this->verbosityLevelMap[$level])) {
|
||||
throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
|
||||
@@ -102,13 +104,13 @@ class ConsoleLogger extends AbstractLogger
|
||||
*/
|
||||
private function interpolate(string $message, array $context): string
|
||||
{
|
||||
if (false === strpos($message, '{')) {
|
||||
if (!str_contains($message, '{')) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
$replacements = array();
|
||||
$replacements = [];
|
||||
foreach ($context as $key => $val) {
|
||||
if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
|
||||
if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
|
||||
$replacements["{{$key}}"] = $val;
|
||||
} elseif ($val instanceof \DateTimeInterface) {
|
||||
$replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
|
||||
|
@@ -39,7 +39,7 @@ class BufferedOutput extends Output
|
||||
$this->buffer .= $message;
|
||||
|
||||
if ($newline) {
|
||||
$this->buffer .= PHP_EOL;
|
||||
$this->buffer .= \PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
vendor/symfony/console/Output/ConsoleOutput.php
vendored
29
vendor/symfony/console/Output/ConsoleOutput.php
vendored
@@ -30,7 +30,7 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
{
|
||||
private $stderr;
|
||||
private $consoleSectionOutputs = array();
|
||||
private $consoleSectionOutputs = [];
|
||||
|
||||
/**
|
||||
* @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
|
||||
@@ -41,6 +41,13 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
{
|
||||
parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
|
||||
|
||||
if (null === $formatter) {
|
||||
// for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter.
|
||||
$this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$actualDecorated = $this->isDecorated();
|
||||
$this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
|
||||
|
||||
@@ -125,16 +132,14 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
/**
|
||||
* Checks if current executing environment is IBM iSeries (OS400), which
|
||||
* doesn't properly convert character-encodings between ASCII to EBCDIC.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isRunningOS400()
|
||||
private function isRunningOS400(): bool
|
||||
{
|
||||
$checks = array(
|
||||
$checks = [
|
||||
\function_exists('php_uname') ? php_uname('s') : '',
|
||||
getenv('OSTYPE'),
|
||||
PHP_OS,
|
||||
);
|
||||
\PHP_OS,
|
||||
];
|
||||
|
||||
return false !== stripos(implode(';', $checks), 'OS400');
|
||||
}
|
||||
@@ -148,7 +153,8 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
return fopen('php://output', 'w');
|
||||
}
|
||||
|
||||
return @fopen('php://stdout', 'w') ?: fopen('php://output', 'w');
|
||||
// Use STDOUT when possible to prevent from opening too many file descriptors
|
||||
return \defined('STDOUT') ? \STDOUT : (@fopen('php://stdout', 'w') ?: fopen('php://output', 'w'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,6 +162,11 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
*/
|
||||
private function openErrorStream()
|
||||
{
|
||||
return fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w');
|
||||
if (!$this->hasStderrSupport()) {
|
||||
return fopen('php://output', 'w');
|
||||
}
|
||||
|
||||
// Use STDERR when possible to prevent from opening too many file descriptors
|
||||
return \defined('STDERR') ? \STDERR : (@fopen('php://stderr', 'w') ?: fopen('php://output', 'w'));
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ use Symfony\Component\Console\Terminal;
|
||||
*/
|
||||
class ConsoleSectionOutput extends StreamOutput
|
||||
{
|
||||
private $content = array();
|
||||
private $content = [];
|
||||
private $lines = 0;
|
||||
private $sections;
|
||||
private $terminal;
|
||||
@@ -50,10 +50,10 @@ class ConsoleSectionOutput extends StreamOutput
|
||||
}
|
||||
|
||||
if ($lines) {
|
||||
\array_splice($this->content, -($lines * 2)); // Multiply lines by 2 to cater for each new line added between content
|
||||
array_splice($this->content, -($lines * 2)); // Multiply lines by 2 to cater for each new line added between content
|
||||
} else {
|
||||
$lines = $this->lines;
|
||||
$this->content = array();
|
||||
$this->content = [];
|
||||
}
|
||||
|
||||
$this->lines -= $lines;
|
||||
@@ -82,10 +82,10 @@ class ConsoleSectionOutput extends StreamOutput
|
||||
*/
|
||||
public function addContent(string $input)
|
||||
{
|
||||
foreach (explode(PHP_EOL, $input) as $lineContent) {
|
||||
foreach (explode(\PHP_EOL, $input) as $lineContent) {
|
||||
$this->lines += ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1;
|
||||
$this->content[] = $lineContent;
|
||||
$this->content[] = PHP_EOL;
|
||||
$this->content[] = \PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,9 @@ class ConsoleSectionOutput extends StreamOutput
|
||||
protected function doWrite($message, $newline)
|
||||
{
|
||||
if (!$this->isDecorated()) {
|
||||
return parent::doWrite($message, $newline);
|
||||
parent::doWrite($message, $newline);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$erasedContent = $this->popStreamContentUntilCurrentSection();
|
||||
@@ -113,7 +115,7 @@ class ConsoleSectionOutput extends StreamOutput
|
||||
private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0): string
|
||||
{
|
||||
$numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection;
|
||||
$erasedContent = array();
|
||||
$erasedContent = [];
|
||||
|
||||
foreach ($this->sections as $section) {
|
||||
if ($section === $this) {
|
||||
|
6
vendor/symfony/console/Output/Output.php
vendored
6
vendor/symfony/console/Output/Output.php
vendored
@@ -40,7 +40,7 @@ abstract class Output implements OutputInterface
|
||||
public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
$this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
|
||||
$this->formatter = $formatter ?: new OutputFormatter();
|
||||
$this->formatter = $formatter ?? new OutputFormatter();
|
||||
$this->formatter->setDecorated($decorated);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ abstract class Output implements OutputInterface
|
||||
public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
|
||||
{
|
||||
if (!is_iterable($messages)) {
|
||||
$messages = array($messages);
|
||||
$messages = [$messages];
|
||||
}
|
||||
|
||||
$types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN;
|
||||
@@ -163,7 +163,7 @@ abstract class Output implements OutputInterface
|
||||
break;
|
||||
}
|
||||
|
||||
$this->doWrite($message, $newline);
|
||||
$this->doWrite($message ?? '', $newline);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,15 +20,15 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
*/
|
||||
interface OutputInterface
|
||||
{
|
||||
const VERBOSITY_QUIET = 16;
|
||||
const VERBOSITY_NORMAL = 32;
|
||||
const VERBOSITY_VERBOSE = 64;
|
||||
const VERBOSITY_VERY_VERBOSE = 128;
|
||||
const VERBOSITY_DEBUG = 256;
|
||||
public const VERBOSITY_QUIET = 16;
|
||||
public const VERBOSITY_NORMAL = 32;
|
||||
public const VERBOSITY_VERBOSE = 64;
|
||||
public const VERBOSITY_VERY_VERBOSE = 128;
|
||||
public const VERBOSITY_DEBUG = 256;
|
||||
|
||||
const OUTPUT_NORMAL = 1;
|
||||
const OUTPUT_RAW = 2;
|
||||
const OUTPUT_PLAIN = 4;
|
||||
public const OUTPUT_NORMAL = 1;
|
||||
public const OUTPUT_RAW = 2;
|
||||
public const OUTPUT_PLAIN = 4;
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
|
13
vendor/symfony/console/Output/StreamOutput.php
vendored
13
vendor/symfony/console/Output/StreamOutput.php
vendored
@@ -12,7 +12,6 @@
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
|
||||
/**
|
||||
@@ -71,13 +70,10 @@ class StreamOutput extends Output
|
||||
protected function doWrite($message, $newline)
|
||||
{
|
||||
if ($newline) {
|
||||
$message .= PHP_EOL;
|
||||
$message .= \PHP_EOL;
|
||||
}
|
||||
|
||||
if (false === @fwrite($this->stream, $message)) {
|
||||
// should never happen
|
||||
throw new RuntimeException('Unable to write output.');
|
||||
}
|
||||
@fwrite($this->stream, $message);
|
||||
|
||||
fflush($this->stream);
|
||||
}
|
||||
@@ -97,6 +93,11 @@ class StreamOutput extends Output
|
||||
*/
|
||||
protected function hasColorSupport()
|
||||
{
|
||||
// Follow https://no-color.org/
|
||||
if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ('Hyper' === getenv('TERM_PROGRAM')) {
|
||||
return true;
|
||||
}
|
||||
|
63
vendor/symfony/console/Output/TrimmedBufferOutput.php
vendored
Normal file
63
vendor/symfony/console/Output/TrimmedBufferOutput.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Output;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
|
||||
/**
|
||||
* A BufferedOutput that keeps only the last N chars.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class TrimmedBufferOutput extends Output
|
||||
{
|
||||
private $maxLength;
|
||||
private $buffer = '';
|
||||
|
||||
public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
if ($maxLength <= 0) {
|
||||
throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength));
|
||||
}
|
||||
|
||||
parent::__construct($verbosity, $decorated, $formatter);
|
||||
$this->maxLength = $maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties buffer and returns its content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fetch()
|
||||
{
|
||||
$content = $this->buffer;
|
||||
$this->buffer = '';
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doWrite($message, $newline)
|
||||
{
|
||||
$this->buffer .= $message;
|
||||
|
||||
if ($newline) {
|
||||
$this->buffer .= \PHP_EOL;
|
||||
}
|
||||
|
||||
$this->buffer = substr($this->buffer, 0 - $this->maxLength);
|
||||
}
|
||||
}
|
@@ -129,22 +129,26 @@ class ChoiceQuestion extends Question
|
||||
$isAssoc = $this->isAssoc($choices);
|
||||
|
||||
return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
|
||||
// Collapse all spaces.
|
||||
$selectedChoices = str_replace(' ', '', $selected);
|
||||
|
||||
if ($multiselect) {
|
||||
// Check for a separated comma values
|
||||
if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selectedChoices, $matches)) {
|
||||
if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) {
|
||||
throw new InvalidArgumentException(sprintf($errorMessage, $selected));
|
||||
}
|
||||
$selectedChoices = explode(',', $selectedChoices);
|
||||
|
||||
$selectedChoices = explode(',', (string) $selected);
|
||||
} else {
|
||||
$selectedChoices = array($selected);
|
||||
$selectedChoices = [$selected];
|
||||
}
|
||||
|
||||
$multiselectChoices = array();
|
||||
if ($this->isTrimmable()) {
|
||||
foreach ($selectedChoices as $k => $v) {
|
||||
$selectedChoices[$k] = trim((string) $v);
|
||||
}
|
||||
}
|
||||
|
||||
$multiselectChoices = [];
|
||||
foreach ($selectedChoices as $value) {
|
||||
$results = array();
|
||||
$results = [];
|
||||
foreach ($choices as $key => $choice) {
|
||||
if ($choice === $value) {
|
||||
$results[] = $key;
|
||||
@@ -152,7 +156,7 @@ class ChoiceQuestion extends Question
|
||||
}
|
||||
|
||||
if (\count($results) > 1) {
|
||||
throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
|
||||
throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results)));
|
||||
}
|
||||
|
||||
$result = array_search($value, $choices);
|
||||
|
@@ -35,10 +35,8 @@ class ConfirmationQuestion extends Question
|
||||
|
||||
/**
|
||||
* Returns the default answer normalizer.
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
private function getDefaultNormalizer()
|
||||
private function getDefaultNormalizer(): callable
|
||||
{
|
||||
$default = $this->getDefault();
|
||||
$regex = $this->trueAnswerRegex;
|
||||
@@ -53,7 +51,7 @@ class ConfirmationQuestion extends Question
|
||||
return $answer && $answerIsTrue;
|
||||
}
|
||||
|
||||
return !$answer || $answerIsTrue;
|
||||
return '' === $answer || $answerIsTrue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
80
vendor/symfony/console/Question/Question.php
vendored
80
vendor/symfony/console/Question/Question.php
vendored
@@ -25,14 +25,15 @@ class Question
|
||||
private $attempts;
|
||||
private $hidden = false;
|
||||
private $hiddenFallback = true;
|
||||
private $autocompleterValues;
|
||||
private $autocompleterCallback;
|
||||
private $validator;
|
||||
private $default;
|
||||
private $normalizer;
|
||||
private $trimmable = true;
|
||||
|
||||
/**
|
||||
* @param string $question The question to ask to the user
|
||||
* @param mixed $default The default answer to return if the user enters nothing
|
||||
* @param string $question The question to ask to the user
|
||||
* @param string|bool|int|float|null $default The default answer to return if the user enters nothing
|
||||
*/
|
||||
public function __construct(string $question, $default = null)
|
||||
{
|
||||
@@ -53,7 +54,7 @@ class Question
|
||||
/**
|
||||
* Returns the default answer.
|
||||
*
|
||||
* @return mixed
|
||||
* @return string|bool|int|float|null
|
||||
*/
|
||||
public function getDefault()
|
||||
{
|
||||
@@ -81,7 +82,7 @@ class Question
|
||||
*/
|
||||
public function setHidden($hidden)
|
||||
{
|
||||
if ($this->autocompleterValues) {
|
||||
if ($this->autocompleterCallback) {
|
||||
throw new LogicException('A hidden question cannot use the autocompleter.');
|
||||
}
|
||||
|
||||
@@ -121,7 +122,9 @@ class Question
|
||||
*/
|
||||
public function getAutocompleterValues()
|
||||
{
|
||||
return $this->autocompleterValues;
|
||||
$callback = $this->getAutocompleterCallback();
|
||||
|
||||
return $callback ? $callback('') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,17 +141,46 @@ class Question
|
||||
{
|
||||
if (\is_array($values)) {
|
||||
$values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
|
||||
}
|
||||
|
||||
if (null !== $values && !\is_array($values) && !$values instanceof \Traversable) {
|
||||
$callback = static function () use ($values) {
|
||||
return $values;
|
||||
};
|
||||
} elseif ($values instanceof \Traversable) {
|
||||
$valueCache = null;
|
||||
$callback = static function () use ($values, &$valueCache) {
|
||||
return $valueCache ?? $valueCache = iterator_to_array($values, false);
|
||||
};
|
||||
} elseif (null === $values) {
|
||||
$callback = null;
|
||||
} else {
|
||||
throw new InvalidArgumentException('Autocompleter values can be either an array, "null" or a "Traversable" object.');
|
||||
}
|
||||
|
||||
if ($this->hidden) {
|
||||
return $this->setAutocompleterCallback($callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the callback function used for the autocompleter.
|
||||
*/
|
||||
public function getAutocompleterCallback(): ?callable
|
||||
{
|
||||
return $this->autocompleterCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callback function used for the autocompleter.
|
||||
*
|
||||
* The callback is passed the user input as argument and should return an iterable of corresponding suggestions.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAutocompleterCallback(callable $callback = null): self
|
||||
{
|
||||
if ($this->hidden && null !== $callback) {
|
||||
throw new LogicException('A hidden question cannot use the autocompleter.');
|
||||
}
|
||||
|
||||
$this->autocompleterValues = $values;
|
||||
$this->autocompleterCallback = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -156,8 +188,6 @@ class Question
|
||||
/**
|
||||
* Sets a validator for the question.
|
||||
*
|
||||
* @param callable|null $validator
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setValidator(callable $validator = null)
|
||||
@@ -190,8 +220,11 @@ class Question
|
||||
*/
|
||||
public function setMaxAttempts($attempts)
|
||||
{
|
||||
if (null !== $attempts && $attempts < 1) {
|
||||
throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
|
||||
if (null !== $attempts) {
|
||||
$attempts = (int) $attempts;
|
||||
if ($attempts < 1) {
|
||||
throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->attempts = $attempts;
|
||||
@@ -216,8 +249,6 @@ class Question
|
||||
*
|
||||
* The normalizer can be a callable (a string), a closure or a class implementing __invoke.
|
||||
*
|
||||
* @param callable $normalizer
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNormalizer(callable $normalizer)
|
||||
@@ -232,7 +263,7 @@ class Question
|
||||
*
|
||||
* The normalizer can ba a callable (a string), a closure or a class implementing __invoke.
|
||||
*
|
||||
* @return callable
|
||||
* @return callable|null
|
||||
*/
|
||||
public function getNormalizer()
|
||||
{
|
||||
@@ -243,4 +274,19 @@ class Question
|
||||
{
|
||||
return (bool) \count(array_filter(array_keys($array), 'is_string'));
|
||||
}
|
||||
|
||||
public function isTrimmable(): bool
|
||||
{
|
||||
return $this->trimmable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setTrimmable(bool $trimmable): self
|
||||
{
|
||||
$this->trimmable = $trimmable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
10
vendor/symfony/console/README.md
vendored
10
vendor/symfony/console/README.md
vendored
@@ -7,11 +7,11 @@ interfaces.
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/components/console/index.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
* [Documentation](https://symfony.com/doc/current/components/console.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
2
vendor/symfony/console/Style/OutputStyle.php
vendored
2
vendor/symfony/console/Style/OutputStyle.php
vendored
@@ -35,7 +35,7 @@ abstract class OutputStyle implements OutputInterface, StyleInterface
|
||||
*/
|
||||
public function newLine($count = 1)
|
||||
{
|
||||
$this->output->write(str_repeat(PHP_EOL, $count));
|
||||
$this->output->write(str_repeat(\PHP_EOL, $count));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -119,7 +119,6 @@ interface StyleInterface
|
||||
* Asks a choice question.
|
||||
*
|
||||
* @param string $question
|
||||
* @param array $choices
|
||||
* @param string|int|null $default
|
||||
*
|
||||
* @return mixed
|
||||
|
120
vendor/symfony/console/Style/SymfonyStyle.php
vendored
120
vendor/symfony/console/Style/SymfonyStyle.php
vendored
@@ -11,15 +11,18 @@
|
||||
|
||||
namespace Symfony\Component\Console\Style;
|
||||
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Helper\Helper;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableCell;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\TrimmedBufferOutput;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
@@ -32,7 +35,7 @@ use Symfony\Component\Console\Terminal;
|
||||
*/
|
||||
class SymfonyStyle extends OutputStyle
|
||||
{
|
||||
const MAX_LINE_LENGTH = 120;
|
||||
public const MAX_LINE_LENGTH = 120;
|
||||
|
||||
private $input;
|
||||
private $questionHelper;
|
||||
@@ -43,7 +46,7 @@ class SymfonyStyle extends OutputStyle
|
||||
public function __construct(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
|
||||
$this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());
|
||||
// Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
|
||||
$width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
|
||||
$this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
|
||||
@@ -63,7 +66,7 @@ class SymfonyStyle extends OutputStyle
|
||||
*/
|
||||
public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = true)
|
||||
{
|
||||
$messages = \is_array($messages) ? array_values($messages) : array($messages);
|
||||
$messages = \is_array($messages) ? array_values($messages) : [$messages];
|
||||
|
||||
$this->autoPrependBlock();
|
||||
$this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
|
||||
@@ -76,10 +79,10 @@ class SymfonyStyle extends OutputStyle
|
||||
public function title($message)
|
||||
{
|
||||
$this->autoPrependBlock();
|
||||
$this->writeln(array(
|
||||
$this->writeln([
|
||||
sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
|
||||
sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
|
||||
));
|
||||
]);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
@@ -89,10 +92,10 @@ class SymfonyStyle extends OutputStyle
|
||||
public function section($message)
|
||||
{
|
||||
$this->autoPrependBlock();
|
||||
$this->writeln(array(
|
||||
$this->writeln([
|
||||
sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
|
||||
sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
|
||||
));
|
||||
]);
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
@@ -117,7 +120,7 @@ class SymfonyStyle extends OutputStyle
|
||||
{
|
||||
$this->autoPrependText();
|
||||
|
||||
$messages = \is_array($message) ? array_values($message) : array($message);
|
||||
$messages = \is_array($message) ? array_values($message) : [$message];
|
||||
foreach ($messages as $message) {
|
||||
$this->writeln(sprintf(' %s', $message));
|
||||
}
|
||||
@@ -154,7 +157,7 @@ class SymfonyStyle extends OutputStyle
|
||||
*/
|
||||
public function warning($message)
|
||||
{
|
||||
$this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true);
|
||||
$this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,6 +193,69 @@ class SymfonyStyle extends OutputStyle
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a horizontal table.
|
||||
*/
|
||||
public function horizontalTable(array $headers, array $rows)
|
||||
{
|
||||
$style = clone Table::getStyleDefinition('symfony-style-guide');
|
||||
$style->setCellHeaderFormat('<info>%s</info>');
|
||||
|
||||
$table = new Table($this);
|
||||
$table->setHeaders($headers);
|
||||
$table->setRows($rows);
|
||||
$table->setStyle($style);
|
||||
$table->setHorizontal(true);
|
||||
|
||||
$table->render();
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a list of key/value horizontally.
|
||||
*
|
||||
* Each row can be one of:
|
||||
* * 'A title'
|
||||
* * ['key' => 'value']
|
||||
* * new TableSeparator()
|
||||
*
|
||||
* @param string|array|TableSeparator ...$list
|
||||
*/
|
||||
public function definitionList(...$list)
|
||||
{
|
||||
$style = clone Table::getStyleDefinition('symfony-style-guide');
|
||||
$style->setCellHeaderFormat('<info>%s</info>');
|
||||
|
||||
$table = new Table($this);
|
||||
$headers = [];
|
||||
$row = [];
|
||||
foreach ($list as $value) {
|
||||
if ($value instanceof TableSeparator) {
|
||||
$headers[] = $value;
|
||||
$row[] = $value;
|
||||
continue;
|
||||
}
|
||||
if (\is_string($value)) {
|
||||
$headers[] = new TableCell($value, ['colspan' => 2]);
|
||||
$row[] = null;
|
||||
continue;
|
||||
}
|
||||
if (!\is_array($value)) {
|
||||
throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
|
||||
}
|
||||
$headers[] = key($value);
|
||||
$row[] = current($value);
|
||||
}
|
||||
|
||||
$table->setHeaders($headers);
|
||||
$table->setRows([$row]);
|
||||
$table->setHorizontal();
|
||||
$table->setStyle($style);
|
||||
|
||||
$table->render();
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -229,7 +295,7 @@ class SymfonyStyle extends OutputStyle
|
||||
{
|
||||
if (null !== $default) {
|
||||
$values = array_flip($choices);
|
||||
$default = $values[$default];
|
||||
$default = $values[$default] ?? $default;
|
||||
}
|
||||
|
||||
return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
|
||||
@@ -307,7 +373,7 @@ class SymfonyStyle extends OutputStyle
|
||||
public function writeln($messages, $type = self::OUTPUT_NORMAL)
|
||||
{
|
||||
if (!is_iterable($messages)) {
|
||||
$messages = array($messages);
|
||||
$messages = [$messages];
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
@@ -322,7 +388,7 @@ class SymfonyStyle extends OutputStyle
|
||||
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
|
||||
{
|
||||
if (!is_iterable($messages)) {
|
||||
$messages = array($messages);
|
||||
$messages = [$messages];
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
@@ -361,38 +427,37 @@ class SymfonyStyle extends OutputStyle
|
||||
|
||||
private function autoPrependBlock(): void
|
||||
{
|
||||
$chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
|
||||
$chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
|
||||
|
||||
if (!isset($chars[0])) {
|
||||
$this->newLine(); //empty history, so we should start with a new line.
|
||||
$this->newLine(); // empty history, so we should start with a new line.
|
||||
|
||||
return;
|
||||
}
|
||||
//Prepend new line for each non LF chars (This means no blank line was output before)
|
||||
// Prepend new line for each non LF chars (This means no blank line was output before)
|
||||
$this->newLine(2 - substr_count($chars, "\n"));
|
||||
}
|
||||
|
||||
private function autoPrependText(): void
|
||||
{
|
||||
$fetched = $this->bufferedOutput->fetch();
|
||||
//Prepend new line if last char isn't EOL:
|
||||
if ("\n" !== substr($fetched, -1)) {
|
||||
// Prepend new line if last char isn't EOL:
|
||||
if (!str_ends_with($fetched, "\n")) {
|
||||
$this->newLine();
|
||||
}
|
||||
}
|
||||
|
||||
private function writeBuffer(string $message, bool $newLine, int $type): void
|
||||
{
|
||||
// We need to know if the two last chars are PHP_EOL
|
||||
// Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer
|
||||
$this->bufferedOutput->write(substr($message, -4), $newLine, $type);
|
||||
// We need to know if the last chars are PHP_EOL
|
||||
$this->bufferedOutput->write($message, $newLine, $type);
|
||||
}
|
||||
|
||||
private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false)
|
||||
private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
|
||||
{
|
||||
$indentLength = 0;
|
||||
$prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
|
||||
$lines = array();
|
||||
$lines = [];
|
||||
|
||||
if (null !== $type) {
|
||||
$type = sprintf('[%s] ', $type);
|
||||
@@ -406,7 +471,12 @@ class SymfonyStyle extends OutputStyle
|
||||
$message = OutputFormatter::escape($message);
|
||||
}
|
||||
|
||||
$lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true)));
|
||||
$decorationLength = Helper::strlen($message) - Helper::strlenWithoutDecoration($this->getFormatter(), $message);
|
||||
$messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);
|
||||
$messageLines = explode(\PHP_EOL, wordwrap($message, $messageLineLength, \PHP_EOL, true));
|
||||
foreach ($messageLines as $messageLine) {
|
||||
$lines[] = $messageLine;
|
||||
}
|
||||
|
||||
if (\count($messages) > 1 && $key < \count($messages) - 1) {
|
||||
$lines[] = '';
|
||||
@@ -426,7 +496,7 @@ class SymfonyStyle extends OutputStyle
|
||||
}
|
||||
|
||||
$line = $prefix.$line;
|
||||
$line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
|
||||
$line .= str_repeat(' ', max($this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line), 0));
|
||||
|
||||
if ($style) {
|
||||
$line = sprintf('<%s>%s</>', $style, $line);
|
||||
|
107
vendor/symfony/console/Terminal.php
vendored
107
vendor/symfony/console/Terminal.php
vendored
@@ -15,6 +15,7 @@ class Terminal
|
||||
{
|
||||
private static $width;
|
||||
private static $height;
|
||||
private static $stty;
|
||||
|
||||
/**
|
||||
* Gets the terminal width.
|
||||
@@ -54,6 +55,27 @@ class Terminal
|
||||
return self::$height ?: 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasSttyAvailable()
|
||||
{
|
||||
if (null !== self::$stty) {
|
||||
return self::$stty;
|
||||
}
|
||||
|
||||
// skip check if exec function is disabled
|
||||
if (!\function_exists('exec')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exec('stty 2>&1', $output, $exitcode);
|
||||
|
||||
return self::$stty = 0 === $exitcode;
|
||||
}
|
||||
|
||||
private static function initDimensions()
|
||||
{
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
@@ -62,12 +84,34 @@ class Terminal
|
||||
// or [w, h] from "wxh"
|
||||
self::$width = (int) $matches[1];
|
||||
self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
|
||||
} elseif (!self::hasVt100Support() && self::hasSttyAvailable()) {
|
||||
// only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash)
|
||||
// testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT
|
||||
self::initDimensionsUsingStty();
|
||||
} elseif (null !== $dimensions = self::getConsoleMode()) {
|
||||
// extract [w, h] from "wxh"
|
||||
self::$width = (int) $dimensions[0];
|
||||
self::$height = (int) $dimensions[1];
|
||||
}
|
||||
} elseif ($sttyString = self::getSttyColumns()) {
|
||||
} else {
|
||||
self::initDimensionsUsingStty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether STDOUT has vt100 support (some Windows 10+ configurations).
|
||||
*/
|
||||
private static function hasVt100Support(): bool
|
||||
{
|
||||
return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes dimensions using the output of an stty columns line.
|
||||
*/
|
||||
private static function initDimensionsUsingStty()
|
||||
{
|
||||
if ($sttyString = self::getSttyColumns()) {
|
||||
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
|
||||
// extract [w, h] from "rows h; columns w;"
|
||||
self::$width = (int) $matches[2];
|
||||
@@ -85,53 +129,46 @@ class Terminal
|
||||
*
|
||||
* @return int[]|null An array composed of the width and the height or null if it could not be parsed
|
||||
*/
|
||||
private static function getConsoleMode()
|
||||
private static function getConsoleMode(): ?array
|
||||
{
|
||||
if (!\function_exists('proc_open')) {
|
||||
return;
|
||||
$info = self::readFromProcess('mode CON');
|
||||
|
||||
if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$descriptorspec = array(
|
||||
1 => array('pipe', 'w'),
|
||||
2 => array('pipe', 'w'),
|
||||
);
|
||||
$process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
|
||||
if (\is_resource($process)) {
|
||||
$info = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
|
||||
if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
|
||||
return array((int) $matches[2], (int) $matches[1]);
|
||||
}
|
||||
}
|
||||
return [(int) $matches[2], (int) $matches[1]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs and parses stty -a if it's available, suppressing any error output.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private static function getSttyColumns()
|
||||
private static function getSttyColumns(): ?string
|
||||
{
|
||||
return self::readFromProcess('stty -a | grep columns');
|
||||
}
|
||||
|
||||
private static function readFromProcess(string $command): ?string
|
||||
{
|
||||
if (!\function_exists('proc_open')) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$descriptorspec = array(
|
||||
1 => array('pipe', 'w'),
|
||||
2 => array('pipe', 'w'),
|
||||
);
|
||||
$descriptorspec = [
|
||||
1 => ['pipe', 'w'],
|
||||
2 => ['pipe', 'w'],
|
||||
];
|
||||
|
||||
$process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
|
||||
if (\is_resource($process)) {
|
||||
$info = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
|
||||
return $info;
|
||||
$process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
|
||||
if (!\is_resource($process)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$info = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
@@ -52,26 +52,39 @@ class ApplicationTester
|
||||
*
|
||||
* @return int The command exit code
|
||||
*/
|
||||
public function run(array $input, $options = array())
|
||||
public function run(array $input, $options = [])
|
||||
{
|
||||
$this->input = new ArrayInput($input);
|
||||
if (isset($options['interactive'])) {
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
$prevShellVerbosity = getenv('SHELL_VERBOSITY');
|
||||
|
||||
try {
|
||||
$this->input = new ArrayInput($input);
|
||||
if (isset($options['interactive'])) {
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
}
|
||||
|
||||
if ($this->inputs) {
|
||||
$this->input->setStream(self::createStream($this->inputs));
|
||||
}
|
||||
|
||||
$this->initOutput($options);
|
||||
|
||||
return $this->statusCode = $this->application->run($this->input, $this->output);
|
||||
} finally {
|
||||
// SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
|
||||
// to its previous value to avoid one test's verbosity to spread to the following tests
|
||||
if (false === $prevShellVerbosity) {
|
||||
if (\function_exists('putenv')) {
|
||||
@putenv('SHELL_VERBOSITY');
|
||||
}
|
||||
unset($_ENV['SHELL_VERBOSITY']);
|
||||
unset($_SERVER['SHELL_VERBOSITY']);
|
||||
} else {
|
||||
if (\function_exists('putenv')) {
|
||||
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
|
||||
}
|
||||
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
|
||||
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
|
||||
}
|
||||
}
|
||||
|
||||
$shellInteractive = getenv('SHELL_INTERACTIVE');
|
||||
|
||||
if ($this->inputs) {
|
||||
$this->input->setStream(self::createStream($this->inputs));
|
||||
putenv('SHELL_INTERACTIVE=1');
|
||||
}
|
||||
|
||||
$this->initOutput($options);
|
||||
|
||||
$this->statusCode = $this->application->run($this->input, $this->output);
|
||||
|
||||
putenv($shellInteractive ? "SHELL_INTERACTIVE=$shellInteractive" : 'SHELL_INTERACTIVE');
|
||||
|
||||
return $this->statusCode;
|
||||
}
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ class CommandTester
|
||||
*
|
||||
* @return int The command exit code
|
||||
*/
|
||||
public function execute(array $input, array $options = array())
|
||||
public function execute(array $input, array $options = [])
|
||||
{
|
||||
// set the command name automatically if the application requires
|
||||
// this argument and no command name was passed
|
||||
@@ -56,13 +56,12 @@ class CommandTester
|
||||
&& (null !== $application = $this->command->getApplication())
|
||||
&& $application->getDefinition()->hasArgument('command')
|
||||
) {
|
||||
$input = array_merge(array('command' => $this->command->getName()), $input);
|
||||
$input = array_merge(['command' => $this->command->getName()], $input);
|
||||
}
|
||||
|
||||
$this->input = new ArrayInput($input);
|
||||
if ($this->inputs) {
|
||||
$this->input->setStream(self::createStream($this->inputs));
|
||||
}
|
||||
// Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN.
|
||||
$this->input->setStream(self::createStream($this->inputs));
|
||||
|
||||
if (isset($options['interactive'])) {
|
||||
$this->input->setInteractive($options['interactive']);
|
||||
|
26
vendor/symfony/console/Tester/TesterTrait.php
vendored
26
vendor/symfony/console/Tester/TesterTrait.php
vendored
@@ -23,7 +23,7 @@ trait TesterTrait
|
||||
{
|
||||
/** @var StreamOutput */
|
||||
private $output;
|
||||
private $inputs = array();
|
||||
private $inputs = [];
|
||||
private $captureStreamsIndependently = false;
|
||||
|
||||
/**
|
||||
@@ -35,12 +35,16 @@ trait TesterTrait
|
||||
*/
|
||||
public function getDisplay($normalize = false)
|
||||
{
|
||||
if (null === $this->output) {
|
||||
throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
|
||||
}
|
||||
|
||||
rewind($this->output->getStream());
|
||||
|
||||
$display = stream_get_contents($this->output->getStream());
|
||||
|
||||
if ($normalize) {
|
||||
$display = str_replace(PHP_EOL, "\n", $display);
|
||||
$display = str_replace(\PHP_EOL, "\n", $display);
|
||||
}
|
||||
|
||||
return $display;
|
||||
@@ -64,7 +68,7 @@ trait TesterTrait
|
||||
$display = stream_get_contents($this->output->getErrorOutput()->getStream());
|
||||
|
||||
if ($normalize) {
|
||||
$display = str_replace(PHP_EOL, "\n", $display);
|
||||
$display = str_replace(\PHP_EOL, "\n", $display);
|
||||
}
|
||||
|
||||
return $display;
|
||||
@@ -106,7 +110,7 @@ trait TesterTrait
|
||||
* @param array $inputs An array of strings representing each input
|
||||
* passed to the command input stream
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setInputs(array $inputs)
|
||||
{
|
||||
@@ -126,7 +130,7 @@ trait TesterTrait
|
||||
*/
|
||||
private function initOutput(array $options)
|
||||
{
|
||||
$this->captureStreamsIndependently = array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
|
||||
$this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately'];
|
||||
if (!$this->captureStreamsIndependently) {
|
||||
$this->output = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
if (isset($options['decorated'])) {
|
||||
@@ -137,8 +141,8 @@ trait TesterTrait
|
||||
}
|
||||
} else {
|
||||
$this->output = new ConsoleOutput(
|
||||
isset($options['verbosity']) ? $options['verbosity'] : ConsoleOutput::VERBOSITY_NORMAL,
|
||||
isset($options['decorated']) ? $options['decorated'] : null
|
||||
$options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL,
|
||||
$options['decorated'] ?? null
|
||||
);
|
||||
|
||||
$errorOutput = new StreamOutput(fopen('php://memory', 'w', false));
|
||||
@@ -158,11 +162,17 @@ trait TesterTrait
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource
|
||||
*/
|
||||
private static function createStream(array $inputs)
|
||||
{
|
||||
$stream = fopen('php://memory', 'r+', false);
|
||||
|
||||
fwrite($stream, implode(PHP_EOL, $inputs));
|
||||
foreach ($inputs as $input) {
|
||||
fwrite($stream, $input.\PHP_EOL);
|
||||
}
|
||||
|
||||
rewind($stream);
|
||||
|
||||
return $stream;
|
||||
|
1791
vendor/symfony/console/Tests/ApplicationTest.php
vendored
1791
vendor/symfony/console/Tests/ApplicationTest.php
vendored
File diff suppressed because it is too large
Load Diff
428
vendor/symfony/console/Tests/Command/CommandTest.php
vendored
428
vendor/symfony/console/Tests/Command/CommandTest.php
vendored
@@ -1,428 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Command;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class CommandTest extends TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = __DIR__.'/../Fixtures/';
|
||||
require_once self::$fixturesPath.'/TestCommand.php';
|
||||
}
|
||||
|
||||
public function testConstructor()
|
||||
{
|
||||
$command = new Command('foo:bar');
|
||||
$this->assertEquals('foo:bar', $command->getName(), '__construct() takes the command name as its first argument');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage The command defined in "Symfony\Component\Console\Command\Command" cannot have an empty name.
|
||||
*/
|
||||
public function testCommandNameCannotBeEmpty()
|
||||
{
|
||||
(new Application())->add(new Command());
|
||||
}
|
||||
|
||||
public function testSetApplication()
|
||||
{
|
||||
$application = new Application();
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication($application);
|
||||
$this->assertEquals($application, $command->getApplication(), '->setApplication() sets the current application');
|
||||
$this->assertEquals($application->getHelperSet(), $command->getHelperSet());
|
||||
}
|
||||
|
||||
public function testSetApplicationNull()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication(null);
|
||||
$this->assertNull($command->getHelperSet());
|
||||
}
|
||||
|
||||
public function testSetGetDefinition()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$ret = $command->setDefinition($definition = new InputDefinition());
|
||||
$this->assertEquals($command, $ret, '->setDefinition() implements a fluent interface');
|
||||
$this->assertEquals($definition, $command->getDefinition(), '->setDefinition() sets the current InputDefinition instance');
|
||||
$command->setDefinition(array(new InputArgument('foo'), new InputOption('bar')));
|
||||
$this->assertTrue($command->getDefinition()->hasArgument('foo'), '->setDefinition() also takes an array of InputArguments and InputOptions as an argument');
|
||||
$this->assertTrue($command->getDefinition()->hasOption('bar'), '->setDefinition() also takes an array of InputArguments and InputOptions as an argument');
|
||||
$command->setDefinition(new InputDefinition());
|
||||
}
|
||||
|
||||
public function testAddArgument()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$ret = $command->addArgument('foo');
|
||||
$this->assertEquals($command, $ret, '->addArgument() implements a fluent interface');
|
||||
$this->assertTrue($command->getDefinition()->hasArgument('foo'), '->addArgument() adds an argument to the command');
|
||||
}
|
||||
|
||||
public function testAddOption()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$ret = $command->addOption('foo');
|
||||
$this->assertEquals($command, $ret, '->addOption() implements a fluent interface');
|
||||
$this->assertTrue($command->getDefinition()->hasOption('foo'), '->addOption() adds an option to the command');
|
||||
}
|
||||
|
||||
public function testSetHidden()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->setHidden(true);
|
||||
$this->assertTrue($command->isHidden());
|
||||
}
|
||||
|
||||
public function testGetNamespaceGetNameSetName()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$this->assertEquals('namespace:name', $command->getName(), '->getName() returns the command name');
|
||||
$command->setName('foo');
|
||||
$this->assertEquals('foo', $command->getName(), '->setName() sets the command name');
|
||||
|
||||
$ret = $command->setName('foobar:bar');
|
||||
$this->assertEquals($command, $ret, '->setName() implements a fluent interface');
|
||||
$this->assertEquals('foobar:bar', $command->getName(), '->setName() sets the command name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidCommandNames
|
||||
*/
|
||||
public function testInvalidCommandNames($name)
|
||||
{
|
||||
if (method_exists($this, 'expectException')) {
|
||||
$this->expectException('InvalidArgumentException');
|
||||
$this->expectExceptionMessage(sprintf('Command name "%s" is invalid.', $name));
|
||||
} else {
|
||||
$this->setExpectedException('InvalidArgumentException', sprintf('Command name "%s" is invalid.', $name));
|
||||
}
|
||||
|
||||
$command = new \TestCommand();
|
||||
$command->setName($name);
|
||||
}
|
||||
|
||||
public function provideInvalidCommandNames()
|
||||
{
|
||||
return array(
|
||||
array(''),
|
||||
array('foo:'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSetDescription()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$this->assertEquals('description', $command->getDescription(), '->getDescription() returns the description');
|
||||
$ret = $command->setDescription('description1');
|
||||
$this->assertEquals($command, $ret, '->setDescription() implements a fluent interface');
|
||||
$this->assertEquals('description1', $command->getDescription(), '->setDescription() sets the description');
|
||||
}
|
||||
|
||||
public function testGetSetHelp()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$this->assertEquals('help', $command->getHelp(), '->getHelp() returns the help');
|
||||
$ret = $command->setHelp('help1');
|
||||
$this->assertEquals($command, $ret, '->setHelp() implements a fluent interface');
|
||||
$this->assertEquals('help1', $command->getHelp(), '->setHelp() sets the help');
|
||||
$command->setHelp('');
|
||||
$this->assertEquals('', $command->getHelp(), '->getHelp() does not fall back to the description');
|
||||
}
|
||||
|
||||
public function testGetProcessedHelp()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->setHelp('The %command.name% command does... Example: php %command.full_name%.');
|
||||
$this->assertContains('The namespace:name command does...', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.name% correctly');
|
||||
$this->assertNotContains('%command.full_name%', $command->getProcessedHelp(), '->getProcessedHelp() replaces %command.full_name%');
|
||||
|
||||
$command = new \TestCommand();
|
||||
$command->setHelp('');
|
||||
$this->assertContains('description', $command->getProcessedHelp(), '->getProcessedHelp() falls back to the description');
|
||||
}
|
||||
|
||||
public function testGetSetAliases()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$this->assertEquals(array('name'), $command->getAliases(), '->getAliases() returns the aliases');
|
||||
$ret = $command->setAliases(array('name1'));
|
||||
$this->assertEquals($command, $ret, '->setAliases() implements a fluent interface');
|
||||
$this->assertEquals(array('name1'), $command->getAliases(), '->setAliases() sets the aliases');
|
||||
}
|
||||
|
||||
public function testSetAliasesNull()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException');
|
||||
$command->setAliases(null);
|
||||
}
|
||||
|
||||
public function testGetSynopsis()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->addOption('foo');
|
||||
$command->addArgument('bar');
|
||||
$this->assertEquals('namespace:name [--foo] [--] [<bar>]', $command->getSynopsis(), '->getSynopsis() returns the synopsis');
|
||||
}
|
||||
|
||||
public function testAddGetUsages()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->addUsage('foo1');
|
||||
$command->addUsage('foo2');
|
||||
$this->assertContains('namespace:name foo1', $command->getUsages());
|
||||
$this->assertContains('namespace:name foo2', $command->getUsages());
|
||||
}
|
||||
|
||||
public function testGetHelper()
|
||||
{
|
||||
$application = new Application();
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication($application);
|
||||
$formatterHelper = new FormatterHelper();
|
||||
$this->assertEquals($formatterHelper->getName(), $command->getHelper('formatter')->getName(), '->getHelper() returns the correct helper');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot retrieve helper "formatter" because there is no HelperSet defined.
|
||||
*/
|
||||
public function testGetHelperWithoutHelperSet()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->getHelper('formatter');
|
||||
}
|
||||
|
||||
public function testMergeApplicationDefinition()
|
||||
{
|
||||
$application1 = new Application();
|
||||
$application1->getDefinition()->addArguments(array(new InputArgument('foo')));
|
||||
$application1->getDefinition()->addOptions(array(new InputOption('bar')));
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication($application1);
|
||||
$command->setDefinition($definition = new InputDefinition(array(new InputArgument('bar'), new InputOption('foo'))));
|
||||
|
||||
$r = new \ReflectionObject($command);
|
||||
$m = $r->getMethod('mergeApplicationDefinition');
|
||||
$m->setAccessible(true);
|
||||
$m->invoke($command);
|
||||
$this->assertTrue($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition() merges the application arguments and the command arguments');
|
||||
$this->assertTrue($command->getDefinition()->hasArgument('bar'), '->mergeApplicationDefinition() merges the application arguments and the command arguments');
|
||||
$this->assertTrue($command->getDefinition()->hasOption('foo'), '->mergeApplicationDefinition() merges the application options and the command options');
|
||||
$this->assertTrue($command->getDefinition()->hasOption('bar'), '->mergeApplicationDefinition() merges the application options and the command options');
|
||||
|
||||
$m->invoke($command);
|
||||
$this->assertEquals(3, $command->getDefinition()->getArgumentCount(), '->mergeApplicationDefinition() does not try to merge twice the application arguments and options');
|
||||
}
|
||||
|
||||
public function testMergeApplicationDefinitionWithoutArgsThenWithArgsAddsArgs()
|
||||
{
|
||||
$application1 = new Application();
|
||||
$application1->getDefinition()->addArguments(array(new InputArgument('foo')));
|
||||
$application1->getDefinition()->addOptions(array(new InputOption('bar')));
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication($application1);
|
||||
$command->setDefinition($definition = new InputDefinition(array()));
|
||||
|
||||
$r = new \ReflectionObject($command);
|
||||
$m = $r->getMethod('mergeApplicationDefinition');
|
||||
$m->setAccessible(true);
|
||||
$m->invoke($command, false);
|
||||
$this->assertTrue($command->getDefinition()->hasOption('bar'), '->mergeApplicationDefinition(false) merges the application and the command options');
|
||||
$this->assertFalse($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition(false) does not merge the application arguments');
|
||||
|
||||
$m->invoke($command, true);
|
||||
$this->assertTrue($command->getDefinition()->hasArgument('foo'), '->mergeApplicationDefinition(true) merges the application arguments and the command arguments');
|
||||
|
||||
$m->invoke($command);
|
||||
$this->assertEquals(2, $command->getDefinition()->getArgumentCount(), '->mergeApplicationDefinition() does not try to merge twice the application arguments');
|
||||
}
|
||||
|
||||
public function testRunInteractive()
|
||||
{
|
||||
$tester = new CommandTester(new \TestCommand());
|
||||
|
||||
$tester->execute(array(), array('interactive' => true));
|
||||
|
||||
$this->assertEquals('interact called'.PHP_EOL.'execute called'.PHP_EOL, $tester->getDisplay(), '->run() calls the interact() method if the input is interactive');
|
||||
}
|
||||
|
||||
public function testRunNonInteractive()
|
||||
{
|
||||
$tester = new CommandTester(new \TestCommand());
|
||||
|
||||
$tester->execute(array(), array('interactive' => false));
|
||||
|
||||
$this->assertEquals('execute called'.PHP_EOL, $tester->getDisplay(), '->run() does not call the interact() method if the input is not interactive');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage You must override the execute() method in the concrete command class.
|
||||
*/
|
||||
public function testExecuteMethodNeedsToBeOverridden()
|
||||
{
|
||||
$command = new Command('foo');
|
||||
$command->run(new StringInput(''), new NullOutput());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\InvalidOptionException
|
||||
* @expectedExceptionMessage The "--bar" option does not exist.
|
||||
*/
|
||||
public function testRunWithInvalidOption()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array('--bar' => true));
|
||||
}
|
||||
|
||||
public function testRunReturnsIntegerExitCode()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$exitCode = $command->run(new StringInput(''), new NullOutput());
|
||||
$this->assertSame(0, $exitCode, '->run() returns integer exit code (treats null as 0)');
|
||||
|
||||
$command = $this->getMockBuilder('TestCommand')->setMethods(array('execute'))->getMock();
|
||||
$command->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue('2.3'));
|
||||
$exitCode = $command->run(new StringInput(''), new NullOutput());
|
||||
$this->assertSame(2, $exitCode, '->run() returns integer exit code (casts numeric to int)');
|
||||
}
|
||||
|
||||
public function testRunWithApplication()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication(new Application());
|
||||
$exitCode = $command->run(new StringInput(''), new NullOutput());
|
||||
|
||||
$this->assertSame(0, $exitCode, '->run() returns an integer exit code');
|
||||
}
|
||||
|
||||
public function testRunReturnsAlwaysInteger()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
|
||||
$this->assertSame(0, $command->run(new StringInput(''), new NullOutput()));
|
||||
}
|
||||
|
||||
public function testRunWithProcessTitle()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->setApplication(new Application());
|
||||
$command->setProcessTitle('foo');
|
||||
$this->assertSame(0, $command->run(new StringInput(''), new NullOutput()));
|
||||
if (\function_exists('cli_set_process_title')) {
|
||||
if (null === @cli_get_process_title() && 'Darwin' === PHP_OS) {
|
||||
$this->markTestSkipped('Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.');
|
||||
}
|
||||
$this->assertEquals('foo', cli_get_process_title());
|
||||
}
|
||||
}
|
||||
|
||||
public function testSetCode()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$ret = $command->setCode(function (InputInterface $input, OutputInterface $output) {
|
||||
$output->writeln('from the code...');
|
||||
});
|
||||
$this->assertEquals($command, $ret, '->setCode() implements a fluent interface');
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array());
|
||||
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function getSetCodeBindToClosureTests()
|
||||
{
|
||||
return array(
|
||||
array(true, 'not bound to the command'),
|
||||
array(false, 'bound to the command'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getSetCodeBindToClosureTests
|
||||
*/
|
||||
public function testSetCodeBindToClosure($previouslyBound, $expected)
|
||||
{
|
||||
$code = createClosure();
|
||||
if ($previouslyBound) {
|
||||
$code = $code->bindTo($this);
|
||||
}
|
||||
|
||||
$command = new \TestCommand();
|
||||
$command->setCode($code);
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array());
|
||||
$this->assertEquals('interact called'.PHP_EOL.$expected.PHP_EOL, $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testSetCodeWithStaticClosure()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$command->setCode(self::createClosure());
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array());
|
||||
|
||||
$this->assertEquals('interact called'.PHP_EOL.'bound'.PHP_EOL, $tester->getDisplay());
|
||||
}
|
||||
|
||||
private static function createClosure()
|
||||
{
|
||||
return function (InputInterface $input, OutputInterface $output) {
|
||||
$output->writeln(isset($this) ? 'bound' : 'not bound');
|
||||
};
|
||||
}
|
||||
|
||||
public function testSetCodeWithNonClosureCallable()
|
||||
{
|
||||
$command = new \TestCommand();
|
||||
$ret = $command->setCode(array($this, 'callableMethodCommand'));
|
||||
$this->assertEquals($command, $ret, '->setCode() implements a fluent interface');
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(array());
|
||||
$this->assertEquals('interact called'.PHP_EOL.'from the code...'.PHP_EOL, $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function callableMethodCommand(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln('from the code...');
|
||||
}
|
||||
}
|
||||
|
||||
// In order to get an unbound closure, we should create it outside a class
|
||||
// scope.
|
||||
function createClosure()
|
||||
{
|
||||
return function (InputInterface $input, OutputInterface $output) {
|
||||
$output->writeln($this instanceof Command ? 'bound to the command' : 'not bound to the command');
|
||||
};
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Command;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\HelpCommand;
|
||||
use Symfony\Component\Console\Command\ListCommand;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class HelpCommandTest extends TestCase
|
||||
{
|
||||
public function testExecuteForCommandAlias()
|
||||
{
|
||||
$command = new HelpCommand();
|
||||
$command->setApplication(new Application());
|
||||
$commandTester = new CommandTester($command);
|
||||
$commandTester->execute(array('command_name' => 'li'), array('decorated' => false));
|
||||
$this->assertContains('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
|
||||
$this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
|
||||
$this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command alias');
|
||||
}
|
||||
|
||||
public function testExecuteForCommand()
|
||||
{
|
||||
$command = new HelpCommand();
|
||||
$commandTester = new CommandTester($command);
|
||||
$command->setCommand(new ListCommand());
|
||||
$commandTester->execute(array(), array('decorated' => false));
|
||||
$this->assertContains('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
$this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
$this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
}
|
||||
|
||||
public function testExecuteForCommandWithXmlOption()
|
||||
{
|
||||
$command = new HelpCommand();
|
||||
$commandTester = new CommandTester($command);
|
||||
$command->setCommand(new ListCommand());
|
||||
$commandTester->execute(array('--format' => 'xml'));
|
||||
$this->assertContains('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --xml is passed');
|
||||
}
|
||||
|
||||
public function testExecuteForApplicationCommand()
|
||||
{
|
||||
$application = new Application();
|
||||
$commandTester = new CommandTester($application->get('help'));
|
||||
$commandTester->execute(array('command_name' => 'list'));
|
||||
$this->assertContains('list [options] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
$this->assertContains('format=FORMAT', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
$this->assertContains('raw', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
}
|
||||
|
||||
public function testExecuteForApplicationCommandWithXmlOption()
|
||||
{
|
||||
$application = new Application();
|
||||
$commandTester = new CommandTester($application->get('help'));
|
||||
$commandTester->execute(array('command_name' => 'list', '--format' => 'xml'));
|
||||
$this->assertContains('list [--raw] [--format FORMAT] [--] [<namespace>]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
|
||||
$this->assertContains('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --format=xml is passed');
|
||||
}
|
||||
}
|
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Command;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class ListCommandTest extends TestCase
|
||||
{
|
||||
public function testExecuteListsCommands()
|
||||
{
|
||||
$application = new Application();
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getName()), array('decorated' => false));
|
||||
|
||||
$this->assertRegExp('/help\s{2,}Displays help for a command/', $commandTester->getDisplay(), '->execute() returns a list of available commands');
|
||||
}
|
||||
|
||||
public function testExecuteListsCommandsWithXmlOption()
|
||||
{
|
||||
$application = new Application();
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getName(), '--format' => 'xml'));
|
||||
$this->assertRegExp('/<command id="list" name="list" hidden="0">/', $commandTester->getDisplay(), '->execute() returns a list of available commands in XML if --xml is passed');
|
||||
}
|
||||
|
||||
public function testExecuteListsCommandsWithRawOption()
|
||||
{
|
||||
$application = new Application();
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getName(), '--raw' => true));
|
||||
$output = <<<'EOF'
|
||||
help Displays help for a command
|
||||
list Lists commands
|
||||
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($output, $commandTester->getDisplay(true));
|
||||
}
|
||||
|
||||
public function testExecuteListsCommandsWithNamespaceArgument()
|
||||
{
|
||||
require_once realpath(__DIR__.'/../Fixtures/FooCommand.php');
|
||||
$application = new Application();
|
||||
$application->add(new \FooCommand());
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getName(), 'namespace' => 'foo', '--raw' => true));
|
||||
$output = <<<'EOF'
|
||||
foo:bar The foo:bar command
|
||||
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($output, $commandTester->getDisplay(true));
|
||||
}
|
||||
|
||||
public function testExecuteListsCommandsOrder()
|
||||
{
|
||||
require_once realpath(__DIR__.'/../Fixtures/Foo6Command.php');
|
||||
$application = new Application();
|
||||
$application->add(new \Foo6Command());
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getName()), array('decorated' => false));
|
||||
$output = <<<'EOF'
|
||||
Console Tool
|
||||
|
||||
Usage:
|
||||
command [options] [arguments]
|
||||
|
||||
Options:
|
||||
-h, --help Display this help message
|
||||
-q, --quiet Do not output any message
|
||||
-V, --version Display this application version
|
||||
--ansi Force ANSI output
|
||||
--no-ansi Disable ANSI output
|
||||
-n, --no-interaction Do not ask any interactive question
|
||||
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
||||
|
||||
Available commands:
|
||||
help Displays help for a command
|
||||
list Lists commands
|
||||
0foo
|
||||
0foo:bar 0foo:bar command
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($output, trim($commandTester->getDisplay(true)));
|
||||
}
|
||||
|
||||
public function testExecuteListsCommandsOrderRaw()
|
||||
{
|
||||
require_once realpath(__DIR__.'/../Fixtures/Foo6Command.php');
|
||||
$application = new Application();
|
||||
$application->add(new \Foo6Command());
|
||||
$commandTester = new CommandTester($command = $application->get('list'));
|
||||
$commandTester->execute(array('command' => $command->getName(), '--raw' => true));
|
||||
$output = <<<'EOF'
|
||||
help Displays help for a command
|
||||
list Lists commands
|
||||
0foo:bar 0foo:bar command
|
||||
EOF;
|
||||
|
||||
$this->assertEquals($output, trim($commandTester->getDisplay(true)));
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Command;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Symfony\Component\Lock\Factory;
|
||||
use Symfony\Component\Lock\Store\FlockStore;
|
||||
use Symfony\Component\Lock\Store\SemaphoreStore;
|
||||
|
||||
class LockableTraitTest extends TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = __DIR__.'/../Fixtures/';
|
||||
require_once self::$fixturesPath.'/FooLockCommand.php';
|
||||
require_once self::$fixturesPath.'/FooLock2Command.php';
|
||||
}
|
||||
|
||||
public function testLockIsReleased()
|
||||
{
|
||||
$command = new \FooLockCommand();
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$this->assertSame(2, $tester->execute(array()));
|
||||
$this->assertSame(2, $tester->execute(array()));
|
||||
}
|
||||
|
||||
public function testLockReturnsFalseIfAlreadyLockedByAnotherCommand()
|
||||
{
|
||||
$command = new \FooLockCommand();
|
||||
|
||||
if (SemaphoreStore::isSupported()) {
|
||||
$store = new SemaphoreStore();
|
||||
} else {
|
||||
$store = new FlockStore();
|
||||
}
|
||||
|
||||
$lock = (new Factory($store))->createLock($command->getName());
|
||||
$lock->acquire();
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$this->assertSame(1, $tester->execute(array()));
|
||||
|
||||
$lock->release();
|
||||
$this->assertSame(2, $tester->execute(array()));
|
||||
}
|
||||
|
||||
public function testMultipleLockCallsThrowLogicException()
|
||||
{
|
||||
$command = new \FooLock2Command();
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$this->assertSame(1, $tester->execute(array()));
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\CommandLoader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
class ContainerCommandLoaderTest extends TestCase
|
||||
{
|
||||
public function testHas()
|
||||
{
|
||||
$loader = new ContainerCommandLoader(new ServiceLocator(array(
|
||||
'foo-service' => function () { return new Command('foo'); },
|
||||
'bar-service' => function () { return new Command('bar'); },
|
||||
)), array('foo' => 'foo-service', 'bar' => 'bar-service'));
|
||||
|
||||
$this->assertTrue($loader->has('foo'));
|
||||
$this->assertTrue($loader->has('bar'));
|
||||
$this->assertFalse($loader->has('baz'));
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$loader = new ContainerCommandLoader(new ServiceLocator(array(
|
||||
'foo-service' => function () { return new Command('foo'); },
|
||||
'bar-service' => function () { return new Command('bar'); },
|
||||
)), array('foo' => 'foo-service', 'bar' => 'bar-service'));
|
||||
|
||||
$this->assertInstanceOf(Command::class, $loader->get('foo'));
|
||||
$this->assertInstanceOf(Command::class, $loader->get('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
|
||||
*/
|
||||
public function testGetUnknownCommandThrows()
|
||||
{
|
||||
(new ContainerCommandLoader(new ServiceLocator(array()), array()))->get('unknown');
|
||||
}
|
||||
|
||||
public function testGetCommandNames()
|
||||
{
|
||||
$loader = new ContainerCommandLoader(new ServiceLocator(array(
|
||||
'foo-service' => function () { return new Command('foo'); },
|
||||
'bar-service' => function () { return new Command('bar'); },
|
||||
)), array('foo' => 'foo-service', 'bar' => 'bar-service'));
|
||||
|
||||
$this->assertSame(array('foo', 'bar'), $loader->getNames());
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\CommandLoader;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
|
||||
|
||||
class FactoryCommandLoaderTest extends TestCase
|
||||
{
|
||||
public function testHas()
|
||||
{
|
||||
$loader = new FactoryCommandLoader(array(
|
||||
'foo' => function () { return new Command('foo'); },
|
||||
'bar' => function () { return new Command('bar'); },
|
||||
));
|
||||
|
||||
$this->assertTrue($loader->has('foo'));
|
||||
$this->assertTrue($loader->has('bar'));
|
||||
$this->assertFalse($loader->has('baz'));
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$loader = new FactoryCommandLoader(array(
|
||||
'foo' => function () { return new Command('foo'); },
|
||||
'bar' => function () { return new Command('bar'); },
|
||||
));
|
||||
|
||||
$this->assertInstanceOf(Command::class, $loader->get('foo'));
|
||||
$this->assertInstanceOf(Command::class, $loader->get('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
|
||||
*/
|
||||
public function testGetUnknownCommandThrows()
|
||||
{
|
||||
(new FactoryCommandLoader(array()))->get('unknown');
|
||||
}
|
||||
|
||||
public function testGetCommandNames()
|
||||
{
|
||||
$loader = new FactoryCommandLoader(array(
|
||||
'foo' => function () { return new Command('foo'); },
|
||||
'bar' => function () { return new Command('bar'); },
|
||||
));
|
||||
|
||||
$this->assertSame(array('foo', 'bar'), $loader->getNames());
|
||||
}
|
||||
}
|
@@ -1,258 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
|
||||
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
class AddConsoleCommandPassTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider visibilityProvider
|
||||
*/
|
||||
public function testProcess($public)
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$container->setParameter('my-command.class', 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand');
|
||||
|
||||
$id = 'my-command';
|
||||
$definition = new Definition('%my-command.class%');
|
||||
$definition->setPublic($public);
|
||||
$definition->addTag('console.command');
|
||||
$container->setDefinition($id, $definition);
|
||||
|
||||
$container->compile();
|
||||
|
||||
$alias = 'console.command.public_alias.my-command';
|
||||
|
||||
if ($public) {
|
||||
$this->assertFalse($container->hasAlias($alias));
|
||||
} else {
|
||||
// The alias is replaced by a Definition by the ReplaceAliasByActualDefinitionPass
|
||||
// in case the original service is private
|
||||
$this->assertFalse($container->hasDefinition($id));
|
||||
$this->assertTrue($container->hasDefinition($alias));
|
||||
}
|
||||
|
||||
$this->assertTrue($container->hasParameter('console.command.ids'));
|
||||
$this->assertSame(array($public ? $id : $alias), $container->getParameter('console.command.ids'));
|
||||
}
|
||||
|
||||
public function testProcessRegistersLazyCommands()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$command = $container
|
||||
->register('my-command', MyCommand::class)
|
||||
->setPublic(false)
|
||||
->addTag('console.command', array('command' => 'my:command'))
|
||||
->addTag('console.command', array('command' => 'my:alias'))
|
||||
;
|
||||
|
||||
(new AddConsoleCommandPass())->process($container);
|
||||
|
||||
$commandLoader = $container->getDefinition('console.command_loader');
|
||||
$commandLocator = $container->getDefinition((string) $commandLoader->getArgument(0));
|
||||
|
||||
$this->assertSame(ContainerCommandLoader::class, $commandLoader->getClass());
|
||||
$this->assertSame(array('my:command' => 'my-command', 'my:alias' => 'my-command'), $commandLoader->getArgument(1));
|
||||
$this->assertEquals(array(array('my-command' => new ServiceClosureArgument(new TypedReference('my-command', MyCommand::class)))), $commandLocator->getArguments());
|
||||
$this->assertSame(array(), $container->getParameter('console.command.ids'));
|
||||
$this->assertSame(array(array('setName', array('my:command')), array('setAliases', array(array('my:alias')))), $command->getMethodCalls());
|
||||
}
|
||||
|
||||
public function testProcessFallsBackToDefaultName()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('with-default-name', NamedCommand::class)
|
||||
->setPublic(false)
|
||||
->addTag('console.command')
|
||||
;
|
||||
|
||||
$pass = new AddConsoleCommandPass();
|
||||
$pass->process($container);
|
||||
|
||||
$commandLoader = $container->getDefinition('console.command_loader');
|
||||
$commandLocator = $container->getDefinition((string) $commandLoader->getArgument(0));
|
||||
|
||||
$this->assertSame(ContainerCommandLoader::class, $commandLoader->getClass());
|
||||
$this->assertSame(array('default' => 'with-default-name'), $commandLoader->getArgument(1));
|
||||
$this->assertEquals(array(array('with-default-name' => new ServiceClosureArgument(new TypedReference('with-default-name', NamedCommand::class)))), $commandLocator->getArguments());
|
||||
$this->assertSame(array(), $container->getParameter('console.command.ids'));
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('with-default-name', NamedCommand::class)
|
||||
->setPublic(false)
|
||||
->addTag('console.command', array('command' => 'new-name'))
|
||||
;
|
||||
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertSame(array('new-name' => 'with-default-name'), $container->getDefinition('console.command_loader')->getArgument(1));
|
||||
}
|
||||
|
||||
public function visibilityProvider()
|
||||
{
|
||||
return array(
|
||||
array(true),
|
||||
array(false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage The service "my-command" tagged "console.command" must not be abstract.
|
||||
*/
|
||||
public function testProcessThrowAnExceptionIfTheServiceIsAbstract()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setResourceTracking(false);
|
||||
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
|
||||
$definition = new Definition('Symfony\Component\Console\Tests\DependencyInjection\MyCommand');
|
||||
$definition->addTag('console.command');
|
||||
$definition->setAbstract(true);
|
||||
$container->setDefinition('my-command', $definition);
|
||||
|
||||
$container->compile();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage The service "my-command" tagged "console.command" must be a subclass of "Symfony\Component\Console\Command\Command".
|
||||
*/
|
||||
public function testProcessThrowAnExceptionIfTheServiceIsNotASubclassOfCommand()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setResourceTracking(false);
|
||||
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
|
||||
$definition = new Definition('SplObjectStorage');
|
||||
$definition->addTag('console.command');
|
||||
$container->setDefinition('my-command', $definition);
|
||||
|
||||
$container->compile();
|
||||
}
|
||||
|
||||
public function testProcessPrivateServicesWithSameCommand()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$className = 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand';
|
||||
|
||||
$definition1 = new Definition($className);
|
||||
$definition1->addTag('console.command')->setPublic(false);
|
||||
|
||||
$definition2 = new Definition($className);
|
||||
$definition2->addTag('console.command')->setPublic(false);
|
||||
|
||||
$container->setDefinition('my-command1', $definition1);
|
||||
$container->setDefinition('my-command2', $definition2);
|
||||
|
||||
(new AddConsoleCommandPass())->process($container);
|
||||
|
||||
$aliasPrefix = 'console.command.public_alias.';
|
||||
$this->assertTrue($container->hasAlias($aliasPrefix.'my-command1'));
|
||||
$this->assertTrue($container->hasAlias($aliasPrefix.'my-command2'));
|
||||
}
|
||||
|
||||
public function testProcessOnChildDefinitionWithClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$className = 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand';
|
||||
|
||||
$parentId = 'my-parent-command';
|
||||
$childId = 'my-child-command';
|
||||
|
||||
$parentDefinition = new Definition(/* no class */);
|
||||
$parentDefinition->setAbstract(true)->setPublic(false);
|
||||
|
||||
$childDefinition = new ChildDefinition($parentId);
|
||||
$childDefinition->addTag('console.command')->setPublic(true);
|
||||
$childDefinition->setClass($className);
|
||||
|
||||
$container->setDefinition($parentId, $parentDefinition);
|
||||
$container->setDefinition($childId, $childDefinition);
|
||||
|
||||
$container->compile();
|
||||
$command = $container->get($childId);
|
||||
|
||||
$this->assertInstanceOf($className, $command);
|
||||
}
|
||||
|
||||
public function testProcessOnChildDefinitionWithParentClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$className = 'Symfony\Component\Console\Tests\DependencyInjection\MyCommand';
|
||||
|
||||
$parentId = 'my-parent-command';
|
||||
$childId = 'my-child-command';
|
||||
|
||||
$parentDefinition = new Definition($className);
|
||||
$parentDefinition->setAbstract(true)->setPublic(false);
|
||||
|
||||
$childDefinition = new ChildDefinition($parentId);
|
||||
$childDefinition->addTag('console.command')->setPublic(true);
|
||||
|
||||
$container->setDefinition($parentId, $parentDefinition);
|
||||
$container->setDefinition($childId, $childDefinition);
|
||||
|
||||
$container->compile();
|
||||
$command = $container->get($childId);
|
||||
|
||||
$this->assertInstanceOf($className, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage The definition for "my-child-command" has no class.
|
||||
*/
|
||||
public function testProcessOnChildDefinitionWithoutClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addCompilerPass(new AddConsoleCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
|
||||
$parentId = 'my-parent-command';
|
||||
$childId = 'my-child-command';
|
||||
|
||||
$parentDefinition = new Definition();
|
||||
$parentDefinition->setAbstract(true)->setPublic(false);
|
||||
|
||||
$childDefinition = new ChildDefinition($parentId);
|
||||
$childDefinition->addTag('console.command')->setPublic(true);
|
||||
|
||||
$container->setDefinition($parentId, $parentDefinition);
|
||||
$container->setDefinition($childId, $childDefinition);
|
||||
|
||||
$container->compile();
|
||||
}
|
||||
}
|
||||
|
||||
class MyCommand extends Command
|
||||
{
|
||||
}
|
||||
|
||||
class NamedCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'default';
|
||||
}
|
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Descriptor;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
|
||||
abstract class AbstractDescriptorTest extends TestCase
|
||||
{
|
||||
/** @dataProvider getDescribeInputArgumentTestData */
|
||||
public function testDescribeInputArgument(InputArgument $argument, $expectedDescription)
|
||||
{
|
||||
$this->assertDescription($expectedDescription, $argument);
|
||||
}
|
||||
|
||||
/** @dataProvider getDescribeInputOptionTestData */
|
||||
public function testDescribeInputOption(InputOption $option, $expectedDescription)
|
||||
{
|
||||
$this->assertDescription($expectedDescription, $option);
|
||||
}
|
||||
|
||||
/** @dataProvider getDescribeInputDefinitionTestData */
|
||||
public function testDescribeInputDefinition(InputDefinition $definition, $expectedDescription)
|
||||
{
|
||||
$this->assertDescription($expectedDescription, $definition);
|
||||
}
|
||||
|
||||
/** @dataProvider getDescribeCommandTestData */
|
||||
public function testDescribeCommand(Command $command, $expectedDescription)
|
||||
{
|
||||
$this->assertDescription($expectedDescription, $command);
|
||||
}
|
||||
|
||||
/** @dataProvider getDescribeApplicationTestData */
|
||||
public function testDescribeApplication(Application $application, $expectedDescription)
|
||||
{
|
||||
// Replaces the dynamic placeholders of the command help text with a static version.
|
||||
// The placeholder %command.full_name% includes the script path that is not predictable
|
||||
// and can not be tested against.
|
||||
foreach ($application->all() as $command) {
|
||||
$command->setHelp(str_replace('%command.full_name%', 'app/console %command.name%', $command->getHelp()));
|
||||
}
|
||||
|
||||
$this->assertDescription($expectedDescription, $application);
|
||||
}
|
||||
|
||||
public function getDescribeInputArgumentTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(ObjectsProvider::getInputArguments());
|
||||
}
|
||||
|
||||
public function getDescribeInputOptionTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(ObjectsProvider::getInputOptions());
|
||||
}
|
||||
|
||||
public function getDescribeInputDefinitionTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(ObjectsProvider::getInputDefinitions());
|
||||
}
|
||||
|
||||
public function getDescribeCommandTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(ObjectsProvider::getCommands());
|
||||
}
|
||||
|
||||
public function getDescribeApplicationTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(ObjectsProvider::getApplications());
|
||||
}
|
||||
|
||||
abstract protected function getDescriptor();
|
||||
|
||||
abstract protected function getFormat();
|
||||
|
||||
protected function getDescriptionTestData(array $objects)
|
||||
{
|
||||
$data = array();
|
||||
foreach ($objects as $name => $object) {
|
||||
$description = file_get_contents(sprintf('%s/../Fixtures/%s.%s', __DIR__, $name, $this->getFormat()));
|
||||
$data[] = array($object, $description);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function assertDescription($expectedDescription, $describedObject, array $options = array())
|
||||
{
|
||||
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
|
||||
$this->getDescriptor()->describe($output, $describedObject, $options + array('raw_output' => true));
|
||||
$this->assertEquals(trim($expectedDescription), trim(str_replace(PHP_EOL, "\n", $output->fetch())));
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Descriptor\JsonDescriptor;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
|
||||
class JsonDescriptorTest extends AbstractDescriptorTest
|
||||
{
|
||||
protected function getDescriptor()
|
||||
{
|
||||
return new JsonDescriptor();
|
||||
}
|
||||
|
||||
protected function getFormat()
|
||||
{
|
||||
return 'json';
|
||||
}
|
||||
|
||||
protected function assertDescription($expectedDescription, $describedObject, array $options = array())
|
||||
{
|
||||
$output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
|
||||
$this->getDescriptor()->describe($output, $describedObject, $options + array('raw_output' => true));
|
||||
$this->assertEquals(json_decode(trim($expectedDescription), true), json_decode(trim(str_replace(PHP_EOL, "\n", $output->fetch())), true));
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorApplicationMbString;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorCommandMbString;
|
||||
|
||||
class MarkdownDescriptorTest extends AbstractDescriptorTest
|
||||
{
|
||||
public function getDescribeCommandTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(array_merge(
|
||||
ObjectsProvider::getCommands(),
|
||||
array('command_mbstring' => new DescriptorCommandMbString())
|
||||
));
|
||||
}
|
||||
|
||||
public function getDescribeApplicationTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(array_merge(
|
||||
ObjectsProvider::getApplications(),
|
||||
array('application_mbstring' => new DescriptorApplicationMbString())
|
||||
));
|
||||
}
|
||||
|
||||
protected function getDescriptor()
|
||||
{
|
||||
return new MarkdownDescriptor();
|
||||
}
|
||||
|
||||
protected function getFormat()
|
||||
{
|
||||
return 'md';
|
||||
}
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorApplication1;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorApplication2;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorCommand1;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorCommand2;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <contact@jfsimon.fr>
|
||||
*/
|
||||
class ObjectsProvider
|
||||
{
|
||||
public static function getInputArguments()
|
||||
{
|
||||
return array(
|
||||
'input_argument_1' => new InputArgument('argument_name', InputArgument::REQUIRED),
|
||||
'input_argument_2' => new InputArgument('argument_name', InputArgument::IS_ARRAY, 'argument description'),
|
||||
'input_argument_3' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', 'default_value'),
|
||||
'input_argument_4' => new InputArgument('argument_name', InputArgument::REQUIRED, "multiline\nargument description"),
|
||||
'input_argument_with_style' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', '<comment>style</>'),
|
||||
'input_argument_with_default_inf_value' => new InputArgument('argument_name', InputArgument::OPTIONAL, 'argument description', INF),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getInputOptions()
|
||||
{
|
||||
return array(
|
||||
'input_option_1' => new InputOption('option_name', 'o', InputOption::VALUE_NONE),
|
||||
'input_option_2' => new InputOption('option_name', 'o', InputOption::VALUE_OPTIONAL, 'option description', 'default_value'),
|
||||
'input_option_3' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description'),
|
||||
'input_option_4' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'option description', array()),
|
||||
'input_option_5' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, "multiline\noption description"),
|
||||
'input_option_6' => new InputOption('option_name', array('o', 'O'), InputOption::VALUE_REQUIRED, 'option with multiple shortcuts'),
|
||||
'input_option_with_style' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description', '<comment>style</>'),
|
||||
'input_option_with_style_array' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'option description', array('<comment>Hello</comment>', '<info>world</info>')),
|
||||
'input_option_with_default_inf_value' => new InputOption('option_name', 'o', InputOption::VALUE_OPTIONAL, 'option description', INF),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getInputDefinitions()
|
||||
{
|
||||
return array(
|
||||
'input_definition_1' => new InputDefinition(),
|
||||
'input_definition_2' => new InputDefinition(array(new InputArgument('argument_name', InputArgument::REQUIRED))),
|
||||
'input_definition_3' => new InputDefinition(array(new InputOption('option_name', 'o', InputOption::VALUE_NONE))),
|
||||
'input_definition_4' => new InputDefinition(array(
|
||||
new InputArgument('argument_name', InputArgument::REQUIRED),
|
||||
new InputOption('option_name', 'o', InputOption::VALUE_NONE),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getCommands()
|
||||
{
|
||||
return array(
|
||||
'command_1' => new DescriptorCommand1(),
|
||||
'command_2' => new DescriptorCommand2(),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getApplications()
|
||||
{
|
||||
return array(
|
||||
'application_1' => new DescriptorApplication1(),
|
||||
'application_2' => new DescriptorApplication2(),
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Descriptor\TextDescriptor;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorApplication2;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorApplicationMbString;
|
||||
use Symfony\Component\Console\Tests\Fixtures\DescriptorCommandMbString;
|
||||
|
||||
class TextDescriptorTest extends AbstractDescriptorTest
|
||||
{
|
||||
public function getDescribeCommandTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(array_merge(
|
||||
ObjectsProvider::getCommands(),
|
||||
array('command_mbstring' => new DescriptorCommandMbString())
|
||||
));
|
||||
}
|
||||
|
||||
public function getDescribeApplicationTestData()
|
||||
{
|
||||
return $this->getDescriptionTestData(array_merge(
|
||||
ObjectsProvider::getApplications(),
|
||||
array('application_mbstring' => new DescriptorApplicationMbString())
|
||||
));
|
||||
}
|
||||
|
||||
public function testDescribeApplicationWithFilteredNamespace()
|
||||
{
|
||||
$application = new DescriptorApplication2();
|
||||
|
||||
$this->assertDescription(file_get_contents(__DIR__.'/../Fixtures/application_filtered_namespace.txt'), $application, array('namespace' => 'command4'));
|
||||
}
|
||||
|
||||
protected function getDescriptor()
|
||||
{
|
||||
return new TextDescriptor();
|
||||
}
|
||||
|
||||
protected function getFormat()
|
||||
{
|
||||
return 'txt';
|
||||
}
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Descriptor\XmlDescriptor;
|
||||
|
||||
class XmlDescriptorTest extends AbstractDescriptorTest
|
||||
{
|
||||
protected function getDescriptor()
|
||||
{
|
||||
return new XmlDescriptor();
|
||||
}
|
||||
|
||||
protected function getFormat()
|
||||
{
|
||||
return 'xml';
|
||||
}
|
||||
}
|
@@ -1,156 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\EventListener;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Event\ConsoleErrorEvent;
|
||||
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
|
||||
use Symfony\Component\Console\EventListener\ErrorListener;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\Input;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ErrorListenerTest extends TestCase
|
||||
{
|
||||
public function testOnConsoleError()
|
||||
{
|
||||
$error = new \TypeError('An error occurred');
|
||||
|
||||
$logger = $this->getLogger();
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('error')
|
||||
->with('Error thrown while running command "{command}". Message: "{message}"', array('exception' => $error, 'command' => 'test:run --foo=baz buzz', 'message' => 'An error occurred'))
|
||||
;
|
||||
|
||||
$listener = new ErrorListener($logger);
|
||||
$listener->onConsoleError(new ConsoleErrorEvent(new ArgvInput(array('console.php', 'test:run', '--foo=baz', 'buzz')), $this->getOutput(), $error, new Command('test:run')));
|
||||
}
|
||||
|
||||
public function testOnConsoleErrorWithNoCommandAndNoInputString()
|
||||
{
|
||||
$error = new \RuntimeException('An error occurred');
|
||||
|
||||
$logger = $this->getLogger();
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('error')
|
||||
->with('An error occurred while using the console. Message: "{message}"', array('exception' => $error, 'message' => 'An error occurred'))
|
||||
;
|
||||
|
||||
$listener = new ErrorListener($logger);
|
||||
$listener->onConsoleError(new ConsoleErrorEvent(new NonStringInput(), $this->getOutput(), $error));
|
||||
}
|
||||
|
||||
public function testOnConsoleTerminateForNonZeroExitCodeWritesToLog()
|
||||
{
|
||||
$logger = $this->getLogger();
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('debug')
|
||||
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run', 'code' => 255))
|
||||
;
|
||||
|
||||
$listener = new ErrorListener($logger);
|
||||
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run')), 255));
|
||||
}
|
||||
|
||||
public function testOnConsoleTerminateForZeroExitCodeDoesNotWriteToLog()
|
||||
{
|
||||
$logger = $this->getLogger();
|
||||
$logger
|
||||
->expects($this->never())
|
||||
->method('debug')
|
||||
;
|
||||
|
||||
$listener = new ErrorListener($logger);
|
||||
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run')), 0));
|
||||
}
|
||||
|
||||
public function testGetSubscribedEvents()
|
||||
{
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'console.error' => array('onConsoleError', -128),
|
||||
'console.terminate' => array('onConsoleTerminate', -128),
|
||||
),
|
||||
ErrorListener::getSubscribedEvents()
|
||||
);
|
||||
}
|
||||
|
||||
public function testAllKindsOfInputCanBeLogged()
|
||||
{
|
||||
$logger = $this->getLogger();
|
||||
$logger
|
||||
->expects($this->exactly(3))
|
||||
->method('debug')
|
||||
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run --foo=bar', 'code' => 255))
|
||||
;
|
||||
|
||||
$listener = new ErrorListener($logger);
|
||||
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArgvInput(array('console.php', 'test:run', '--foo=bar')), 255));
|
||||
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new ArrayInput(array('name' => 'test:run', '--foo' => 'bar')), 255));
|
||||
$listener->onConsoleTerminate($this->getConsoleTerminateEvent(new StringInput('test:run --foo=bar'), 255));
|
||||
}
|
||||
|
||||
public function testCommandNameIsDisplayedForNonStringableInput()
|
||||
{
|
||||
$logger = $this->getLogger();
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('debug')
|
||||
->with('Command "{command}" exited with code "{code}"', array('command' => 'test:run', 'code' => 255))
|
||||
;
|
||||
|
||||
$listener = new ErrorListener($logger);
|
||||
$listener->onConsoleTerminate($this->getConsoleTerminateEvent($this->getMockBuilder(InputInterface::class)->getMock(), 255));
|
||||
}
|
||||
|
||||
private function getLogger()
|
||||
{
|
||||
return $this->getMockForAbstractClass(LoggerInterface::class);
|
||||
}
|
||||
|
||||
private function getConsoleTerminateEvent(InputInterface $input, $exitCode)
|
||||
{
|
||||
return new ConsoleTerminateEvent(new Command('test:run'), $input, $this->getOutput(), $exitCode);
|
||||
}
|
||||
|
||||
private function getOutput()
|
||||
{
|
||||
return $this->getMockBuilder(OutputInterface::class)->getMock();
|
||||
}
|
||||
}
|
||||
|
||||
class NonStringInput extends Input
|
||||
{
|
||||
public function getFirstArgument()
|
||||
{
|
||||
}
|
||||
|
||||
public function hasParameterOption($values, $onlyParams = false)
|
||||
{
|
||||
}
|
||||
|
||||
public function getParameterOption($values, $default = false, $onlyParams = false)
|
||||
{
|
||||
}
|
||||
|
||||
public function parse()
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
class BarBucCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('bar:buc');
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
class DescriptorApplication2 extends Application
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('My Symfony application', 'v1.0');
|
||||
$this->add(new DescriptorCommand1());
|
||||
$this->add(new DescriptorCommand2());
|
||||
$this->add(new DescriptorCommand3());
|
||||
$this->add(new DescriptorCommand4());
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
class DescriptorApplicationMbString extends Application
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('MbString åpplicätion');
|
||||
|
||||
$this->add(new DescriptorCommandMbString());
|
||||
}
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
class DescriptorCommand1 extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('descriptor:command1')
|
||||
->setAliases(array('alias1', 'alias2'))
|
||||
->setDescription('command 1 description')
|
||||
->setHelp('command 1 help')
|
||||
;
|
||||
}
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class DescriptorCommand2 extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('descriptor:command2')
|
||||
->setDescription('command 2 description')
|
||||
->setHelp('command 2 help')
|
||||
->addUsage('-o|--option_name <argument_name>')
|
||||
->addUsage('<argument_name>')
|
||||
->addArgument('argument_name', InputArgument::REQUIRED)
|
||||
->addOption('option_name', 'o', InputOption::VALUE_NONE)
|
||||
;
|
||||
}
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
class DescriptorCommand3 extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('descriptor:command3')
|
||||
->setDescription('command 3 description')
|
||||
->setHelp('command 3 help')
|
||||
->setHidden(true)
|
||||
;
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
class DescriptorCommand4 extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('descriptor:command4')
|
||||
->setAliases(array('descriptor:alias_command4', 'command4:descriptor'))
|
||||
;
|
||||
}
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class DescriptorCommandMbString extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('descriptor:åèä')
|
||||
->setDescription('command åèä description')
|
||||
->setHelp('command åèä help')
|
||||
->addUsage('-o|--option_name <argument_name>')
|
||||
->addUsage('<argument_name>')
|
||||
->addArgument('argument_åèä', InputArgument::REQUIRED)
|
||||
->addOption('option_åèä', 'o', InputOption::VALUE_NONE)
|
||||
;
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Console\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
|
||||
/**
|
||||
* Dummy output.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class DummyOutput extends BufferedOutput
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getLogs()
|
||||
{
|
||||
$logs = array();
|
||||
foreach (explode(PHP_EOL, trim($this->fetch())) as $message) {
|
||||
preg_match('/^\[(.*)\] (.*)/', $message, $matches);
|
||||
$logs[] = sprintf('%s %s', $matches[1], $matches[2]);
|
||||
}
|
||||
|
||||
return $logs;
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Foo1Command extends Command
|
||||
{
|
||||
public $input;
|
||||
public $output;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('foo:bar1')
|
||||
->setDescription('The foo:bar1 command')
|
||||
->setAliases(array('afoobar1'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->output = $output;
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Foo2Command extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('foo1:bar')
|
||||
->setDescription('The foo1:bar command')
|
||||
->setAliases(array('afoobar2'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user