You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
5.0 KiB

  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2017, ownCloud GmbH
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Robin Appelman <robin@icewind.nl>
  7. *
  8. * @license AGPL-3.0
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace OC\Core\Command\Db\Migrations;
  24. use OC\DB\MigrationService;
  25. use OC\Migration\ConsoleOutput;
  26. use OCP\IDBConnection;
  27. use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface;
  28. use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
  29. use Symfony\Component\Console\Command\Command;
  30. use Symfony\Component\Console\Input\InputArgument;
  31. use Symfony\Component\Console\Input\InputInterface;
  32. use Symfony\Component\Console\Output\OutputInterface;
  33. class StatusCommand extends Command implements CompletionAwareInterface {
  34. /** @var IDBConnection */
  35. private $connection;
  36. /**
  37. * @param IDBConnection $connection
  38. */
  39. public function __construct(IDBConnection $connection) {
  40. $this->connection = $connection;
  41. parent::__construct();
  42. }
  43. protected function configure() {
  44. $this
  45. ->setName('migrations:status')
  46. ->setDescription('View the status of a set of migrations.')
  47. ->addArgument('app', InputArgument::REQUIRED, 'Name of the app this migration command shall work on');
  48. }
  49. public function execute(InputInterface $input, OutputInterface $output): int {
  50. $appName = $input->getArgument('app');
  51. $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output));
  52. $infos = $this->getMigrationsInfos($ms);
  53. foreach ($infos as $key => $value) {
  54. if (is_array($value)) {
  55. $output->writeln(" <comment>>></comment> $key:");
  56. foreach ($value as $subKey => $subValue) {
  57. $output->writeln(" <comment>>></comment> $subKey: " . str_repeat(' ', 46 - strlen($subKey)) . $subValue);
  58. }
  59. } else {
  60. $output->writeln(" <comment>>></comment> $key: " . str_repeat(' ', 50 - strlen($key)) . $value);
  61. }
  62. }
  63. return 0;
  64. }
  65. /**
  66. * @param string $optionName
  67. * @param CompletionContext $context
  68. * @return string[]
  69. */
  70. public function completeOptionValues($optionName, CompletionContext $context) {
  71. return [];
  72. }
  73. /**
  74. * @param string $argumentName
  75. * @param CompletionContext $context
  76. * @return string[]
  77. */
  78. public function completeArgumentValues($argumentName, CompletionContext $context) {
  79. if ($argumentName === 'app') {
  80. $allApps = \OC_App::getAllApps();
  81. return array_diff($allApps, \OC_App::getEnabledApps(true, true));
  82. }
  83. return [];
  84. }
  85. /**
  86. * @param MigrationService $ms
  87. * @return array associative array of human readable info name as key and the actual information as value
  88. */
  89. public function getMigrationsInfos(MigrationService $ms) {
  90. $executedMigrations = $ms->getMigratedVersions();
  91. $availableMigrations = $ms->getAvailableVersions();
  92. $executedUnavailableMigrations = array_diff($executedMigrations, array_keys($availableMigrations));
  93. $numExecutedUnavailableMigrations = count($executedUnavailableMigrations);
  94. $numNewMigrations = count(array_diff(array_keys($availableMigrations), $executedMigrations));
  95. $pending = $ms->describeMigrationStep('lastest');
  96. $infos = [
  97. 'App' => $ms->getApp(),
  98. 'Version Table Name' => $ms->getMigrationsTableName(),
  99. 'Migrations Namespace' => $ms->getMigrationsNamespace(),
  100. 'Migrations Directory' => $ms->getMigrationsDirectory(),
  101. 'Previous Version' => $this->getFormattedVersionAlias($ms, 'prev'),
  102. 'Current Version' => $this->getFormattedVersionAlias($ms, 'current'),
  103. 'Next Version' => $this->getFormattedVersionAlias($ms, 'next'),
  104. 'Latest Version' => $this->getFormattedVersionAlias($ms, 'latest'),
  105. 'Executed Migrations' => count($executedMigrations),
  106. 'Executed Unavailable Migrations' => $numExecutedUnavailableMigrations,
  107. 'Available Migrations' => count($availableMigrations),
  108. 'New Migrations' => $numNewMigrations,
  109. 'Pending Migrations' => count($pending) ? $pending : 'None'
  110. ];
  111. return $infos;
  112. }
  113. /**
  114. * @param MigrationService $migrationService
  115. * @param string $alias
  116. * @return mixed|null|string
  117. */
  118. private function getFormattedVersionAlias(MigrationService $migrationService, $alias) {
  119. $migration = $migrationService->getMigration($alias);
  120. //No version found
  121. if ($migration === null) {
  122. if ($alias === 'next') {
  123. return 'Already at latest migration step';
  124. }
  125. if ($alias === 'prev') {
  126. return 'Already at first migration step';
  127. }
  128. }
  129. return $migration;
  130. }
  131. }