From: Côme Chilliet Date: Tue, 7 Feb 2023 15:56:04 +0000 (+0100) Subject: Move loadApp function to the AppManager X-Git-Tag: v27.0.0beta1~310^2~7 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a7c8090dc3c47c79ed9e7e22967cba7d124f0fa7;p=nextcloud-server.git Move loadApp function to the AppManager Signed-off-by: Côme Chilliet --- diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 0a89711f178..0b0bcecb5dc 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -39,6 +39,8 @@ namespace OC\App; use OC\AppConfig; +use OC\AppFramework\Bootstrap\Coordinator; +use OC\ServerNotAvailableException; use OCP\App\AppPathNotFoundException; use OCP\App\Events\AppDisableEvent; use OCP\App\Events\AppEnableEvent; @@ -51,6 +53,7 @@ use OCP\IGroup; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserSession; +use OCP\Settings\IManager as ISettingsManager; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -108,6 +111,9 @@ class AppManager implements IAppManager { /** @var array */ private $autoDisabledApps = []; + /** @var array */ + private array $loadedApps = []; + public function __construct(IUserSession $userSession, IConfig $config, AppConfig $appConfig, @@ -310,6 +316,139 @@ class AppManager implements IAppManager { } } + public function loadApp(string $app): void { + if (isset($this->loadedApps[$app])) { + return; + } + $this->loadedApps[$app] = true; + $appPath = \OC_App::getAppPath($app); + if ($appPath === false) { + return; + } + $eventLogger = \OC::$server->get(\OCP\Diagnostics\IEventLogger::class); + $eventLogger->start("bootstrap:load_app:$app", "Load $app"); + + // in case someone calls loadApp() directly + \OC_App::registerAutoloading($app, $appPath); + + /** @var Coordinator $coordinator */ + $coordinator = \OC::$server->get(Coordinator::class); + $isBootable = $coordinator->isBootable($app); + + $hasAppPhpFile = is_file($appPath . '/appinfo/app.php'); + + if ($isBootable && $hasAppPhpFile) { + \OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [ + 'app' => $app, + ]); + } elseif ($hasAppPhpFile) { + $eventLogger->start("bootstrap:load_app:$app:app.php", "Load legacy app.php app $app"); + \OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [ + 'app' => $app, + ]); + try { + self::requireAppFile($appPath); + } catch (\Throwable $ex) { + if ($ex instanceof ServerNotAvailableException) { + throw $ex; + } + if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) { + \OC::$server->getLogger()->logException($ex, [ + 'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(), + ]); + + // Only disable apps which are not shipped and that are not authentication apps + \OC::$server->getAppManager()->disableApp($app, true); + } else { + \OC::$server->getLogger()->logException($ex, [ + 'message' => "App $app threw an error during app.php load: " . $ex->getMessage(), + ]); + } + } + $eventLogger->end("bootstrap:load_app:$app:app.php"); + } + + $coordinator->bootApp($app); + + $eventLogger->start("bootstrap:load_app:$app:info", "Load info.xml for $app and register any services defined in it"); + $info = self::getAppInfo($app); + if (!empty($info['activity']['filters'])) { + foreach ($info['activity']['filters'] as $filter) { + \OC::$server->getActivityManager()->registerFilter($filter); + } + } + if (!empty($info['activity']['settings'])) { + foreach ($info['activity']['settings'] as $setting) { + \OC::$server->getActivityManager()->registerSetting($setting); + } + } + if (!empty($info['activity']['providers'])) { + foreach ($info['activity']['providers'] as $provider) { + \OC::$server->getActivityManager()->registerProvider($provider); + } + } + + if (!empty($info['settings']['admin'])) { + foreach ($info['settings']['admin'] as $setting) { + \OC::$server->get(ISettingsManager::class)->registerSetting('admin', $setting); + } + } + if (!empty($info['settings']['admin-section'])) { + foreach ($info['settings']['admin-section'] as $section) { + \OC::$server->get(ISettingsManager::class)->registerSection('admin', $section); + } + } + if (!empty($info['settings']['personal'])) { + foreach ($info['settings']['personal'] as $setting) { + \OC::$server->get(ISettingsManager::class)->registerSetting('personal', $setting); + } + } + if (!empty($info['settings']['personal-section'])) { + foreach ($info['settings']['personal-section'] as $section) { + \OC::$server->get(ISettingsManager::class)->registerSection('personal', $section); + } + } + + if (!empty($info['collaboration']['plugins'])) { + // deal with one or many plugin entries + $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ? + [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin']; + foreach ($plugins as $plugin) { + if ($plugin['@attributes']['type'] === 'collaborator-search') { + $pluginInfo = [ + 'shareType' => $plugin['@attributes']['share-type'], + 'class' => $plugin['@value'], + ]; + \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo); + } elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') { + \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']); + } + } + } + $eventLogger->end("bootstrap:load_app:$app:info"); + + $eventLogger->end("bootstrap:load_app:$app"); + } + /** + * Check if an app is loaded + * @param string $app app id + * @since 26.0.0 + */ + public function isAppLoaded(string $app): bool { + return isset($this->loadedApps[$app]); + } + + /** + * Load app.php from the given app + * + * @param string $app app name + * @throws \Error + */ + private static function requireAppFile(string $app): void { + // encapsulated here to avoid variable scope conflicts + require_once $app . '/appinfo/app.php'; + } + /** * Enable an app for every user * diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index 3c255e91661..01bce057881 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -53,11 +53,11 @@ declare(strict_types=1); use OCP\App\Events\AppUpdateEvent; use OCP\AppFramework\QueryException; +use OCP\App\IAppManager; use OCP\App\ManagerEvent; use OCP\Authentication\IAlternativeLogin; use OCP\EventDispatcher\IEventDispatcher; use OCP\ILogger; -use OCP\Settings\IManager as ISettingsManager; use OC\AppFramework\Bootstrap\Coordinator; use OC\App\DependencyAnalyzer; use OC\App\Platform; @@ -65,7 +65,6 @@ use OC\DB\MigrationService; use OC\Installer; use OC\Repair; use OC\Repair\Events\RepairErrorEvent; -use OC\ServerNotAvailableException; use Psr\Log\LoggerInterface; /** @@ -77,7 +76,6 @@ class OC_App { private static $adminForms = []; private static $personalForms = []; private static $appTypes = []; - private static $loadedApps = []; private static $altLogin = []; private static $alreadyRegistered = []; public const supportedApp = 300; @@ -103,7 +101,7 @@ class OC_App { * @return bool */ public static function isAppLoaded(string $app): bool { - return isset(self::$loadedApps[$app]); + return \OC::$server->get(IAppManager::class)->isAppLoaded($app); } /** @@ -128,7 +126,7 @@ class OC_App { // Add each apps' folder as allowed class path foreach ($apps as $app) { // If the app is already loaded then autoloading it makes no sense - if (!isset(self::$loadedApps[$app])) { + if (!self::isAppLoaded($app)) { $path = self::getAppPath($app); if ($path !== false) { self::registerAutoloading($app, $path); @@ -139,7 +137,7 @@ class OC_App { // prevent app.php from printing output ob_start(); foreach ($apps as $app) { - if (!isset(self::$loadedApps[$app]) && ($types === [] || self::isType($app, $types))) { + if (!self::isAppLoaded($app) && ($types === [] || self::isType($app, $types))) { try { self::loadApp($app); } catch (\Throwable $e) { @@ -162,118 +160,7 @@ class OC_App { * @throws Exception */ public static function loadApp(string $app): void { - if (isset(self::$loadedApps[$app])) { - return; - } - self::$loadedApps[$app] = true; - $appPath = self::getAppPath($app); - if ($appPath === false) { - return; - } - $eventLogger = \OC::$server->get(\OCP\Diagnostics\IEventLogger::class); - $eventLogger->start("bootstrap:load_app:$app", "Load $app"); - - // in case someone calls loadApp() directly - self::registerAutoloading($app, $appPath); - - /** @var Coordinator $coordinator */ - $coordinator = \OC::$server->query(Coordinator::class); - $isBootable = $coordinator->isBootable($app); - - $hasAppPhpFile = is_file($appPath . '/appinfo/app.php'); - - if ($isBootable && $hasAppPhpFile) { - \OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [ - 'app' => $app, - ]); - } elseif ($hasAppPhpFile) { - $eventLogger->start("bootstrap:load_app:$app:app.php", "Load legacy app.php app $app"); - \OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [ - 'app' => $app, - ]); - try { - self::requireAppFile($appPath); - } catch (Throwable $ex) { - if ($ex instanceof ServerNotAvailableException) { - throw $ex; - } - if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) { - \OC::$server->getLogger()->logException($ex, [ - 'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(), - ]); - - // Only disable apps which are not shipped and that are not authentication apps - \OC::$server->getAppManager()->disableApp($app, true); - } else { - \OC::$server->getLogger()->logException($ex, [ - 'message' => "App $app threw an error during app.php load: " . $ex->getMessage(), - ]); - } - } - $eventLogger->end("bootstrap:load_app:$app:app.php"); - } - - $coordinator->bootApp($app); - - $eventLogger->start("bootstrap:load_app:$app:info", "Load info.xml for $app and register any services defined in it"); - $info = self::getAppInfo($app); - if (!empty($info['activity']['filters'])) { - foreach ($info['activity']['filters'] as $filter) { - \OC::$server->getActivityManager()->registerFilter($filter); - } - } - if (!empty($info['activity']['settings'])) { - foreach ($info['activity']['settings'] as $setting) { - \OC::$server->getActivityManager()->registerSetting($setting); - } - } - if (!empty($info['activity']['providers'])) { - foreach ($info['activity']['providers'] as $provider) { - \OC::$server->getActivityManager()->registerProvider($provider); - } - } - - if (!empty($info['settings']['admin'])) { - foreach ($info['settings']['admin'] as $setting) { - \OC::$server->get(ISettingsManager::class)->registerSetting('admin', $setting); - } - } - if (!empty($info['settings']['admin-section'])) { - foreach ($info['settings']['admin-section'] as $section) { - \OC::$server->get(ISettingsManager::class)->registerSection('admin', $section); - } - } - if (!empty($info['settings']['personal'])) { - foreach ($info['settings']['personal'] as $setting) { - \OC::$server->get(ISettingsManager::class)->registerSetting('personal', $setting); - } - } - if (!empty($info['settings']['personal-section'])) { - foreach ($info['settings']['personal-section'] as $section) { - \OC::$server->get(ISettingsManager::class)->registerSection('personal', $section); - } - } - - if (!empty($info['collaboration']['plugins'])) { - // deal with one or many plugin entries - $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ? - [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin']; - foreach ($plugins as $plugin) { - if ($plugin['@attributes']['type'] === 'collaborator-search') { - $pluginInfo = [ - 'shareType' => $plugin['@attributes']['share-type'], - 'class' => $plugin['@value'], - ]; - \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo); - } elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') { - \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']); - } - } - } - - $eventLogger->end("bootstrap:load_app:$app:info"); - - $eventLogger->end("bootstrap:load_app:$app"); + \OC::$server->get(IAppManager::class)->loadApp($app); } /** @@ -306,17 +193,6 @@ class OC_App { } } - /** - * Load app.php from the given app - * - * @param string $app app name - * @throws Error - */ - private static function requireAppFile(string $app) { - // encapsulated here to avoid variable scope conflicts - require_once $app . '/appinfo/app.php'; - } - /** * check if an app is of a specific type * diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index de36fafcdfe..51bd5845b7c 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -93,6 +93,20 @@ interface IAppManager { */ public function isDefaultEnabled(string $appId):bool; + /** + * Load an app, if not already loaded + * @param string $app app id + * @since 26.0.0 + */ + public function loadApp(string $app): void; + + /** + * Check if an app is loaded + * @param string $app app id + * @since 26.0.0 + */ + public function isAppLoaded(string $app): bool; + /** * Enable an app for every user *