Skip to content

Commit

Permalink
WIP runtime repair steps
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Needham committed Jul 5, 2018
1 parent dc0d8a6 commit 25921a0
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 30 deletions.
92 changes: 64 additions & 28 deletions core/Command/Maintenance/Repair.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
namespace OC\Core\Command\Maintenance;

use Exception;
use OCP\App\IAppManager;
use OCP\IConfig;
use OCP\Migration\IRuntimeRepairStep;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -46,15 +48,18 @@ class Repair extends Command {
private $progress;
/** @var OutputInterface */
private $output;
/** @var IAppManager */
private $appManager;

/**
* @param \OC\Repair $repair
* @param IConfig $config
*/
public function __construct(\OC\Repair $repair, IConfig $config, EventDispatcherInterface $dispatcher) {
public function __construct(\OC\Repair $repair, IConfig $config, EventDispatcherInterface $dispatcher, IAppManager $appManager) {
$this->repair = $repair;
$this->config = $config;
$this->dispatcher = $dispatcher;
$this->appManager = $appManager;
parent::__construct();
}

Expand All @@ -66,39 +71,27 @@ protected function configure() {
'include-expensive',
null,
InputOption::VALUE_NONE,
'Use this option when you want to include resource and load expensive tasks.')
->addOption(
'runtime',
null,
InputOption::VALUE_NONE,
'Use this option when you want to include resource and load expensive tasks.');
}

protected function execute(InputInterface $input, OutputInterface $output) {
$includeExpensive = $input->getOption('include-expensive');
if ($includeExpensive) {
foreach ($this->repair->getExpensiveRepairSteps() as $step) {
$this->repair->addStep($step);
}
}
$this->output = $output;

$apps = \OC::$server->getAppManager()->getInstalledApps();
foreach ($apps as $app) {
if (!\OC_App::isEnabled($app)) {
continue;
}
$info = \OC_App::getAppInfo($app);
if (!\is_array($info)) {
continue;
}
\OC_App::loadApp($app);
$steps = $info['repair-steps']['post-migration'];
foreach ($steps as $step) {
try {
$this->repair->addStep($step);
} catch (Exception $ex) {
$output->writeln("<error>Failed to load repair step for $app: {$ex->getMessage()}</error>");
}
}
}
$includeExpensive = $input->getOption('include-expensive');
$runtime = $input->getOption('runtime');
$this->buildRepairList($includeExpensive, $runtime, $this->repair);

// If not runtime mode, we need maintenance mode
$maintenanceMode = $this->config->getSystemValue('maintenance', false);
$this->config->setSystemValue('maintenance', true);
if (!$runtime) {
$this->output->writeln('<info>Enabling maintenance mode...');
$this->config->setSystemValue('maintenance', true);
}

$this->progress = new ProgressBar($output);
$this->output = $output;
Expand All @@ -112,7 +105,50 @@ protected function execute(InputInterface $input, OutputInterface $output) {

$this->repair->run();

$this->config->setSystemValue('maintenance', $maintenanceMode);
if (!$runtime) {
$this->output->writeln('<info>Resetting maintenance mode...');
$this->config->setSystemValue('maintenance', $maintenanceMode);
}
}

public function buildRepairList($includeExpensive, $runtimeSteps, \OC\Repair $repair) {
$repair->clearSteps();
$steps = [];
$steps = array_merge($steps, \OC\Repair::getRepairSteps());
if ($includeExpensive) {
$steps = array_merge($steps, $repair->getExpensiveRepairSteps());
}
$apps = $this->appManager->getInstalledApps();
foreach ($apps as $app) {
if (!$this->appManager->isEnabledForUser($app)) {
continue;
}
$info = $this->appManager->getAppInfo($app);
if (!\is_array($info)) {
continue;
}
\OC_App::loadApp($app);
$appSteps = $info['repair-steps']['post-migration'];
foreach ($appSteps as $step) {
$steps[] = $step;
}
}
// Add to repair lib
foreach ($steps as $step) {
if (\is_string($step)) {
$step = \OC::$server->query($step);
}
// Skip step if runtime only and this one isnt
if ($runtimeSteps && !$step instanceof IRuntimeRepairStep) {
continue;
}
try {
$repair->addStep($step);
} catch (\Exception $e) {
$stepName = get_class($step);
$this->output->writeln("<error>Problem loading repair step: $stepName</error>");
}
}
}

public function handleRepairFeedBack($event) {
Expand Down
7 changes: 7 additions & 0 deletions lib/private/Repair.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ public function run() {
}
}

/**
* Clears the list of steps to run
*/
public function clearSteps() {
$this->repairSteps = [];
}

/**
* Add repair step
*
Expand Down
4 changes: 2 additions & 2 deletions lib/private/Repair/MoveAvatarOutsideHome.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@
use OCP\ILogger;
use OCP\IUserManager;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
use OCP\IUser;
use OC\Avatar;
use OCP\IConfig;
use OCP\IAvatarManager;
use OCP\Files\NotFoundException;
use OCP\Migration\IRuntimeRepairStep;

/**
* Move avatars outside of their homes to the new location
*
* @package OC\Repair
*/
class MoveAvatarOutsideHome implements IRepairStep {
class MoveAvatarOutsideHome implements IRuntimeRepairStep {
/** @var \OCP\IConfig */
protected $config;

Expand Down
25 changes: 25 additions & 0 deletions lib/public/Migration/IRuntimeRepairStep.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
/**
* @author Tom Needham <tom@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @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 <http://www.gnu.org/licenses/>
*
*/
namespace OCP\Migration;

interface IRuntimeRepairStep extends IRepairStep {

}
80 changes: 80 additions & 0 deletions tests/lib/Command/Maintenance/RepairTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php
/**
* @author Tom Needham <tom@owncloud.com>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @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 <http://www.gnu.org/licenses/>
*
*/

namespace Test\Command\Maintenance;

use OC\Core\Command\Maintenance\Repair;
use OCP\App\IAppManager;
use OCP\IConfig;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Test\TestCase;

/**
* Class RepairTest
*
* @package Test\Command\Maintenance
* @group DB
*/
class RepairTest extends TestCase {

/** @var \OC\Repair */
protected $repair;
/** @var Repair */
protected $command;
/** @var IConfig */
protected $config;
/** @var EventDispatcherInterface */
protected $dispatcher;
/** @var IAppManager */
protected $appManager;

public function setUp() {
parent::setUp();
$this->repair = $this->createMock(\OC\Repair::class);
$this->config = $this->createMock(IConfig::class);
$this->dispatcher = $this->createMock(EventDispatcherInterface::class);
$this->appManager = $this->createMock(IAppManager::class);
$this->command = new Repair($this->repair, $this->config, $this->dispatcher, $this->appManager);
}

/**
* @dataProvider buildStepsData
* @param $expensiveSteps
* @param $runtimeSteps
* @param $expensive
* @param $runtimeMode
* @param $expected
*/
public function testBuildSteps($expensiveSteps, $runtimeSteps, $expensive, $runtimeMode, $expectedCount) {
$this->appManager->method('getInstalledApps')->willReturn([]);
$this->repair->expects($this->exactly($expectedCount))->method('addStep');
$this->command->buildRepairList($expensive, $runtimeMode, $this->repair);
//$this->assertSame($expected, $this->command->buildRepairList($expected, $runtimeMode, $this->repair));
//$this->assertAttributeEquals($expected, '$repairSteps', )
}

public function buildStepsData() {
return [
[[], [], false, false, []]
];
}

}

0 comments on commit 25921a0

Please sign in to comment.