diff --git a/core/Command/App/Update.php b/core/Command/App/Update.php index 8b56e9bea701f..4408c0973ce03 100644 --- a/core/Command/App/Update.php +++ b/core/Command/App/Update.php @@ -36,35 +36,35 @@ public function __construct( protected function configure(): void { $this ->setName('app:update') - ->setDescription('update an app or all apps') + ->setDescription('Update an app, or all apps, from the app store') ->addArgument( 'app-id', InputArgument::OPTIONAL, - 'update the specified app' + 'the ID of the app to update' ) ->addOption( 'all', null, InputOption::VALUE_NONE, - 'update all updatable apps' + 'update all apps that have an available update' ) ->addOption( 'showonly', null, InputOption::VALUE_NONE, - 'show update(s) without updating' + 'only list available updates, without installing them' ) ->addOption( 'showcurrent', null, InputOption::VALUE_NONE, - 'show currently installed version' + 'also show the currently installed version alongside the available update (implies --showonly)' ) ->addOption( 'allow-unstable', null, InputOption::VALUE_NONE, - 'allow updating to unstable releases' + 'allow updating to unstable (e.g. beta) releases' ) ; } @@ -73,75 +73,100 @@ protected function configure(): void { protected function execute(InputInterface $input, OutputInterface $output): int { $appStoreEnabled = $this->config->getSystemValueBool('appstoreenabled', true); if ($appStoreEnabled === false) { - $output->writeln('App store access is disabled'); + $output->writeln('App store access is disabled by the administrator; cannot check for updates'); return 1; } $internetAvailable = $this->config->getSystemValueBool('has_internet_connection', true); $isDefaultAppStore = $this->config->getSystemValueString('appstoreurl', self::APP_STORE_URL) === self::APP_STORE_URL; if ($internetAvailable === false && $isDefaultAppStore === true) { - $output->writeln('Internet connection is disabled, and therefore the default public App store is not reachable'); + $output->writeln('The default app store is configured, but Internet access is disabled, so the app store cannot be reached'); return 1; } $singleAppId = $input->getArgument('app-id'); $updateFound = false; + $checkFailed = false; $showOnly = $input->getOption('showonly') || $input->getOption('showcurrent'); if ($singleAppId) { $apps = [$singleAppId]; try { $this->manager->getAppPath($singleAppId); - } catch (AppPathNotFoundException $e) { - $output->writeln($singleAppId . ' not installed'); + } catch (AppPathNotFoundException) { + $output->writeln('App "' . $singleAppId . '" is not installed'); return 1; } } elseif ($input->getOption('all') || $showOnly) { $apps = $this->manager->getAllAppsInAppsFolders(); } else { - $output->writeln('Please specify an app to update or "--all" to update all updatable apps"'); + $output->writeln('Please specify an app ID to update, or use "--all" to update all apps'); return 1; } $return = 0; foreach ($apps as $appId) { - $newVersion = $this->installer->isUpdateAvailable($appId, $input->getOption('allow-unstable')); - if ($newVersion) { + try { + $newVersion = $this->installer->isUpdateAvailable( + $appId, + $input->getOption('allow-unstable'), + ); + } catch (\Exception $e) { + // Handles installer/app-manager failures that escape the app-store fetcher. + $this->logger->error('Failure while checking for an update of app "' . $appId . '"', [ + 'app' => 'app:update', + 'exception' => $e, + ]); + $output->writeln('App "' . $appId . '" could not be checked for updates: ' . $e->getMessage()); + $checkFailed = true; + $return = 1; + continue; + } + + if ($newVersion !== false) { $updateFound = true; - $message = $appId . ' new version available: ' . $newVersion; if ($input->getOption('showcurrent')) { - $message .= ' (current version: ' . $this->manager->getAppVersion($appId) . ')'; + $message = 'App "' . $appId . '": ' . $this->manager->getAppVersion($appId) . ' → ' . $newVersion . ' available'; + } else { + $message = 'App "' . $appId . '": update available (' . $newVersion . ')'; } $output->writeln($message); if (!$showOnly) { try { - $result = $this->installer->updateAppstoreApp($appId, $input->getOption('allow-unstable')); + $result = $this->installer->updateAppstoreApp( + $appId, + $input->getOption('allow-unstable'), + ); } catch (\Exception $e) { $this->logger->error('Failure during update of app "' . $appId . '"', [ 'app' => 'app:update', 'exception' => $e, ]); - $output->writeln('Error: ' . $e->getMessage()); - $result = false; + $output->writeln('App "' . $appId . '" could not be updated: ' . $e->getMessage()); $return = 1; + continue; } if ($result === false) { - $output->writeln($appId . ' couldn\'t be updated'); + $output->writeln('App "' . $appId . '" could not be updated'); $return = 1; } else { - $output->writeln($appId . ' updated'); + $output->writeln('App "' . $appId . '" updated successfully'); } } } } if (!$updateFound) { - if ($singleAppId) { - $output->writeln($singleAppId . ' is up-to-date or no updates could be found'); + if ($checkFailed) { + if (!$singleAppId) { + $output->writeln('Some apps could not be checked for updates; the rest are up to date'); + } + } elseif ($singleAppId) { + $output->writeln('App "' . $singleAppId . '" is already up to date'); } else { - $output->writeln('All apps are up-to-date or no updates could be found'); + $output->writeln('All apps are up to date'); } }