12 namespace Symfony\Component\Console;
41 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
87 $this->defaultCommand =
'list';
115 if (null === $input) {
119 if (null === $output) {
126 $exitCode = $this->
doRun($input, $output);
127 }
catch (\Exception $e) {
128 if (!$this->catchExceptions) {
138 $exitCode = $e->getCode();
139 if (is_numeric($exitCode)) {
140 $exitCode = (int) $exitCode;
141 if (0 === $exitCode) {
149 if ($this->autoExit) {
150 if ($exitCode > 255) {
180 $input =
new ArrayInput(array(
'command' =>
'help'));
182 $this->wantHelps =
true;
188 $input =
new ArrayInput(array(
'command' => $this->defaultCommand));
194 $this->runningCommand = $command;
195 $exitCode = $this->
doRunCommand($command, $input, $output);
196 $this->runningCommand = null;
266 $this->catchExceptions = (bool) $boolean;
278 $this->autoExit = (bool) $boolean;
339 return sprintf(
'<info>%s</info> version <comment>%s</comment>', $this->
getName(), $this->
getVersion());
342 return '<info>Console Tool</info>';
368 foreach ($commands as $command) {
369 $this->
add($command);
395 throw new \LogicException(sprintf(
'Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
398 $this->commands[$command->
getName()] = $command;
401 $this->commands[$alias] = $command;
420 if (!isset($this->commands[
$name])) {
421 throw new \InvalidArgumentException(sprintf(
'The command "%s" does not exist.', $name));
424 $command = $this->commands[
$name];
426 if ($this->wantHelps) {
427 $this->wantHelps =
false;
429 $helpCommand = $this->
get(
'help');
430 $helpCommand->setCommand($command);
449 return isset($this->commands[
$name]);
461 $namespaces = array();
462 foreach ($this->commands as $command) {
465 foreach ($command->getAliases() as $alias) {
470 return array_values(array_unique(array_filter($namespaces)));
485 $expr = preg_replace_callback(
'{([^:]+|)}',
function ($matches) {
return preg_quote($matches[1]).
'[^:]*'; }, $namespace);
486 $namespaces = preg_grep(
'{^'.$expr.
'}', $allNamespaces);
488 if (empty($namespaces)) {
489 $message = sprintf(
'There are no commands defined in the "%s" namespace.', $namespace);
492 if (1 == count($alternatives)) {
493 $message .=
"\n\nDid you mean this?\n ";
495 $message .=
"\n\nDid you mean one of these?\n ";
498 $message .= implode(
"\n ", $alternatives);
501 throw new \InvalidArgumentException($message);
504 $exact = in_array($namespace, $namespaces,
true);
505 if (count($namespaces) > 1 && !$exact) {
506 throw new \InvalidArgumentException(sprintf(
'The namespace "%s" is ambiguous (%s).', $namespace, $this->
getAbbreviationSuggestions(array_values($namespaces))));
509 return $exact ? $namespace : reset($namespaces);
528 $allCommands = array_keys($this->commands);
529 $expr = preg_replace_callback(
'{([^:]+|)}',
function ($matches) {
return preg_quote($matches[1]).
'[^:]*'; },
$name);
530 $commands = preg_grep(
'{^'.$expr.
'}', $allCommands);
532 if (empty($commands) || count(preg_grep(
'{^'.$expr.
'$}', $commands)) < 1) {
533 if (
false !== $pos = strrpos(
$name,
':')) {
538 $message = sprintf(
'Command "%s" is not defined.',
$name);
541 if (1 == count($alternatives)) {
542 $message .=
"\n\nDid you mean this?\n ";
544 $message .=
"\n\nDid you mean one of these?\n ";
546 $message .= implode(
"\n ", $alternatives);
549 throw new \InvalidArgumentException($message);
553 if (count($commands) > 1) {
555 $commands = array_filter($commands,
function ($nameOrAlias) use ($commandList, $commands) {
556 $commandName = $commandList[$nameOrAlias]->getName();
558 return $commandName === $nameOrAlias || !in_array($commandName, $commands);
562 $exact = in_array(
$name, $commands,
true);
563 if (count($commands) > 1 && !$exact) {
566 throw new \InvalidArgumentException(sprintf(
'Command "%s" is ambiguous (%s).',
$name, $suggestions));
569 return $this->
get($exact ?
$name : reset($commands));
583 public function all($namespace = null)
585 if (null === $namespace) {
590 foreach ($this->commands as
$name => $command) {
609 foreach ($names as
$name) {
610 for ($len = strlen($name); $len > 0; --$len) {
611 $abbrev = substr($name, 0, $len);
612 $abbrevs[$abbrev][] =
$name;
629 public function asText($namespace = null, $raw =
false)
631 @trigger_error(
'The '.__METHOD__.
' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
635 $descriptor->describe($output, $this, array(
'namespace' => $namespace,
'raw_output' =>
true));
637 return $output->fetch();
650 public function asXml($namespace = null, $asDom =
false)
652 @trigger_error(
'The '.__METHOD__.
' method is deprecated since version 2.3 and will be removed in 3.0.', E_USER_DEPRECATED);
657 return $descriptor->getApplicationDocument($this, $namespace);
661 $descriptor->describe($output, $this, array(
'namespace' => $namespace));
663 return $output->fetch();
675 $title = sprintf(
' [%s] ', get_class($e));
681 if (defined(
'HHVM_VERSION') && $width > 1 << 31) {
684 $formatter = $output->getFormatter();
686 foreach (preg_split(
'/\r?\n/', $e->getMessage()) as $line) {
689 $lineLength = $this->
stringWidth(preg_replace(
'/\[[^m]*m/',
'', $formatter->format($line))) + 4;
690 $lines[] = array($line, $lineLength);
692 $len = max($lineLength, $len);
696 $messages = array(
'',
'');
697 $messages[] = $emptyLine = $formatter->format(sprintf(
'<error>%s</error>', str_repeat(
' ', $len)));
698 $messages[] = $formatter->format(sprintf(
'<error>%s%s</error>', $title, str_repeat(
' ', max(0, $len - $this->
stringWidth($title)))));
699 foreach ($lines as $line) {
700 $messages[] = $formatter->format(sprintf(
'<error> %s %s</error>', $line[0], str_repeat(
' ', $len - $line[1])));
702 $messages[] = $emptyLine;
708 if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
709 $output->writeln(
'<comment>Exception trace:</comment>');
712 $trace = $e->getTrace();
713 array_unshift($trace, array(
715 'file' => $e->getFile() !== null ? $e->getFile() :
'n/a',
716 'line' => $e->getLine() !== null ? $e->getLine() :
'n/a',
720 for ($i = 0, $count = count($trace); $i < $count; ++$i) {
721 $class = isset($trace[$i][
'class']) ? $trace[$i][
'class'] :
'';
722 $type = isset($trace[$i][
'type']) ? $trace[$i][
'type'] :
'';
723 $function = $trace[$i][
'function'];
724 $file = isset($trace[$i][
'file']) ? $trace[$i][
'file'] :
'n/a';
725 $line = isset($trace[$i][
'line']) ? $trace[$i][
'line'] :
'n/a';
727 $output->writeln(sprintf(
' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line));
730 $output->writeln(
'');
731 $output->writeln(
'');
733 }
while ($e = $e->getPrevious());
735 if (null !== $this->runningCommand) {
736 $output->writeln(sprintf(
'<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->
getName())));
737 $output->writeln(
'');
738 $output->writeln(
'');
751 return $dimensions[0];
763 return $dimensions[1];
773 if ($this->terminalDimensions) {
777 if (
'\\' === DIRECTORY_SEPARATOR) {
779 if (preg_match(
'/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv(
'ANSICON')), $matches)) {
780 return array((
int) $matches[1], (
int) $matches[2]);
783 if (preg_match(
'/^(\d+)x(\d+)$/', $this->
getConsoleMode(), $matches)) {
784 return array((
int) $matches[1], (
int) $matches[2]);
790 if (preg_match(
'/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
791 return array((
int) $matches[2], (
int) $matches[1]);
794 if (preg_match(
'/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
795 return array((
int) $matches[2], (
int) $matches[1]);
799 return array(null, null);
814 $this->terminalDimensions = array($width, $height);
836 $inputStream = $this->
getHelperSet()->get(
'question')->getInputStream();
837 if (!@posix_isatty($inputStream) &&
false === getenv(
'SHELL_INTERACTIVE')) {
873 $helper->setInput($input);
877 if (null === $this->dispatcher) {
878 return $command->
run($input, $output);
884 if ($event->commandShouldRun()) {
886 $exitCode = $command->
run($input, $output);
887 }
catch (\Exception $e) {
903 return $event->getExitCode();
930 new InputOption(
'--verbose',
'-v|vv|vvv',
InputOption::VALUE_NONE,
'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
973 if (!function_exists(
'proc_open')) {
977 $descriptorspec = array(1 => array(
'pipe',
'w'), 2 => array(
'pipe',
'w'));
978 $process = proc_open(
'stty -a | grep columns', $descriptorspec, $pipes, null, null, array(
'suppress_errors' =>
true));
979 if (is_resource($process)) {
980 $info = stream_get_contents($pipes[1]);
983 proc_close($process);
996 if (!function_exists(
'proc_open')) {
1000 $descriptorspec = array(1 => array(
'pipe',
'w'), 2 => array(
'pipe',
'w'));
1001 $process = proc_open(
'mode CON', $descriptorspec, $pipes, null, null, array(
'suppress_errors' =>
true));
1002 if (is_resource($process)) {
1003 $info = stream_get_contents($pipes[1]);
1006 proc_close($process);
1008 if (preg_match(
'/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
1009 return $matches[2].
'x'.$matches[1];
1023 return sprintf(
'%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(
' and %d more', count($abbrevs) - 2) :
'');
1038 $parts = explode(
':',
$name);
1041 return implode(
':', null === $limit ? $parts : array_slice($parts, 0, $limit));
1056 $alternatives = array();
1058 $collectionParts = array();
1059 foreach ($collection as $item) {
1060 $collectionParts[$item] = explode(
':', $item);
1063 foreach (explode(
':',
$name) as $i => $subname) {
1064 foreach ($collectionParts as $collectionName => $parts) {
1065 $exists = isset($alternatives[$collectionName]);
1066 if (!isset($parts[$i]) && $exists) {
1067 $alternatives[$collectionName] += $threshold;
1069 }
elseif (!isset($parts[$i])) {
1073 $lev = levenshtein($subname, $parts[$i]);
1074 if ($lev <= strlen($subname) / 3 ||
'' !== $subname &&
false !== strpos($parts[$i], $subname)) {
1075 $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
1077 $alternatives[$collectionName] += $threshold;
1082 foreach ($collection as $item) {
1083 $lev = levenshtein(
$name, $item);
1084 if ($lev <= strlen(
$name) / 3 ||
false !== strpos($item,
$name)) {
1085 $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
1089 $alternatives = array_filter($alternatives,
function ($lev) use ($threshold) {
return $lev < 2 * $threshold; });
1090 asort($alternatives);
1092 return array_keys($alternatives);
1102 $this->defaultCommand = $commandName;
1107 if (!function_exists(
'mb_strwidth')) {
1108 return strlen($string);
1111 if (
false === $encoding = mb_detect_encoding($string)) {
1112 return strlen($string);
1115 return mb_strwidth($string, $encoding);
1124 if (!function_exists(
'mb_strwidth')) {
1125 return str_split($string, $width);
1128 if (
false === $encoding = mb_detect_encoding($string)) {
1129 return str_split($string, $width);
1132 $utf8String = mb_convert_encoding($string,
'utf8', $encoding);
1135 foreach (preg_split(
'//u', $utf8String) as $char) {
1137 if (mb_strwidth($line.$char,
'utf8') <= $width) {
1142 $lines[] = str_pad($line, $width);
1146 $lines[] = count($lines) ? str_pad($line, $width) : $line;
1149 mb_convert_variables($encoding,
'utf8', $lines);
1164 $parts = explode(
':',
$name, -1);
1165 $namespaces = array();
1167 foreach ($parts as $part) {
1168 if (count($namespaces)) {
1169 $namespaces[] = end($namespaces).
':'.$part;
1171 $namespaces[] = $part;