]> BookStack Code Mirror - system-cli/blob - src/Commands/UpdateCommand.php
Made changes based upon freebsd/openbsd testing
[system-cli] / src / Commands / UpdateCommand.php
1 <?php declare(strict_types=1);
2
3 namespace Cli\Commands;
4
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;
14
15 class UpdateCommand extends Command
16 {
17     protected function configure(): void
18     {
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', '');
22     }
23
24     /**
25      * @throws CommandError
26      */
27     protected function execute(InputInterface $input, OutputInterface $output): int
28     {
29         $appDir = AppLocator::require($input->getOption('app-directory'));
30         $output->writeln("<info>Checking system requirements...</info>");
31         RequirementsValidator::validate();
32
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();
39         }
40
41         $output->writeln("<info>Fetching latest code via Git...</info>");
42         $this->updateCodeUsingGit($appDir);
43
44         $output->writeln("<info>Installing PHP dependencies via composer...</info>");
45         $this->installComposerDependencies($composer, $appDir);
46
47         $output->writeln("<info>Running database migrations...</info>");
48         $artisan = (new ArtisanRunner($appDir));
49         $artisan->run(['migrate', '--force']);
50
51         $output->writeln("<info>Clearing app caches...</info>");
52         $artisan->run(['cache:clear']);
53         $artisan->run(['config:clear']);
54         $artisan->run(['view:clear']);
55
56         $output->writeln("<success>Your BookStack instance at [{$appDir}] has been updated!</success>");
57
58         return Command::SUCCESS;
59     }
60
61     /**
62      * @throws CommandError
63      */
64     protected function updateCodeUsingGit(string $appDir): void
65     {
66         $errors = (new ProgramRunner('git', '/usr/bin/git'))
67             ->withTimeout(240)
68             ->withIdleTimeout(15)
69             ->runCapturingStdErr([
70                 '-C', $appDir,
71                 'pull', '-q', 'origin', 'release',
72             ]);
73
74         if ($errors) {
75             throw new CommandError("Failed git pull with errors:\n" . $errors);
76         }
77     }
78
79     /**
80      * @throws CommandError
81      */
82     protected function installComposerDependencies(ProgramRunner $composer, string $appDir): void
83     {
84         $errors = $composer->runCapturingStdErr([
85             'install',
86             '--no-dev', '-n', '-q', '--no-progress',
87             '-d', $appDir,
88         ]);
89
90         if ($errors) {
91             throw new CommandError("Failed composer install with errors:\n" . $errors);
92         }
93     }
94 }