Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions build/psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2965,7 +2965,6 @@
</file>
<file src="core/Command/Config/ListConfigs.php">
<DeprecatedMethod>
<code><![CDATA[\OC_App::getAllApps()]]></code>
<code><![CDATA[getFilteredValues]]></code>
<code><![CDATA[getValues]]></code>
</DeprecatedMethod>
Expand All @@ -2988,26 +2987,11 @@
<code><![CDATA[getDatabasePlatform]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Db/Migrations/ExecuteCommand.php">
<DeprecatedMethod>
<code><![CDATA[\OC_App::getAllApps()]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Db/Migrations/GenerateCommand.php">
<DeprecatedMethod>
<code><![CDATA[Util::getVersion()]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Db/Migrations/MigrateCommand.php">
<DeprecatedMethod>
<code><![CDATA[\OC_App::getAllApps()]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Db/Migrations/StatusCommand.php">
<DeprecatedMethod>
<code><![CDATA[\OC_App::getAllApps()]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Encryption/ChangeKeyStorageRoot.php">
<DeprecatedClass>
<code><![CDATA[\OC_Util::setupFS($uid)]]></code>
Expand Down
4 changes: 3 additions & 1 deletion core/Command/App/Disable.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ public function completeOptionValues($optionName, CompletionContext $context): a
#[\Override]
public function completeArgumentValues($argumentName, CompletionContext $context): array {
if ($argumentName === 'app-id') {
return array_diff(\OC_App::getEnabledApps(true, true), $this->appManager->getAlwaysEnabledApps());
$enabledApps = $this->appManager->getEnabledApps();
$coreApps = $this->appManager->getAlwaysEnabledApps();
return array_diff($enabledApps, $coreApps);
}
return [];
}
Expand Down
3 changes: 2 additions & 1 deletion core/Command/App/Enable.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ public function completeOptionValues($optionName, CompletionContext $context): a
public function completeArgumentValues($argumentName, CompletionContext $context): array {
if ($argumentName === 'app-id') {
$allApps = $this->appManager->getAllAppsInAppsFolders();
return array_diff($allApps, \OC_App::getEnabledApps(true, true));
$enabledApps = $this->appManager->getEnabledApps();
return array_diff($allApps, $enabledApps);
}
return [];
}
Expand Down
4 changes: 3 additions & 1 deletion core/Command/Config/ListConfigs.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OC\Config\ConfigManager;
use OC\Core\Command\Base;
use OC\SystemConfig;
use OCP\App\IAppManager;
use OCP\IAppConfig;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -24,6 +25,7 @@ public function __construct(
protected SystemConfig $systemConfig,
protected IAppConfig $appConfig,
protected ConfigManager $configManager,
protected IAppManager $appManager,
) {
parent::__construct();
}
Expand Down Expand Up @@ -141,7 +143,7 @@ protected function getAppConfigs(string $app, bool $noSensitiveValues) {
#[\Override]
public function completeArgumentValues($argumentName, CompletionContext $context) {
if ($argumentName === 'app') {
return array_merge(['all', 'system'], \OC_App::getAllApps());
return array_merge(['all', 'system'], $this->appManager->getAllAppsInAppsFolders());
}
return [];
}
Expand Down
4 changes: 3 additions & 1 deletion core/Command/Db/ExpectedSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use OC\DB\MigrationService;
use OC\DB\SchemaWrapper;
use OC\Migration\NullOutput;
use OCP\App\IAppManager;
use Override;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -23,6 +24,7 @@
class ExpectedSchema extends Base {
public function __construct(
protected readonly Connection $connection,
protected readonly IAppManager $appManager,
) {
parent::__construct();
}
Expand All @@ -45,7 +47,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$this->applyMigrations('core', $schema);

$apps = \OC_App::getEnabledApps();
$apps = $this->appManager->getEnabledApps();
foreach ($apps as $app) {
$this->applyMigrations($app, $schema);
}
Expand Down
6 changes: 4 additions & 2 deletions core/Command/Db/Migrations/ExecuteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OC\DB\Connection;
use OC\DB\MigrationService;
use OC\Migration\ConsoleOutput;
use OCP\App\IAppManager;
use OCP\IConfig;
use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
Expand All @@ -22,6 +23,7 @@ class ExecuteCommand extends Command implements CompletionAwareInterface {
public function __construct(
private Connection $connection,
private IConfig $config,
private IAppManager $appManager,
) {
parent::__construct();
}
Expand Down Expand Up @@ -81,8 +83,8 @@ public function completeOptionValues($optionName, CompletionContext $context) {
#[\Override]
public function completeArgumentValues($argumentName, CompletionContext $context) {
if ($argumentName === 'app') {
$allApps = \OC_App::getAllApps();
return array_diff($allApps, \OC_App::getEnabledApps(true, true));
$allApps = $this->appManager->getAllAppsInAppsFolders();
return array_diff($allApps, $this->appManager->getEnabledApps());
}

if ($argumentName === 'version') {
Expand Down
3 changes: 2 additions & 1 deletion core/Command/Db/Migrations/GenerateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ public function completeOptionValues($optionName, CompletionContext $context) {
public function completeArgumentValues($argumentName, CompletionContext $context) {
if ($argumentName === 'app') {
$allApps = $this->appManager->getAllAppsInAppsFolders();
return array_diff($allApps, \OC_App::getEnabledApps(true, true));
$enabledApps = $this->appManager->getEnabledApps();
return array_diff($allApps, $enabledApps);
}

if ($argumentName === 'version') {
Expand Down
6 changes: 4 additions & 2 deletions core/Command/Db/Migrations/MigrateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OC\DB\Connection;
use OC\DB\MigrationService;
use OC\Migration\ConsoleOutput;
use OCP\App\IAppManager;
use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
use Symfony\Component\Console\Command\Command;
Expand All @@ -20,6 +21,7 @@
class MigrateCommand extends Command implements CompletionAwareInterface {
public function __construct(
private Connection $connection,
private IAppManager $appManager,
) {
parent::__construct();
}
Expand Down Expand Up @@ -63,8 +65,8 @@ public function completeOptionValues($optionName, CompletionContext $context) {
#[\Override]
public function completeArgumentValues($argumentName, CompletionContext $context) {
if ($argumentName === 'app') {
$allApps = \OC_App::getAllApps();
return array_diff($allApps, \OC_App::getEnabledApps(true, true));
$allApps = $this->appManager->getAllAppsInAppsFolders();
return array_diff($allApps, $this->appManager->getEnabledApps());
}

if ($argumentName === 'version') {
Expand Down
6 changes: 4 additions & 2 deletions core/Command/Db/Migrations/StatusCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OC\DB\Connection;
use OC\DB\MigrationService;
use OC\Migration\ConsoleOutput;
use OCP\App\IAppManager;
use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
use Symfony\Component\Console\Command\Command;
Expand All @@ -20,6 +21,7 @@
class StatusCommand extends Command implements CompletionAwareInterface {
public function __construct(
private Connection $connection,
private IAppManager $appManager,
) {
parent::__construct();
}
Expand Down Expand Up @@ -69,8 +71,8 @@ public function completeOptionValues($optionName, CompletionContext $context) {
#[\Override]
public function completeArgumentValues($argumentName, CompletionContext $context) {
if ($argumentName === 'app') {
$allApps = \OC_App::getAllApps();
return array_diff($allApps, \OC_App::getEnabledApps(true, true));
$allApps = $this->appManager->getAllAppsInAppsFolders();
return array_diff($allApps, $this->appManager->getEnabledApps());
}
return [];
}
Expand Down
103 changes: 73 additions & 30 deletions lib/private/App/AppManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
use OC\Config\ConfigManager;
use OC\DB\MigrationService;
use OC\Migration\BackgroundRepair;
use OC\NeedsUpdateException;
use OC\Repair;
use OC\Repair\Events\RepairErrorEvent;
use OCP\Activity\IManager as IActivityManager;
use OCP\App\AppPathNotFoundException;
use OCP\App\Events\AppDisableEvent;
Expand Down Expand Up @@ -147,6 +150,10 @@ private function getUrlGenerator(): IURLGenerator {
* @return array<string,string> appId => enabled (may be 'yes', or a json encoded list of group ids)
*/
private function getEnabledAppsValues(): array {
if ($this->config->getSystemValueBool('installed', false) === false) {
return [];
}

if (!$this->enabledAppsCache) {
/** @var array<string,string> */
$values = $this->getAppConfig()->searchValues('enabled', false, IAppConfig::VALUE_STRING);
Expand Down Expand Up @@ -240,25 +247,18 @@ public function getEnabledAppsForGroup(IGroup $group): array {
return array_keys($appsForGroups);
}

/**
* Loads all apps
*
* @param string[] $types
* @return bool
*
* This function walks through the Nextcloud directory and loads all apps
* it can find. A directory contains an app if the file /appinfo/info.xml
* exists.
*
* if $types is set to non-empty array, only apps of those types will be loaded
*/
#[\Override]
public function loadApps(array $types = []): bool {
if ($this->config->getSystemValueBool('maintenance', false)) {
return false;
}
if ($this->config->getSystemValueBool('installed', false) === false) {
// can only access the apps folder after installation, so we can't load any apps before that
return false;
}

// Load the enabled apps here
$apps = \OC_App::getEnabledApps();
$apps = $this->getEnabledApps();

// Add each apps' folder as allowed class path
foreach ($apps as $app) {
Expand Down Expand Up @@ -708,7 +708,7 @@ public function disableApp($appId, $automaticDisabled = false): void {
// run uninstall steps
$appData = $this->getAppInfo($appId);
if (!is_null($appData)) {
\OC_App::executeRepairSteps($appId, $appData['repair-steps']['uninstall']);
$this->executeRepairSteps($appId, $appData['repair-steps']['uninstall']);
}

$this->dispatcher->dispatchTyped(new AppDisableEvent($appId));
Expand Down Expand Up @@ -1109,30 +1109,24 @@ public function upgradeApp(string $appId): bool {
$appPath = $this->getAppPath($appId, true);

$this->clearAppsCache();
$l = \OC::$server->getL10N('core');
$appData = $this->getAppInfo($appId, false, $l->getLanguageCode());
if ($appData === null) {
$appInfo = $this->getAppInfo($appId);
if ($appInfo === null) {
throw new AppPathNotFoundException('Could not find ' . $appId);
}

$ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []);
$ignoreMax = in_array($appId, $ignoreMaxApps, true);
\OC_App::checkAppDependencies(
$this->config,
$l,
$appData,
$ignoreMax
);
$this->checkAppDependencies($appId, $ignoreMax);

\OC_App::registerAutoloading($appId, $appPath, true);
\OC_App::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
$this->executeRepairSteps($appId, $appInfo['repair-steps']['pre-migration']);

$ms = new MigrationService($appId, Server::get(\OC\DB\Connection::class));
$ms->migrate();

\OC_App::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
$this->executeRepairSteps($appId, $appInfo['repair-steps']['post-migration']);
$queue = Server::get(IJobList::class);
foreach ($appData['repair-steps']['live-migration'] as $step) {
foreach ($appInfo['repair-steps']['live-migration'] as $step) {
$queue->add(BackgroundRepair::class, [
'app' => $appId,
'step' => $step]);
Expand All @@ -1143,19 +1137,19 @@ public function upgradeApp(string $appId): bool {
$this->getAppVersion($appId, false);

// Setup background jobs
foreach ($appData['background-jobs'] as $job) {
foreach ($appInfo['background-jobs'] as $job) {
$queue->add($job);
}

//set remote/public handlers
foreach ($appData['remote'] as $name => $path) {
foreach ($appInfo['remote'] as $name => $path) {
$this->config->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
}
foreach ($appData['public'] as $name => $path) {
foreach ($appInfo['public'] as $name => $path) {
$this->config->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
}

$this->setAppTypes($appId, $appData);
$this->setAppTypes($appId, $appInfo);

$version = $this->getAppVersion($appId);
$this->config->setAppValue($appId, 'installed_version', $version);
Expand Down Expand Up @@ -1197,4 +1191,53 @@ public function isUpgradeRequired(string $appId): bool {
public function isAppCompatible(string $serverVersion, array $appInfo, bool $ignoreMax = false): bool {
return count($this->dependencyAnalyzer->analyzeServerVersion($serverVersion, $appInfo, $ignoreMax)) === 0;
}

/**
* Check if all dependencies of an app are satisfied.
*
* @param string $appId - The app to check
* @param bool $ignoreMax - Whether to ignore the Nextcloud max version requirement
* @throws \Exception - If there are missing dependencies
*/
public function checkAppDependencies(string $appId, bool $ignoreMax = false): void {
$info = $this->getAppInfo($appId);
$missing = $this->dependencyAnalyzer->analyze($info, $ignoreMax);
if (!empty($missing)) {
$l = \OCP\Server::get(\OCP\L10N\IFactory::class)->get('core');
$missingMsg = implode(PHP_EOL, $missing);
throw new \Exception(
$l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
[$info['name'], $missingMsg]
)
);
}
}

/**
* Run repair steps for an app.
*
* @param string $appId - The app to run the repair steps for
* @param string[] $steps - The repair steps to run
* @throws NeedsUpdateException
*/
public function executeRepairSteps(string $appId, array $steps): void {
if (empty($steps)) {
return;
}

$this->loadApp($appId);

// load the steps
$r = Server::get(Repair::class);
foreach ($steps as $step) {
try {
$r->addStep($step);
} catch (\Exception $ex) {
$this->dispatcher->dispatchTyped(new RepairErrorEvent($ex->getMessage()));
$this->logger->error('Failed to add app migration step ' . $step, ['exception' => $ex]);
}
}
// run the steps
$r->run();
}
}
5 changes: 2 additions & 3 deletions lib/private/AppFramework/Bootstrap/Coordinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@ public function __construct(
}

public function runInitialRegistration(): void {
$apps = OC_App::getEnabledApps();
if (!empty($apps)) {
// make sure to also register the core app
$apps = $this->appManager->getEnabledApps();
if ($apps !== []) {
$apps = ['core', ...$apps];
}

Expand Down
Loading
Loading