setName('update'); $this->setDescription('Update an existing BookStack instance.'); $this->addOption('app-directory', null, InputOption::VALUE_OPTIONAL, 'BookStack install directory to update', ''); } /** * @throws CommandError */ protected function execute(InputInterface $input, OutputInterface $output): int { $appDir = AppLocator::require($input->getOption('app-directory')); $output->writeln("Checking system requirements..."); RequirementsValidator::validate(); $output->writeln("Checking composer exists..."); $composerLocator = new ComposerLocator($appDir); $composer = $composerLocator->getProgram(); if (!$composer->isFound()) { $output->writeln("Composer does not exist, downloading a local copy..."); $composerLocator->download(); } $output->writeln("Fetching latest code via Git..."); $this->updateCodeUsingGit($appDir); $output->writeln("Installing PHP dependencies via composer..."); $this->installComposerDependencies($composer, $appDir); $output->writeln("Running database migrations..."); $artisan = (new ArtisanRunner($appDir)); $artisan->run(['migrate', '--force']); $output->writeln("Clearing app caches..."); $artisan->run(['cache:clear']); $artisan->run(['config:clear']); $artisan->run(['view:clear']); $output->writeln("Your BookStack instance at [{$appDir}] has been updated!"); return Command::SUCCESS; } /** * @throws CommandError */ protected function updateCodeUsingGit(string $appDir): void { $errors = (new ProgramRunner('git', '/usr/bin/git')) ->withTimeout(240) ->withIdleTimeout(15) ->runCapturingStdErr([ '-C', $appDir, 'pull', '-q', 'origin', 'release', ]); if ($errors) { throw new CommandError("Failed git pull with errors:\n" . $errors); } } /** * @throws CommandError */ protected function installComposerDependencies(ProgramRunner $composer, string $appDir): void { $errors = $composer->runCapturingStdErr([ 'install', '--no-dev', '-n', '-q', '--no-progress', '-d', $appDir, ]); if ($errors) { throw new CommandError("Failed composer install with errors:\n" . $errors); } } }