diff --git a/core/Command/Base.php b/core/Command/Base.php index 029942c067329..a5cafae6fd7b9 100644 --- a/core/Command/Base.php +++ b/core/Command/Base.php @@ -1,4 +1,6 @@ addOption( - 'output', - null, - InputOption::VALUE_OPTIONAL, - 'Output format (plain, json or json_pretty, default is plain)', - $this->defaultOutputFormat - ) - ; - } - - /** - * @param InputInterface $input - * @param OutputInterface $output - * @param array $items - * @param string $prefix - */ - protected function writeArrayInOutputFormat(InputInterface $input, OutputInterface $output, $items, $prefix = ' - ') { - switch ($input->getOption('output')) { - case self::OUTPUT_FORMAT_JSON: - $output->writeln(json_encode($items)); - break; - case self::OUTPUT_FORMAT_JSON_PRETTY: - $output->writeln(json_encode($items, JSON_PRETTY_PRINT)); - break; - default: - foreach ($items as $key => $item) { - if (is_array($item)) { - $output->writeln($prefix . $key . ':'); - $this->writeArrayInOutputFormat($input, $output, $item, ' ' . $prefix); - continue; - } - if (!is_int($key) || ListCommand::class === get_class($this)) { - $value = $this->valueToString($item); - if (!is_null($value)) { - $output->writeln($prefix . $key . ': ' . $value); - } else { - $output->writeln($prefix . $key); - } - } else { - $output->writeln($prefix . $this->valueToString($item)); - } - } - break; - } - } - - /** - * @param InputInterface $input - * @param OutputInterface $output - * @param mixed $item - */ - protected function writeMixedInOutputFormat(InputInterface $input, OutputInterface $output, $item) { - if (is_array($item)) { - $this->writeArrayInOutputFormat($input, $output, $item, ''); - return; - } - - switch ($input->getOption('output')) { - case self::OUTPUT_FORMAT_JSON: - $output->writeln(json_encode($item)); - break; - case self::OUTPUT_FORMAT_JSON_PRETTY: - $output->writeln(json_encode($item, JSON_PRETTY_PRINT)); - break; - default: - $output->writeln($this->valueToString($item, false)); - break; - } - } - - protected function valueToString($value, $returnNull = true) { - if ($value === false) { - return 'false'; - } elseif ($value === true) { - return 'true'; - } elseif ($value === null) { - return $returnNull ? null : 'null'; - } else { - return $value; - } - } +use OCP\Command\ACommand; - /** - * Throw InterruptedException when interrupted by user - * - * @throws InterruptedException - */ - protected function abortIfInterrupted() { - if ($this->php_pcntl_signal === false) { - return; - } - - pcntl_signal_dispatch(); - - if ($this->interrupted === true) { - throw new InterruptedException('Command interrupted by user'); - } - } - - /** - * Changes the status of the command to "interrupted" if ctrl-c has been pressed - * - * Gives a chance to the command to properly terminate what it's doing - */ - protected function cancelOperation() { - $this->interrupted = true; - } - - public function run(InputInterface $input, OutputInterface $output) { - // check if the php pcntl_signal functions are accessible - $this->php_pcntl_signal = function_exists('pcntl_signal'); - if ($this->php_pcntl_signal) { - // Collect interrupts and notify the running command - pcntl_signal(SIGTERM, [$this, 'cancelOperation']); - pcntl_signal(SIGINT, [$this, 'cancelOperation']); - } - - return parent::run($input, $output); - } - - /** - * @param string $optionName - * @param CompletionContext $context - * @return string[] - */ - public function completeOptionValues($optionName, CompletionContext $context) { - if ($optionName === 'output') { - return ['plain', 'json', 'json_pretty']; - } - return []; - } - - /** - * @param string $argumentName - * @param CompletionContext $context - * @return string[] - */ - public function completeArgumentValues($argumentName, CompletionContext $context) { - return []; - } +/** + * @depreacted 25.0.0 Please use \OCP\Command\ACommand directly + */ +class Base extends ACommand { } diff --git a/lib/public/Command/ACommand.php b/lib/public/Command/ACommand.php new file mode 100644 index 0000000000000..279e0f83570a4 --- /dev/null +++ b/lib/public/Command/ACommand.php @@ -0,0 +1,220 @@ + + * @author Daniel Kesselberg + * @author Joas Schilling + * @author Morris Jobke + * @author Thomas Müller + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OCP\Command; + +use OC\Core\Command\InterruptedException; +use OC\Core\Command\User\ListCommand; +use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; +use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * @since 25.0.0 + */ +abstract class ACommand extends Command implements CompletionAwareInterface { + /** + * @since 25.0.0 + */ + public const OUTPUT_FORMAT_PLAIN = 'plain'; + /** + * @since 25.0.0 + */ + public const OUTPUT_FORMAT_JSON = 'json'; + /** + * @since 25.0.0 + */ + public const OUTPUT_FORMAT_JSON_PRETTY = 'json_pretty'; + + protected bool $phpPcntlSignal = false; + protected bool $interrupted = false; + + /** + * @since 25.0.0 + */ + protected function configure(): void { + parent::configure(); + $this + ->addOption( + 'output', + null, + InputOption::VALUE_OPTIONAL, + 'Output format (plain, json or json_pretty, default is plain)', + self::OUTPUT_FORMAT_PLAIN + ) + ; + } + + /** + * @since 25.0.0 + */ + protected function writeArrayInOutputFormat(InputInterface $input, OutputInterface $output, array $items, string $prefix = ' - '): void { + switch ($input->getOption('output')) { + case self::OUTPUT_FORMAT_JSON: + $output->writeln(json_encode($items)); + break; + case self::OUTPUT_FORMAT_JSON_PRETTY: + $output->writeln(json_encode($items, JSON_PRETTY_PRINT)); + break; + default: + foreach ($items as $key => $item) { + if (is_array($item)) { + $output->writeln($prefix . $key . ':'); + $this->writeArrayInOutputFormat($input, $output, $item, ' ' . $prefix); + continue; + } + if (!is_int($key) || ListCommand::class === get_class($this)) { + $value = $this->valueToString($item); + if (!is_null($value)) { + $output->writeln($prefix . $key . ': ' . $value); + } else { + $output->writeln($prefix . $key); + } + } else { + $output->writeln($prefix . $this->valueToString($item)); + } + } + break; + } + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @param mixed $item + * @since 25.0.0 + */ + protected function writeMixedInOutputFormat(InputInterface $input, OutputInterface $output, $item): void { + if (is_array($item)) { + $this->writeArrayInOutputFormat($input, $output, $item, ''); + return; + } + + switch ($input->getOption('output')) { + case self::OUTPUT_FORMAT_JSON: + $output->writeln(json_encode($item)); + break; + case self::OUTPUT_FORMAT_JSON_PRETTY: + $output->writeln(json_encode($item, JSON_PRETTY_PRINT)); + break; + default: + $output->writeln($this->valueToString($item, false)); + break; + } + } + + /** + * @param mixed $value + * @param bool $returnNull + * @return ?string + * @since 25.0.0 + */ + protected function valueToString($value, bool $returnNull = true): ?string { + if ($value === false) { + return 'false'; + } elseif ($value === true) { + return 'true'; + } elseif ($value === null) { + return $returnNull ? null : 'null'; + } else { + return $value; + } + } + + /** + * Throw InterruptedException when interrupted by user + * + * @throws InterruptedException + * @since 25.0.0 + */ + protected function abortIfInterrupted(): void { + if ($this->phpPcntlSignal === false) { + return; + } + + pcntl_signal_dispatch(); + + if ($this->interrupted === true) { + throw new InterruptedException('Command interrupted by user'); + } + } + + /** + * Changes the status of the command to "interrupted" if ctrl-c has been pressed + * + * Gives a chance to the command to properly terminate what it's doing + * @since 25.0.0 + */ + protected function cancelOperation(): void { + $this->interrupted = true; + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int + * @throws \Exception + * @since 25.0.0 + */ + public function run(InputInterface $input, OutputInterface $output): int { + // check if the php pcntl_signal functions are accessible + $this->phpPcntlSignal = function_exists('pcntl_signal'); + if ($this->phpPcntlSignal) { + // Collect interrupts and notify the running command + pcntl_signal(SIGTERM, [$this, 'cancelOperation']); + pcntl_signal(SIGINT, [$this, 'cancelOperation']); + } + + return parent::run($input, $output); + } + + /** + * @param string $optionName + * @param CompletionContext $context + * @return string[] + * @since 25.0.0 + */ + public function completeOptionValues($optionName, CompletionContext $context): array { + if ($optionName === 'output') { + return ['plain', 'json', 'json_pretty']; + } + return []; + } + + /** + * @param string $argumentName + * @param CompletionContext $context + * @return string[] + * @since 25.0.0 + */ + public function completeArgumentValues($argumentName, CompletionContext $context): array { + return []; + } +}