1 <?php declare(strict_types=1);
3 namespace Cli\Commands;
5 use Cli\Services\AppLocator;
6 use Cli\Services\ArtisanRunner;
7 use Cli\Services\ComposerLocator;
8 use Cli\Services\ProgramRunner;
9 use Cli\Services\RequirementsValidator;
10 use Symfony\Component\Console\Command\Command;
11 use Symfony\Component\Console\Input\InputInterface;
12 use Symfony\Component\Console\Input\InputOption;
13 use Symfony\Component\Console\Output\OutputInterface;
15 class UpdateCommand extends Command
17 protected function configure(): void
19 $this->setName('update');
20 $this->setDescription('Update an existing BookStack instance.');
21 $this->addOption('app-directory', null, InputOption::VALUE_OPTIONAL, 'BookStack install directory to update', '');
25 * @throws CommandError
27 protected function execute(InputInterface $input, OutputInterface $output): int
29 $appDir = AppLocator::require($input->getOption('app-directory'));
30 $output->writeln("<info>Checking system requirements...</info>");
31 RequirementsValidator::validate();
33 $output->writeln("<info>Checking composer exists...</info>");
34 $composerLocator = new ComposerLocator($appDir);
35 $composer = $composerLocator->getProgram();
36 if (!$composer->isFound()) {
37 $output->writeln("<info>Composer does not exist, downloading a local copy...</info>");
38 $composerLocator->download();
41 $output->writeln("<info>Fetching latest code via Git...</info>");
42 $this->updateCodeUsingGit($appDir);
44 $output->writeln("<info>Installing PHP dependencies via composer...</info>");
45 $this->installComposerDependencies($composer, $appDir);
47 $output->writeln("<info>Running database migrations...</info>");
48 $artisan = (new ArtisanRunner($appDir));
49 $artisan->run(['migrate', '--force']);
51 $output->writeln("<info>Clearing app caches...</info>");
52 $artisan->run(['cache:clear']);
53 $artisan->run(['config:clear']);
54 $artisan->run(['view:clear']);
56 $output->writeln("<success>Your BookStack instance at [{$appDir}] has been updated!</success>");
58 return Command::SUCCESS;
62 * @throws CommandError
64 protected function updateCodeUsingGit(string $appDir): void
66 $errors = (new ProgramRunner('git', '/usr/bin/git'))
69 ->runCapturingStdErr([
71 'pull', '-q', 'origin', 'release',
75 throw new CommandError("Failed git pull with errors:\n" . $errors);
80 * @throws CommandError
82 protected function installComposerDependencies(ProgramRunner $composer, string $appDir): void
84 $errors = $composer->runCapturingStdErr([
86 '--no-dev', '-n', '-q', '--no-progress',
91 throw new CommandError("Failed composer install with errors:\n" . $errors);