Skip to content

Commit

Permalink
[stable10] Don't enable market app on upgrade from 9.1.x or lower whe…
Browse files Browse the repository at this point in the history
…n app store was disabled in the past - fixes owncloud/market#118

Disable market app if 'appstoreenabled' was set to false in config

Handle 'has_internet_connection' and cleanup of market app handling
  • Loading branch information
DeepDiver1975 committed Aug 21, 2017
1 parent d4b137d commit 0494dcd
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 71 deletions.
2 changes: 1 addition & 1 deletion lib/private/Repair.php
Expand Up @@ -179,7 +179,7 @@ public static function getBeforeUpgradeRepairSteps() {
new Collation(\OC::$server->getConfig(), $connection),
new SqliteAutoincrement($connection),
new SearchLuceneTables(),
new Apps(\OC::$server->getAppManager(), \OC::$server->getEventDispatcher(), \OC::$server->getConfig()),
new Apps(\OC::$server->getAppManager(), \OC::$server->getEventDispatcher(), \OC::$server->getConfig(), new \OC_Defaults()),
];

//There is no need to delete all previews on every single update
Expand Down
155 changes: 100 additions & 55 deletions lib/private/Repair/Apps.php
Expand Up @@ -51,15 +51,22 @@ class Apps implements IRepairStep {
/** @var IConfig */
private $config;

/** @var \OC_Defaults */
private $defaults;

/**
* Apps constructor.
*
* @param IAppManager $appManager
* @param EventDispatcher $eventDispatcher
* @param IConfig $config
* @param \OC_Defaults $defaults
*/
public function __construct(IAppManager $appManager, EventDispatcher $eventDispatcher, IConfig $config) {
public function __construct(IAppManager $appManager, EventDispatcher $eventDispatcher, IConfig $config, \OC_Defaults $defaults) {
$this->appManager = $appManager;
$this->eventDispatcher = $eventDispatcher;
$this->config = $config;
$this->defaults = $defaults;
}

/**
Expand All @@ -75,7 +82,7 @@ public function getName() {
*/
private function isCoreUpdate() {
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
$currentVersion = implode('.', \OCP\Util::getVersion());
$currentVersion = implode('.', Util::getVersion());
$versionDiff = version_compare($currentVersion, $installedVersion);
if ($versionDiff > 0) {
return true;
Expand All @@ -90,78 +97,78 @@ private function isCoreUpdate() {
private function requiresMarketEnable() {
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
$versionDiff = version_compare('10.0.0', $installedVersion);
if ($versionDiff >= 0) {
return true;
if ($versionDiff < 0) {
return false;
}
return false;
return true;

}

/**
* @param IOutput $output
* @throws RepairException
*/
public function run(IOutput $output) {
$isCoreUpdate = $this->isCoreUpdate();

if ($this->config->getSystemValue('has_internet_connection', true) !== true) {
$link = $this->defaults->buildDocLinkToKey('admin-marketplace-apps');
$output->info('No internet connection available - no app updates will be taken from the marketplace.');
$output->info("How to update apps in such situation please see $link");
return;
}
$appsToUpgrade = $this->getAppsToUpgrade();
$failedCompatibleApps = [];
$failedMissingApps = $appsToUpgrade[self::KEY_MISSING];
$failedIncompatibleApps = $appsToUpgrade[self::KEY_INCOMPATIBLE];
$hasNotUpdatedCompatibleApps = 0;
$requiresMarketEnable = $this->requiresMarketEnable();

if($isCoreUpdate && $requiresMarketEnable) {
// Then we need to enable the market app to support app updates / downloads during upgrade
$output->info('Enabling market app to assist with update');
// delete old value that might influence old APIs
if ($this->config->getSystemValue('appstoreenabled', null) !== null) {
$this->config->deleteSystemValue('appstoreenabled');
}
$this->appManager->enableApp('market');
}
// fix market app state
$shallContactMarketplace = $this->fixMarketAppState($output);
if ($shallContactMarketplace) {
// Check if we can use the marketplace to update apps as needed?
if ($this->appManager->isEnabledForUser('market')) {
// Use market to fix missing / old apps
$this->loadApp('market');
$output->info('Using market to update existing apps');
try {
// Try to update incompatible apps
if (!empty($appsToUpgrade[self::KEY_INCOMPATIBLE])) {
$output->info('Attempting to update the following existing but incompatible app from market: ' . implode(', ', $appsToUpgrade[self::KEY_INCOMPATIBLE]));
$failedIncompatibleApps = $this->getAppsFromMarket(
$output,
$appsToUpgrade[self::KEY_INCOMPATIBLE],
'upgradeAppStoreApp'
);
}

// Check if we can use the marketplace to update apps as needed?
if($this->appManager->isEnabledForUser('market')) {
// Use market to fix missing / old apps
$this->loadApp('market');
$output->info('Using market to update existing apps');
try {
// Try to update incompatible apps
if(!empty($appsToUpgrade[self::KEY_INCOMPATIBLE])) {
$output->info('Attempting to update the following existing but incompatible app from market: '.implode(', ', $appsToUpgrade[self::KEY_INCOMPATIBLE]));
$failedIncompatibleApps = $this->getAppsFromMarket(
$output,
$appsToUpgrade[self::KEY_INCOMPATIBLE],
'upgradeAppStoreApp'
);
}
// Try to download missing apps
if (!empty($appsToUpgrade[self::KEY_MISSING])) {
$output->info('Attempting to update the following missing apps from market: ' . implode(', ', $appsToUpgrade[self::KEY_MISSING]));
$failedMissingApps = $this->getAppsFromMarket(
$output,
$appsToUpgrade[self::KEY_MISSING],
'reinstallAppStoreApp'
);
}

// Try to download missing apps
if(!empty($appsToUpgrade[self::KEY_MISSING])) {
$output->info('Attempting to update the following missing apps from market: '.implode(', ', $appsToUpgrade[self::KEY_MISSING]));
$failedMissingApps = $this->getAppsFromMarket(
$output,
$appsToUpgrade[self::KEY_MISSING],
'reinstallAppStoreApp'
);
}
// Try to update compatible apps
if (!empty($appsToUpgrade[self::KEY_COMPATIBLE])) {
$output->info('Attempting to update the following existing compatible apps from market: ' . implode(', ', $appsToUpgrade[self::KEY_MISSING]));
$failedCompatibleApps = $this->getAppsFromMarket(
$output,
$appsToUpgrade[self::KEY_COMPATIBLE],
'upgradeAppStoreApp'
);
}

// Try to update compatible apps
if(!empty($appsToUpgrade[self::KEY_COMPATIBLE])) {
$output->info('Attempting to update the following existing compatible apps from market: '.implode(', ', $appsToUpgrade[self::KEY_MISSING]));
$failedCompatibleApps = $this->getAppsFromMarket(
$output,
$appsToUpgrade[self::KEY_COMPATIBLE],
'upgradeAppStoreApp'
);
$hasNotUpdatedCompatibleApps = count($failedCompatibleApps);
} catch (AppManagerException $e) {
$output->warning('No connection to marketplace: ' . $e->getPrevious());
}

$hasNotUpdatedCompatibleApps = count($failedCompatibleApps);
} catch (AppManagerException $e) {
$output->warning('No connection to marketplace: ' . $e->getPrevious());
} else {
// No market available, output error and continue attempt
$output->warning('Market app is unavailable for updating of apps. Enable with: occ app:enable market');
}
} else {
// No market available, output error and continue attempt
$output->warning('Market app is unavailable for updating of apps. Enable with: occ app:enable market');
}

$hasBlockingMissingApps = count($failedMissingApps);
Expand Down Expand Up @@ -190,6 +197,7 @@ public function run(IOutput $output) {
*
* @param IOutput $output
* @param string[] $appList
* @param string $event
* @return array
* @throws AppManagerException
*/
Expand Down Expand Up @@ -274,4 +282,41 @@ function ($appId) {
protected function loadApp($app) {
OC_App::loadApp($app, false);
}

/**
* @return bool
*/
private function isAppStoreEnabled() {
// if appstoreenabled was explicitly disabled we shall not use the market app for upgrade
$appStoreEnabled = $this->config->getSystemValue('appstoreenabled', null);
if ($appStoreEnabled === false) {
return false;
}
return true;
}

private function fixMarketAppState(IOutput $output) {
// no core update -> nothing to do
if (!$this->isCoreUpdate()) {
return false;
}

// no update from a version before 10.0 -> nothing to do, but allow apps to be updated
if (!$this->requiresMarketEnable()) {
return true;
}
// if the appstore was explicitly disabled -> disable market app as well
if (!$this->isAppStoreEnabled()) {
$this->appManager->disableApp('market');
$link = $this->defaults->buildDocLinkToKey('admin-marketplace-apps');
$output->info('Appstore was disabled in past versions and marketplace interactions are disabled for now as well.');
$output->info('If you would like to get automated app updates on upgrade please enable the market app and remove "appstoreenabled" from your config.');
$output->info("Please note that the market app is not recommended for clustered setups - see $link");
return false;
}
// Then we need to enable the market app to support app updates / downloads during upgrade
$output->info('Enabling market app to assist with update');
$this->appManager->enableApp('market');
return true;
}
}
34 changes: 19 additions & 15 deletions tests/lib/Repair/AppsTest.php
Expand Up @@ -19,53 +19,57 @@
*
*/
namespace Test\Repair;
use OC\Repair\Apps;
use OCP\App\IAppManager;
use OCP\IConfig;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Test\TestCase;

/**
* Tests to check version comparison
*
* @see \OC\Repair\AppsTest
*/
class AppsTest extends \Test\TestCase {
class AppsTest extends TestCase {

/** @var \OC\Repair\AvatarPermissions */
/** @var Apps */
protected $repair;

/** @var IAppManager */
/** @var IAppManager | \PHPUnit_Framework_MockObject_MockObject */
protected $appManager;
/** @var EventDispatcher */
/** @var EventDispatcher | \PHPUnit_Framework_MockObject_MockObject */
protected $eventDispatcher;
/** @var IConfig */
/** @var IConfig | \PHPUnit_Framework_MockObject_MockObject*/
protected $config;
/** @var \OC_Defaults | \PHPUnit_Framework_MockObject_MockObject */
private $defaults;

protected function setUp() {
parent::setUp();

$this->appManager = $this->getMockBuilder(IAppManager::class)->getMock();
$this->eventDispatcher = $this->getMockBuilder(EventDispatcher::class)->getMock();
$this->config = $this->getMockBuilder(IConfig::class)->getMock();
$this->repair = new \OC\Repair\Apps($this->appManager, $this->eventDispatcher, $this->config);
$this->appManager = $this->createMock(IAppManager::class);
$this->defaults = $this->createMock(\OC_Defaults::class);
$this->eventDispatcher = $this->createMock(EventDispatcher::class);
$this->config = $this->createMock(IConfig::class);
$this->repair = new Apps($this->appManager, $this->eventDispatcher, $this->config, $this->defaults);
}

public function testMarketEnableVersionCompare10() {
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->will($this->returnValue('10.0.0'));
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->willReturn('10.0.0');
$this->assertTrue($this->invokePrivate($this->repair, 'requiresMarketEnable'));
}

public function testMarketEnableVersionCompare9() {
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->will($this->returnValue('9.1.5'));
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->willReturn('9.1.5');
$this->assertTrue($this->invokePrivate($this->repair, 'requiresMarketEnable'));
}

public function testMarketEnableVersionCompareFuture() {
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->will($this->returnValue('10.0.2'));
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->willReturn('10.0.2');
$this->assertFalse($this->invokePrivate($this->repair, 'requiresMarketEnable'));
}

public function testMarketEnableVersionCompareCurrent() {
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->will($this->returnValue('10.0.1'));
$this->config->expects($this->once())->method('getSystemValue')->with('version', '0.0.0')->willReturn('10.0.1');
$this->assertFalse($this->invokePrivate($this->repair, 'requiresMarketEnable'));
}
}
}

0 comments on commit 0494dcd

Please sign in to comment.