annotate vendor/consolidation/annotated-command/src/ResultWriter.php @ 4:a9cd425dd02b

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:11:55 +0000
parents
children
rev   line source
Chris@4 1 <?php
Chris@4 2 namespace Consolidation\AnnotatedCommand;
Chris@4 3
Chris@4 4 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ReplaceCommandHookDispatcher;
Chris@4 5 use Symfony\Component\Console\Input\InputInterface;
Chris@4 6 use Symfony\Component\Console\Output\OutputInterface;
Chris@4 7 use Symfony\Component\Console\Output\ConsoleOutputInterface;
Chris@4 8
Chris@4 9 use Consolidation\OutputFormatters\FormatterManager;
Chris@4 10 use Consolidation\OutputFormatters\Options\FormatterOptions;
Chris@4 11 use Consolidation\AnnotatedCommand\Hooks\HookManager;
Chris@4 12 use Consolidation\AnnotatedCommand\Options\PrepareFormatter;
Chris@4 13
Chris@4 14 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher;
Chris@4 15 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\OptionsHookDispatcher;
Chris@4 16 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\InteractHookDispatcher;
Chris@4 17 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ValidateHookDispatcher;
Chris@4 18 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ProcessResultHookDispatcher;
Chris@4 19 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\StatusDeterminerHookDispatcher;
Chris@4 20 use Consolidation\AnnotatedCommand\Hooks\Dispatchers\ExtracterHookDispatcher;
Chris@4 21
Chris@4 22 /**
Chris@4 23 * Write the results of a command. Inject your ResultWriter
Chris@4 24 * into the CommandProcessor.
Chris@4 25 */
Chris@4 26 class ResultWriter
Chris@4 27 {
Chris@4 28 /** var FormatterManager */
Chris@4 29 protected $formatterManager;
Chris@4 30 /** @var callable */
Chris@4 31 protected $displayErrorFunction;
Chris@4 32
Chris@4 33 public function setFormatterManager(FormatterManager $formatterManager)
Chris@4 34 {
Chris@4 35 $this->formatterManager = $formatterManager;
Chris@4 36 return $this;
Chris@4 37 }
Chris@4 38
Chris@4 39 /**
Chris@4 40 * Return the formatter manager
Chris@4 41 * @return FormatterManager
Chris@4 42 */
Chris@4 43 public function formatterManager()
Chris@4 44 {
Chris@4 45 return $this->formatterManager;
Chris@4 46 }
Chris@4 47
Chris@4 48 public function setDisplayErrorFunction(callable $fn)
Chris@4 49 {
Chris@4 50 $this->displayErrorFunction = $fn;
Chris@4 51 return $this;
Chris@4 52 }
Chris@4 53
Chris@4 54 /**
Chris@4 55 * Handle the result output and status code calculation.
Chris@4 56 */
Chris@4 57 public function handle(OutputInterface $output, $result, CommandData $commandData, $statusCodeDispatcher = null, $extractDispatcher = null)
Chris@4 58 {
Chris@4 59 // A little messy, for backwards compatibility: if the result implements
Chris@4 60 // ExitCodeInterface, then use that as the exit code. If a status code
Chris@4 61 // dispatcher returns a non-zero result, then we will never print a
Chris@4 62 // result.
Chris@4 63 $status = null;
Chris@4 64 if ($result instanceof ExitCodeInterface) {
Chris@4 65 $status = $result->getExitCode();
Chris@4 66 } elseif (isset($statusCodeDispatcher)) {
Chris@4 67 $status = $statusCodeDispatcher->determineStatusCode($result);
Chris@4 68 if (isset($status) && ($status != 0)) {
Chris@4 69 return $status;
Chris@4 70 }
Chris@4 71 }
Chris@4 72 // If the result is an integer and no separate status code was provided, then use the result as the status and do no output.
Chris@4 73 if (is_integer($result) && !isset($status)) {
Chris@4 74 return $result;
Chris@4 75 }
Chris@4 76 $status = $this->interpretStatusCode($status);
Chris@4 77
Chris@4 78 // Get the structured output, the output stream and the formatter
Chris@4 79 $structuredOutput = $result;
Chris@4 80 if (isset($extractDispatcher)) {
Chris@4 81 $structuredOutput = $extractDispatcher->extractOutput($result);
Chris@4 82 }
Chris@4 83 if (($status != 0) && is_string($structuredOutput)) {
Chris@4 84 $output = $this->chooseOutputStream($output, $status);
Chris@4 85 return $this->writeErrorMessage($output, $status, $structuredOutput, $result);
Chris@4 86 }
Chris@4 87 if ($this->dataCanBeFormatted($structuredOutput) && isset($this->formatterManager)) {
Chris@4 88 return $this->writeUsingFormatter($output, $structuredOutput, $commandData, $status);
Chris@4 89 }
Chris@4 90 return $this->writeCommandOutput($output, $structuredOutput, $status);
Chris@4 91 }
Chris@4 92
Chris@4 93 protected function dataCanBeFormatted($structuredOutput)
Chris@4 94 {
Chris@4 95 if (!isset($this->formatterManager)) {
Chris@4 96 return false;
Chris@4 97 }
Chris@4 98 return
Chris@4 99 is_object($structuredOutput) ||
Chris@4 100 is_array($structuredOutput);
Chris@4 101 }
Chris@4 102
Chris@4 103 /**
Chris@4 104 * Determine the formatter that should be used to render
Chris@4 105 * output.
Chris@4 106 *
Chris@4 107 * If the user specified a format via the --format option,
Chris@4 108 * then always return that. Otherwise, return the default
Chris@4 109 * format, unless --pipe was specified, in which case
Chris@4 110 * return the default pipe format, format-pipe.
Chris@4 111 *
Chris@4 112 * n.b. --pipe is a handy option introduced in Drush 2
Chris@4 113 * (or perhaps even Drush 1) that indicates that the command
Chris@4 114 * should select the output format that is most appropriate
Chris@4 115 * for use in scripts (e.g. to pipe to another command).
Chris@4 116 *
Chris@4 117 * @return string
Chris@4 118 */
Chris@4 119 protected function getFormat(FormatterOptions $options)
Chris@4 120 {
Chris@4 121 // In Symfony Console, there is no way for us to differentiate
Chris@4 122 // between the user specifying '--format=table', and the user
Chris@4 123 // not specifying --format when the default value is 'table'.
Chris@4 124 // Therefore, we must make --field always override --format; it
Chris@4 125 // cannot become the default value for --format.
Chris@4 126 if ($options->get('field')) {
Chris@4 127 return 'string';
Chris@4 128 }
Chris@4 129 $defaults = [];
Chris@4 130 if ($options->get('pipe')) {
Chris@4 131 return $options->get('pipe-format', [], 'tsv');
Chris@4 132 }
Chris@4 133 return $options->getFormat($defaults);
Chris@4 134 }
Chris@4 135
Chris@4 136 /**
Chris@4 137 * Determine whether we should use stdout or stderr.
Chris@4 138 */
Chris@4 139 protected function chooseOutputStream(OutputInterface $output, $status)
Chris@4 140 {
Chris@4 141 // If the status code indicates an error, then print the
Chris@4 142 // result to stderr rather than stdout
Chris@4 143 if ($status && ($output instanceof ConsoleOutputInterface)) {
Chris@4 144 return $output->getErrorOutput();
Chris@4 145 }
Chris@4 146 return $output;
Chris@4 147 }
Chris@4 148
Chris@4 149 /**
Chris@4 150 * Call the formatter to output the provided data.
Chris@4 151 */
Chris@4 152 protected function writeUsingFormatter(OutputInterface $output, $structuredOutput, CommandData $commandData, $status = 0)
Chris@4 153 {
Chris@4 154 $formatterOptions = $commandData->formatterOptions();
Chris@4 155 $format = $this->getFormat($formatterOptions);
Chris@4 156 $this->formatterManager->write(
Chris@4 157 $output,
Chris@4 158 $format,
Chris@4 159 $structuredOutput,
Chris@4 160 $formatterOptions
Chris@4 161 );
Chris@4 162 return $status;
Chris@4 163 }
Chris@4 164
Chris@4 165 /**
Chris@4 166 * Description
Chris@4 167 * @param OutputInterface $output
Chris@4 168 * @param int $status
Chris@4 169 * @param string $structuredOutput
Chris@4 170 * @param mixed $originalResult
Chris@4 171 * @return type
Chris@4 172 */
Chris@4 173 protected function writeErrorMessage($output, $status, $structuredOutput, $originalResult)
Chris@4 174 {
Chris@4 175 if (isset($this->displayErrorFunction)) {
Chris@4 176 call_user_func($this->displayErrorFunction, $output, $structuredOutput, $status, $originalResult);
Chris@4 177 } else {
Chris@4 178 $this->writeCommandOutput($output, $structuredOutput);
Chris@4 179 }
Chris@4 180 return $status;
Chris@4 181 }
Chris@4 182
Chris@4 183 /**
Chris@4 184 * If the result object is a string, then print it.
Chris@4 185 */
Chris@4 186 protected function writeCommandOutput(
Chris@4 187 OutputInterface $output,
Chris@4 188 $structuredOutput,
Chris@4 189 $status = 0
Chris@4 190 ) {
Chris@4 191 // If there is no formatter, we will print strings,
Chris@4 192 // but can do no more than that.
Chris@4 193 if (is_string($structuredOutput)) {
Chris@4 194 $output->writeln($structuredOutput);
Chris@4 195 }
Chris@4 196 return $status;
Chris@4 197 }
Chris@4 198
Chris@4 199 /**
Chris@4 200 * If a status code was set, then return it; otherwise,
Chris@4 201 * presume success.
Chris@4 202 */
Chris@4 203 protected function interpretStatusCode($status)
Chris@4 204 {
Chris@4 205 if (isset($status)) {
Chris@4 206 return $status;
Chris@4 207 }
Chris@4 208 return 0;
Chris@4 209 }
Chris@4 210 }