summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Commands/DownloadVendorCommand.php135
-rw-r--r--src/Commands/InitCommand.php36
-rw-r--r--src/Commands/UpdateCommand.php31
-rw-r--r--src/Services/VendorDownloader.php151
-rw-r--r--src/app.php2
5 files changed, 165 insertions, 190 deletions
diff --git a/src/Commands/DownloadVendorCommand.php b/src/Commands/DownloadVendorCommand.php
index d3b0501..5019238 100644
--- a/src/Commands/DownloadVendorCommand.php
+++ b/src/Commands/DownloadVendorCommand.php
@@ -3,14 +3,12 @@
namespace Cli\Commands;
use Cli\Services\AppLocator;
+use Cli\Services\VendorDownloader;
use Exception;
-use RecursiveDirectoryIterator;
-use RecursiveIteratorIterator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-use ZipArchive;
class DownloadVendorCommand extends Command
{
@@ -28,136 +26,9 @@ class DownloadVendorCommand extends Command
{
$appDir = AppLocator::require($input->getOption('app-directory'));
- $output->writeln("<info>Checking app version...</info>");
- $version = AppLocator::getVersion($appDir);
- if (empty($version)) {
- throw new CommandError("Could not determine instance BookStack version.");
- }
- $targetChecksum = $this->getTargetChecksum($appDir);
-
- $output->writeln("<info>Downloading ZIP from files.bookstackapp.com...</info>");
- $zip = $this->downloadVendorZip($version);
-
- $output->writeln("<info>Validating downloaded ZIP...</info>");
- $this->verifyZipChecksum($zip, $targetChecksum);
-
- $output->writeln("<info>Deleting existing vendor/ directory...</info>");
- try {
- $this->deleteAppVendorFiles($appDir);
- } catch (Exception $exception) {
- unlink($zip);
- throw $exception;
- }
-
- $output->writeln("<info>Extracting ZIP into BookStack instance...</info>");
- $this->extractZip($zip, $appDir);
-
- $output->writeln("<info>Cleaning up old app services...</info>");
- $cleaned = $this->cleanupAppServices($appDir);
- if (!$cleaned) {
- $output->writeln("<warning>Failed to remove exising app services file</warning>");
- }
-
- $output->writeln("<success>Successfully downloaded & extracted vendor files into BookStack instance!</success>");
+ $downloader = new VendorDownloader($appDir, $output);
+ $downloader->download();
return Command::SUCCESS;
}
-
- protected function cleanupAppServices(string $appDir): bool
- {
- $filesToClear = [
- implode(DIRECTORY_SEPARATOR, [$appDir, 'bootstrap', 'cache', 'services.php']),
- implode(DIRECTORY_SEPARATOR, [$appDir, 'bootstrap', 'cache', 'packages.php']),
- ];
-
- $status = true;
-
- foreach ($filesToClear as $file) {
- if (file_exists($file)) {
- if (@unlink($file) === false) {
- $status = false;
- }
- }
- }
-
- return $status;
- }
-
- protected function extractZip(string $zipPath, string $appDir): void
- {
- $zip = new ZipArchive();
- $opened = $zip->open($zipPath, ZipArchive::RDONLY);
- $extracted = $zip->extractTo($appDir);
- $closed = $zip->close();
-
- unlink($zipPath);
- if (!$opened || !$extracted || !$closed) {
- throw new CommandError("Failed to extract ZIP files into {$appDir}");
- }
- }
-
- protected function deleteAppVendorFiles(string $appDir): void
- {
- $targetDir = $appDir . DIRECTORY_SEPARATOR . 'vendor';
- if (!is_dir($targetDir)) {
- return;
- }
-
- $it = new RecursiveDirectoryIterator($targetDir, RecursiveDirectoryIterator::SKIP_DOTS);
- $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
- foreach($files as $file) {
- if ($file->isDir()){
- rmdir($file->getPathname());
- } else {
- unlink($file->getPathname());
- }
- }
-
- $deleted = rmdir($targetDir);
- if (!$deleted) {
- throw new CommandError("Could not delete existing app vendor directory.");
- }
- }
-
- protected function verifyZipChecksum(string $zipPath, string $targetChecksum): void
- {
- $zipChecksum = hash_file('sha256', $zipPath);
- if ($zipChecksum !== $targetChecksum) {
- unlink($zipPath);
- throw new CommandError("Checksum of downloaded ZIP does not match the expected checksum.");
- }
- }
-
- protected function downloadVendorZip(string $version): string
- {
- $tempFile = tempnam(sys_get_temp_dir(), 'bs-cli-vendor-zip');
- $targetUrl = "https://files.bookstackapp.com/vendor/{$version}.zip";
-
- $targetFile = @fopen($targetUrl, 'rb');
- if ($targetFile === false) {
- throw new CommandError("Failed to download ZIP file from $targetUrl");
- }
-
- file_put_contents($tempFile, $targetFile);
-
- return $tempFile;
- }
-
- /**
- * @throws CommandError
- */
- protected function getTargetChecksum(string $appDir): string
- {
- $checksumFile = implode(DIRECTORY_SEPARATOR, [$appDir, 'dev', 'checksums', 'vendor']);
- $checksum = '';
- if (file_exists($checksumFile)) {
- $checksum = trim(file_get_contents($checksumFile));
- }
-
- if (empty($checksum)) {
- throw new CommandError("Could not find a vendor checksum for validation.");
- }
-
- return $checksum;
- }
}
diff --git a/src/Commands/InitCommand.php b/src/Commands/InitCommand.php
index 4ebd267..80d17e9 100644
--- a/src/Commands/InitCommand.php
+++ b/src/Commands/InitCommand.php
@@ -2,11 +2,11 @@
namespace Cli\Commands;
-use Cli\Services\ComposerLocator;
use Cli\Services\EnvironmentLoader;
use Cli\Services\Paths;
use Cli\Services\ProgramRunner;
use Cli\Services\RequirementsValidator;
+use Cli\Services\VendorDownloader;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -38,16 +38,9 @@ class InitCommand extends Command
$output->writeln("<info>Cloning down BookStack project to install directory...</info>");
$this->cloneBookStackViaGit($installDir);
- $output->writeln("<info>Checking composer exists...</info>");
- $composerLocator = new ComposerLocator($installDir);
- $composer = $composerLocator->getProgram();
- if (!$composer->isFound()) {
- $output->writeln("<info>Composer does not exist, downloading a local copy...</info>");
- $composerLocator->download();
- }
-
- $output->writeln("<info>Installing application dependencies using composer...</info>");
- $this->installComposerDependencies($composer, $installDir);
+ $output->writeln("<info>Downloading PHP dependencies from files.bookstackapp.com..</info>");
+ $vendorDownloader = new VendorDownloader($installDir, $output);
+ $vendorDownloader->download();
$output->writeln("<info>Creating .env file from .env.example...</info>");
copy(Paths::join($installDir, '.env.example'), Paths::join($installDir, '.env'));
@@ -84,24 +77,7 @@ class InitCommand extends Command
}
/**
- * Run composer install to download PHP dependencies.
- * @throws CommandError
- */
- protected function installComposerDependencies(ProgramRunner $composer, string $installDir): void
- {
- $errors = $composer->runCapturingStdErr([
- 'install',
- '--no-dev', '-n', '-q', '--no-progress',
- '-d', $installDir
- ]);
-
- if ($errors) {
- throw new CommandError("Failed composer install with errors:\n" . $errors);
- }
- }
-
- /**
- * Clone a new instance of BookStack to the given install folder.
+ * Clone a new instance of BookStack to the given installation folder.
* @throws CommandError
*/
protected function cloneBookStackViaGit(string $installDir): void
@@ -114,7 +90,7 @@ class InitCommand extends Command
'clone', '-q',
'--branch', 'release',
'--single-branch',
- 'https://github.com/BookStackApp/BookStack.git',
+ 'https://source.bookstackapp.com/bookstack.git',
$installDir
]);
diff --git a/src/Commands/UpdateCommand.php b/src/Commands/UpdateCommand.php
index 23ffc2d..c6fc476 100644
--- a/src/Commands/UpdateCommand.php
+++ b/src/Commands/UpdateCommand.php
@@ -4,10 +4,10 @@ namespace Cli\Commands;
use Cli\Services\AppLocator;
use Cli\Services\ArtisanRunner;
-use Cli\Services\ComposerLocator;
use Cli\Services\Paths;
use Cli\Services\ProgramRunner;
use Cli\Services\RequirementsValidator;
+use Cli\Services\VendorDownloader;
use Phar;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@@ -35,14 +35,6 @@ class UpdateCommand extends Command
$output->writeln("<info>Checking local Git repository is active...</info>");
$this->ensureGitRepoExists($appDir);
- $output->writeln("<info>Checking composer exists...</info>");
- $composerLocator = new ComposerLocator($appDir);
- $composer = $composerLocator->getProgram();
- if (!$composer->isFound()) {
- $output->writeln("<info>Composer does not exist, downloading a local copy...</info>");
- $composerLocator->download();
- }
-
$cliPath = Phar::running(false);
$cliPreUpdateHash = $cliPath ? hash_file('sha256', $cliPath) : '';
@@ -55,8 +47,9 @@ class UpdateCommand extends Command
return Command::FAILURE;
}
- $output->writeln("<info>Installing PHP dependencies via composer...</info>");
- $this->installComposerDependencies($composer, $appDir);
+ $output->writeln("<info>Downloading PHP dependencies from files.bookstackapp.com...</info>");
+ $vendorDownloader = new VendorDownloader($appDir, $output);
+ $vendorDownloader->download();
$output->writeln("<info>Running database migrations...</info>");
$artisan = (new ArtisanRunner($appDir));
@@ -90,22 +83,6 @@ class UpdateCommand extends Command
}
}
- /**
- * @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);
- }
- }
-
protected function ensureGitRepoExists(string $appDir): void
{
$expectedPath = Paths::join($appDir, '.git');
diff --git a/src/Services/VendorDownloader.php b/src/Services/VendorDownloader.php
new file mode 100644
index 0000000..389baf2
--- /dev/null
+++ b/src/Services/VendorDownloader.php
@@ -0,0 +1,151 @@
+<?php declare(strict_types=1);
+
+namespace Cli\Services;
+
+use Cli\Commands\CommandError;
+use Exception;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+use Symfony\Component\Console\Output\OutputInterface;
+use ZipArchive;
+
+class VendorDownloader
+{
+ public function __construct(
+ protected string $appDir,
+ protected OutputInterface $output
+ ) {}
+
+ public function download(): void
+ {
+ $this->output->writeln("<info>Checking app version...</info>");
+ $version = AppLocator::getVersion($this->appDir);
+ if (empty($version)) {
+ throw new CommandError("Could not determine instance BookStack version.");
+ }
+ $targetChecksum = $this->getTargetChecksum();
+
+ $this->output->writeln("<info>Downloading ZIP from files.bookstackapp.com...</info>");
+ $zip = $this->downloadVendorZip($version);
+
+ $this->output->writeln("<info>Validating downloaded ZIP...</info>");
+ $this->verifyZipChecksum($zip, $targetChecksum);
+
+ $this->output->writeln("<info>Deleting existing vendor/ directory...</info>");
+ try {
+ $this->deleteAppVendorFiles();
+ } catch (Exception $exception) {
+ unlink($zip);
+ throw $exception;
+ }
+
+ $this->output->writeln("<info>Extracting ZIP into BookStack instance...</info>");
+ $this->extractZip($zip);
+
+ $this->output->writeln("<info>Cleaning up old app services...</info>");
+ $cleaned = $this->cleanupAppServices();
+ if (!$cleaned) {
+ $this->output->writeln("<warning>Failed to remove exising app services file</warning>");
+ }
+
+ $this->output->writeln("<success>Successfully downloaded & extracted vendor files into BookStack instance!</success>");
+ }
+
+ protected function cleanupAppServices(): bool
+ {
+ $filesToClear = [
+ implode(DIRECTORY_SEPARATOR, [$this->appDir, 'bootstrap', 'cache', 'services.php']),
+ implode(DIRECTORY_SEPARATOR, [$this->appDir, 'bootstrap', 'cache', 'packages.php']),
+ ];
+
+ $status = true;
+
+ foreach ($filesToClear as $file) {
+ if (file_exists($file)) {
+ if (@unlink($file) === false) {
+ $status = false;
+ }
+ }
+ }
+
+ return $status;
+ }
+
+ protected function extractZip(string $zipPath): void
+ {
+ $zip = new ZipArchive();
+ $opened = $zip->open($zipPath, ZipArchive::RDONLY);
+ $extracted = $zip->extractTo($this->appDir);
+ $closed = $zip->close();
+
+ unlink($zipPath);
+ if (!$opened || !$extracted || !$closed) {
+ throw new CommandError("Failed to extract ZIP files into {$this->appDir}");
+ }
+ }
+
+ protected function deleteAppVendorFiles(): void
+ {
+ $targetDir = $this->appDir . DIRECTORY_SEPARATOR . 'vendor';
+ if (!is_dir($targetDir)) {
+ return;
+ }
+
+ $it = new RecursiveDirectoryIterator($targetDir, RecursiveDirectoryIterator::SKIP_DOTS);
+ $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
+ foreach($files as $file) {
+ if ($file->isDir()){
+ rmdir($file->getPathname());
+ } else {
+ unlink($file->getPathname());
+ }
+ }
+
+ $deleted = rmdir($targetDir);
+ if (!$deleted) {
+ throw new CommandError("Could not delete existing app vendor directory.");
+ }
+ }
+
+ protected function verifyZipChecksum(string $zipPath, string $targetChecksum): void
+ {
+ $zipChecksum = hash_file('sha256', $zipPath);
+ if ($zipChecksum !== $targetChecksum) {
+ unlink($zipPath);
+ throw new CommandError("Checksum of downloaded ZIP does not match the expected checksum.");
+ }
+ }
+
+ protected function downloadVendorZip(string $version): string
+ {
+ $tempFile = tempnam(sys_get_temp_dir(), 'bs-cli-vendor-zip');
+ $targetUrl = "https://files.bookstackapp.com/vendor/{$version}.zip";
+
+ $targetFile = @fopen($targetUrl, 'rb');
+ if ($targetFile === false) {
+ throw new CommandError("Failed to download ZIP file from $targetUrl");
+ }
+
+ file_put_contents($tempFile, $targetFile);
+
+ return $tempFile;
+ }
+
+ /**
+ * @throws CommandError
+ */
+ protected function getTargetChecksum(): string
+ {
+ $checksumFile = implode(DIRECTORY_SEPARATOR, [$this->appDir, 'dev', 'checksums', 'vendor']);
+ $checksum = '';
+ if (file_exists($checksumFile)) {
+ $checksum = trim(file_get_contents($checksumFile));
+ }
+
+ if (empty($checksum)) {
+ throw new CommandError("Could not find a vendor checksum for validation.");
+ }
+
+ return $checksum;
+ }
+}
diff --git a/src/app.php b/src/app.php
index cef8388..26e5c53 100644
--- a/src/app.php
+++ b/src/app.php
@@ -9,7 +9,7 @@ use Cli\Commands\RestoreCommand;
use Cli\Commands\UpdateCommand;
// Setup our CLI
-$app = new Application('bookstack-system-cli', '0.3.1');
+$app = new Application('bookstack-system-cli', '0.4.0');
$app->setCatchExceptions(false);
$app->add(new BackupCommand());