SetupChecks.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OC\Core\Command;
  8. use OCP\SetupCheck\ISetupCheckManager;
  9. use Symfony\Component\Console\Input\InputInterface;
  10. use Symfony\Component\Console\Output\OutputInterface;
  11. class SetupChecks extends Base {
  12. public function __construct(
  13. private ISetupCheckManager $setupCheckManager,
  14. ) {
  15. parent::__construct();
  16. }
  17. protected function configure(): void {
  18. parent::configure();
  19. $this
  20. ->setName('setupchecks')
  21. ->setDescription('Run setup checks and output the results')
  22. ;
  23. }
  24. /**
  25. * @TODO move this method to a common service used by notifications, activity and this command
  26. * @throws \InvalidArgumentException if a parameter has no name or no type
  27. */
  28. private function richToParsed(string $message, array $parameters): string {
  29. $placeholders = [];
  30. $replacements = [];
  31. foreach ($parameters as $placeholder => $parameter) {
  32. $placeholders[] = '{' . $placeholder . '}';
  33. foreach (['name','type'] as $requiredField) {
  34. if (!isset($parameter[$requiredField]) || !is_string($parameter[$requiredField])) {
  35. throw new \InvalidArgumentException("Invalid rich object, {$requiredField} field is missing");
  36. }
  37. }
  38. $replacements[] = match($parameter['type']) {
  39. 'user' => '@' . $parameter['name'],
  40. 'file' => $parameter['path'] ?? $parameter['name'],
  41. default => $parameter['name'],
  42. };
  43. }
  44. return str_replace($placeholders, $replacements, $message);
  45. }
  46. protected function execute(InputInterface $input, OutputInterface $output): int {
  47. $results = $this->setupCheckManager->runAll();
  48. switch ($input->getOption('output')) {
  49. case self::OUTPUT_FORMAT_JSON:
  50. case self::OUTPUT_FORMAT_JSON_PRETTY:
  51. $this->writeArrayInOutputFormat($input, $output, $results);
  52. break;
  53. default:
  54. foreach ($results as $category => $checks) {
  55. $output->writeln("\t{$category}:");
  56. foreach ($checks as $check) {
  57. $styleTag = match ($check->getSeverity()) {
  58. 'success' => 'info',
  59. 'error' => 'error',
  60. 'warning' => 'comment',
  61. default => null,
  62. };
  63. $emoji = match ($check->getSeverity()) {
  64. 'success' => '✓',
  65. 'error' => '✗',
  66. 'warning' => '⚠',
  67. default => 'ℹ',
  68. };
  69. $verbosity = ($check->getSeverity() === 'error' ? OutputInterface::VERBOSITY_QUIET : OutputInterface::VERBOSITY_NORMAL);
  70. $description = $check->getDescription();
  71. $descriptionParameters = $check->getDescriptionParameters();
  72. if ($description !== null && $descriptionParameters !== null) {
  73. $description = $this->richToParsed($description, $descriptionParameters);
  74. }
  75. $output->writeln(
  76. "\t\t".
  77. ($styleTag !== null ? "<{$styleTag}>" : '').
  78. "{$emoji} ".
  79. ($check->getName() ?? $check::class).
  80. ($description !== null ? ': '.$description : '').
  81. ($styleTag !== null ? "</{$styleTag}>" : ''),
  82. $verbosity
  83. );
  84. }
  85. }
  86. }
  87. foreach ($results as $category => $checks) {
  88. foreach ($checks as $check) {
  89. if ($check->getSeverity() !== 'success') {
  90. return self::FAILURE;
  91. }
  92. }
  93. }
  94. return self::SUCCESS;
  95. }
  96. }