appManager->isEnabledForAnyone(self::APP); } private function codeIsPresent(): bool { try { $this->appManager->getAppPath(self::APP); return true; } catch (AppPathNotFoundException) { return false; } } /** Installs (from the app store, if missing) and enables user_migration; throws on failure. */ public function install(): void { $args = $this->codeIsPresent() ? ['app:enable', self::APP] : ['app:install', self::APP]; /** @psalm-suppress UndefinedClass */ $occ = \OC::$SERVERROOT . '/occ'; $command = implode(' ', array_map('escapeshellarg', [PHP_BINARY, $occ, ...$args])) . ' 2>&1'; exec($command, $lines, $code); if ($code !== 0) { throw new \RuntimeException("occ " . implode(' ', $args) . " failed:\n" . implode("\n", $lines)); } } /** * Returns when user_migration is enabled. Otherwise asks the administrator (interactive shell) or * requires --install-user-migration, and throws when neither gives consent. * * @throws \RuntimeException */ public function ensureEnabled(InputInterface $input, OutputInterface $output): void { if ($this->isEnabled()) { return; } $consent = $input->getOption('install-user-migration') === true; if (!$consent && $input->isInteractive()) { $consent = (new QuestionHelper())->ask($input, $output, new ConfirmationQuestion( 'The user_migration app is not enabled. Install and enable it now? [y/N] ', false)) === true; } if (!$consent) { throw new \RuntimeException('The user_migration app is not enabled; per-user backup/restore needs it. Run "occ ' . 'app:install ' . self::APP . '" and "occ app:enable ' . self::APP . '", or repeat with --install-user-migration'); } $output->writeln('Installing and enabling user_migration (approved by the administrator)...'); $this->install(); throw new \RuntimeException('user_migration is installed and enabled; run this command again'); } }