chore: Move isAppCompatible and shouldUpgrade to the app manager

Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
pull/53895/head
Côme Chilliet 2025-07-29 16:50:00 +07:00
parent 25c2279966
commit 4abfd4871f
No known key found for this signature in database
GPG Key ID: A3E2F658B28C760A
5 changed files with 106 additions and 83 deletions

@ -568,24 +568,18 @@ class AppSettingsController extends Controller {
$appId = $this->appManager->cleanAppId($appId);
// Check if app is already downloaded
/** @var Installer $installer */
$installer = Server::get(Installer::class);
$isDownloaded = $installer->isDownloaded($appId);
if (!$isDownloaded) {
$installer->downloadApp($appId);
if (!$this->installer->isDownloaded($appId)) {
$this->installer->downloadApp($appId);
}
$installer->installApp($appId);
$this->installer->installApp($appId);
if (count($groups) > 0) {
$this->appManager->enableAppForGroups($appId, $this->getGroupList($groups));
} else {
$this->appManager->enableApp($appId);
}
if (\OC_App::shouldUpgrade($appId)) {
$updateRequired = true;
}
$updateRequired = $updateRequired || $this->appManager->isUpgradeRequired($appId);
}
return new JSONResponse(['data' => ['update_required' => $updateRequired]]);
} catch (\Throwable $e) {

@ -727,7 +727,7 @@ class AppManager implements IAppManager {
if ($appDbVersion
&& isset($appInfo['version'])
&& version_compare($appInfo['version'], $appDbVersion, '>')
&& \OC_App::isAppCompatible($version, $appInfo)
&& $this->isAppCompatible($version, $appInfo)
) {
$appsToUpgrade[] = $appInfo;
}
@ -817,7 +817,7 @@ class AppManager implements IAppManager {
$info = $this->getAppInfo($appId);
if ($info === null) {
$incompatibleApps[] = ['id' => $appId, 'name' => $appId];
} elseif (!\OC_App::isAppCompatible($version, $info)) {
} elseif (!$this->isAppCompatible($version, $info)) {
$incompatibleApps[] = $info;
}
}
@ -1023,4 +1023,75 @@ class AppManager implements IAppManager {
return true;
}
public function isUpgradeRequired(string $appId): bool {
$versions = $this->getAppInstalledVersions();
$currentVersion = $this->getAppVersion($appId);
if ($currentVersion && isset($versions[$appId])) {
$installedVersion = $versions[$appId];
if (!version_compare($currentVersion, $installedVersion, '=')) {
return true;
}
}
return false;
}
public function isAppCompatible(string $serverVersion, array $appInfo, bool $ignoreMax = false): bool {
$requireMin = '';
$requireMax = '';
if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
} elseif (isset($appInfo['requiremin'])) {
$requireMin = $appInfo['requiremin'];
} elseif (isset($appInfo['require'])) {
$requireMin = $appInfo['require'];
}
if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
} elseif (isset($appInfo['requiremax'])) {
$requireMax = $appInfo['requiremax'];
}
if (!empty($requireMin)
&& version_compare($this->adjustVersionParts($serverVersion, $requireMin), $requireMin, '<')
) {
return false;
}
if (!$ignoreMax && !empty($requireMax)
&& version_compare($this->adjustVersionParts($serverVersion, $requireMax), $requireMax, '>')
) {
return false;
}
return true;
}
/**
* Adjust the number of version parts of $version1 to match
* the number of version parts of $version2.
*
* @param string $version1 version to adjust
* @param string $version2 version to take the number of parts from
* @return string shortened $version1
*/
private function adjustVersionParts(string $version1, string $version2): string {
//FIXME Most likely this function is not needed and version_compare directly will work. Should be tested.
$version1 = explode('.', $version1);
$version2 = explode('.', $version2);
// reduce $version1 to match the number of parts in $version2
while (count($version1) > count($version2)) {
array_pop($version1);
}
// if $version1 does not have enough parts, add some
while (count($version1) < count($version2)) {
$version1[] = '0';
}
return implode('.', $version1);
}
}

@ -23,7 +23,6 @@ use OC\Repair\Events\RepairInfoEvent;
use OC\Repair\Events\RepairStartEvent;
use OC\Repair\Events\RepairStepEvent;
use OC\Repair\Events\RepairWarningEvent;
use OC_App;
use OCP\App\IAppManager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
@ -319,7 +318,7 @@ class Updater extends BasicEmitter {
foreach (array_merge($priorityTypes, [$pseudoOtherType]) as $type) {
$stack = $stacks[$type];
foreach ($stack as $appId) {
if (\OC_App::shouldUpgrade($appId)) {
if ($this->appManager->isUpgradeRequired($appId)) {
$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, $this->appManager->getAppVersion($appId)]);
$this->appManager->upgradeApp($appId);
$this->emit('\OC\Updater', 'appUpgrade', [$appId, $this->appManager->getAppVersion($appId)]);
@ -349,7 +348,7 @@ class Updater extends BasicEmitter {
foreach ($apps as $app) {
// check if the app is compatible with this version of Nextcloud
$info = $this->appManager->getAppInfo($app);
if ($info === null || !OC_App::isAppCompatible($version, $info)) {
if ($info === null || !$this->appManager->isAppCompatible($version, $info)) {
if ($this->appManager->isShipped($app)) {
throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
}
@ -359,9 +358,6 @@ class Updater extends BasicEmitter {
}
}
/**
* @return bool
*/
private function isCodeUpgrade(): bool {
$installedVersion = $this->config->getSystemValueString('version', '0.0.0');
$currentVersion = implode('.', Util::getVersion());

@ -539,37 +539,7 @@ class OC_App {
}
public static function shouldUpgrade(string $app): bool {
$versions = self::getAppVersions();
$currentVersion = Server::get(\OCP\App\IAppManager::class)->getAppVersion($app);
if ($currentVersion && isset($versions[$app])) {
$installedVersion = $versions[$app];
if (!version_compare($currentVersion, $installedVersion, '=')) {
return true;
}
}
return false;
}
/**
* Adjust the number of version parts of $version1 to match
* the number of version parts of $version2.
*
* @param string $version1 version to adjust
* @param string $version2 version to take the number of parts from
* @return string shortened $version1
*/
private static function adjustVersionParts(string $version1, string $version2): string {
$version1 = explode('.', $version1);
$version2 = explode('.', $version2);
// reduce $version1 to match the number of parts in $version2
while (count($version1) > count($version2)) {
array_pop($version1);
}
// if $version1 does not have enough parts, add some
while (count($version1) < count($version2)) {
$version1[] = '0';
}
return implode('.', $version1);
return Server::get(\OCP\App\IAppManager::class)->isUpgradeRequired($app);
}
/**
@ -586,42 +556,10 @@ class OC_App {
* @param string $ocVersion Nextcloud version to check against
* @param array $appInfo app info (from xml)
*
* @return boolean true if compatible, otherwise false
* @return bool true if compatible, otherwise false
*/
public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
$requireMin = '';
$requireMax = '';
if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
} elseif (isset($appInfo['requiremin'])) {
$requireMin = $appInfo['requiremin'];
} elseif (isset($appInfo['require'])) {
$requireMin = $appInfo['require'];
}
if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
} elseif (isset($appInfo['requiremax'])) {
$requireMax = $appInfo['requiremax'];
}
if (!empty($requireMin)
&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
) {
return false;
}
if (!$ignoreMax && !empty($requireMax)
&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
) {
return false;
}
return true;
return Server::get(\OCP\App\IAppManager::class)->isAppCompatible($ocVersion, $appInfo, $ignoreMax);
}
/**

@ -349,4 +349,28 @@ interface IAppManager {
* @since 32.0.0
*/
public function upgradeApp(string $appId): bool;
/**
* Check whether the installed version is the same as the version from info.xml
*
* @since 32.0.0
*/
public function isUpgradeRequired(string $appId): bool;
/**
* Check whether the current Nextcloud version matches the given
* application's version requirements.
*
* The comparison is made based on the number of parts that the
* app info version has. For example for Nextcloud 26.0.3 if the
* app info version is expecting version 26.0, the comparison is
* made on the first two parts of the Nextcloud version.
* This means that it's possible to specify "requiremin" => 26
* and "requiremax" => 26 and it will still match Nextcloud 26.0.3.
*
* @param string $serverVersion Nextcloud version to check against
* @param array $appInfo app info (from xml)
* @since 32.0.0
*/
public function isAppCompatible(string $serverVersion, array $appInfo, bool $ignoreMax = false): bool;
}