use Cli\Services\EnvironmentLoader;
use Cli\Services\ProgramRunner;
-use Minicli\Command\CommandCall;
use RecursiveDirectoryIterator;
use SplFileInfo;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use ZipArchive;
-final class BackupCommand
+final class BackupCommand extends Command
{
public function __construct(
protected string $appDir
) {
+ parent::__construct();
+ }
+
+ protected function configure(): void
+ {
+ $this->setName('backup');
+ $this->setDescription('Backup a BookStack installation to a single compressed ZIP file.');
+ $this->addArgument('backup-path', InputArgument::OPTIONAL, 'Outfile file or directory to store the resulting backup file.', '');
+ $this->addOption('no-database', null, null, "Skip adding a database dump to the backup");
+ $this->addOption('no-uploads', null, null, "Skip adding uploaded files to the backup");
+ $this->addOption('no-themes', null, null, "Skip adding the themes folder to the backup");
}
/**
* @throws CommandError
*/
- public function handle(CommandCall $input)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->ensureRequiredExtensionInstalled();
- $handleDatabase = !$input->hasFlag('no-database');
- $handleUploads = !$input->hasFlag('no-uploads');
- $handleThemes = !$input->hasFlag('no-themes');
- $suggestedOutPath = $input->subcommand;
- if ($suggestedOutPath === 'default') {
- $suggestedOutPath = '';
- }
+ $handleDatabase = !$input->getOption('no-database');
+ $handleUploads = !$input->getOption('no-uploads');
+ $handleThemes = !$input->getOption('no-themes');
+ $suggestedOutPath = $input->getArgument('backup-path');
$zipOutFile = $this->buildZipFilePath($suggestedOutPath);
$zip->addFile($this->appDir . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'run', 'run');
if ($handleDatabase) {
- echo "Dumping the database via mysqldump...\n";
+ $output->writeln("<info>Dumping the database via mysqldump...</info>");
$dumpTempFile = $this->createDatabaseDump();
- echo "Adding database dump to backup archive...\n";
+ $output->writeln("<info>Adding database dump to backup archive...</info>");
$zip->addFile($dumpTempFile, 'db.sql');
}
if ($handleUploads) {
- echo "Adding BookStack upload folders to backup archive...\n";
+ $output->writeln("<info>Adding BookStack upload folders to backup archive...</info>");
$this->addUploadFoldersToZip($zip);
}
if ($handleThemes) {
- echo "Adding BookStack theme folders to backup archive...\n";
+ $output->writeln("<info>Adding BookStack theme folders to backup archive...</info>");
$this->addFolderToZipRecursive($zip, implode(DIRECTORY_SEPARATOR, [$this->appDir, 'themes']), 'themes');
}
rename($zipTempFile, $zipOutFile);
// Announce end
- echo "Backup finished.\nOutput ZIP saved to: {$zipOutFile}\n";
+ $output->writeln("<info>Backup finished.</info>");
+ $output->writeln("Output ZIP saved to: {$zipOutFile}");
+
+ return Command::SUCCESS;
}
/**
use Cli\Services\EnvironmentLoader;
use Cli\Services\ProgramRunner;
-use Minicli\Command\CommandCall;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
-class InitCommand
+class InitCommand extends Command
{
+ protected function configure(): void
+ {
+ $this->setName('init');
+ $this->setDescription('Initialise a new BookStack install. Does not configure the webserver or database.');
+ $this->addArgument('target-directory', InputArgument::OPTIONAL, 'The directory to create the BookStack install within. Must be empty.', '');
+ }
+
/**
* @throws CommandError
*/
- public function handle(CommandCall $input)
+ protected function execute(InputInterface $input, OutputInterface $output): int
{
- echo "Checking system requirements...\n";
+ $output->writeln("<info>Checking system requirements...</info>");
$this->ensureRequirementsMet();
- $suggestedOutPath = $input->subcommand;
- if ($suggestedOutPath === 'default') {
- $suggestedOutPath = '';
- }
+ $suggestedOutPath = $input->getArgument('target-directory');
- echo "Locating and checking install directory...\n";
+ $output->writeln("<info>Locating and checking install directory...</info>");
$installDir = $this->getInstallDir($suggestedOutPath);
$this->ensureInstallDirEmptyAndWritable($installDir);
- echo "Cloning down BookStack project to install directory...\n";
+ $output->writeln("<info>Cloning down BookStack project to install directory...</info>");
$this->cloneBookStackViaGit($installDir);
- echo "Checking composer exists...\n";
+ $output->writeln("<info>Checking composer exists...</info>");
$composer = $this->getComposerProgram($installDir);
try {
$composer->ensureFound();
} catch (\Exception $exception) {
- echo "Composer does not exist, downloading a local copy...\n";
+ $output->writeln("<info>Composer does not exist, downloading a local copy...</info>");
$this->downloadComposerToInstall($installDir);
}
- echo "Installing application dependencies using composer...\n";
+ $output->writeln("<info>Installing application dependencies using composer...</info>");
$this->installComposerDependencies($composer, $installDir);
- echo "Creating .env file from .env.example...\n";
+ $output->writeln("<info>Creating .env file from .env.example...</info>");
copy($installDir . DIRECTORY_SEPARATOR . '.env.example', $installDir . DIRECTORY_SEPARATOR . '.env');
sleep(1);
- echo "Generating app key...\n";
+ $output->writeln("<info>Generating app key...</info>");
$this->generateAppKey($installDir);
// Announce end
- echo "A BookStack install has been initialized at: {$installDir}\n\n";
- echo "You will still need to:\n";
- echo "- Update the .env file in the install with correct URL, database and email details.\n";
- echo "- Run 'php artisan migrate' to set-up the database.\n";
- echo "- Configure your webserver for use with BookStack.\n";
- echo "- Ensure the required directories (storage/ bootstrap/cache public/uploads) are web-server writable.\n";
+ $output->writeln("<info>A BookStack install has been initialized at: {$installDir}\n</info>");
+ $output->writeln("<info>You will still need to:</info>");
+ $output->writeln("<info>- Update the .env file in the install with correct URL, database and email details.</info>");
+ $output->writeln("<info>- Run 'php artisan migrate' to set-up the database.</info>");
+ $output->writeln("<info>- Configure your webserver for use with BookStack.</info>");
+ $output->writeln("<info>- Ensure the required directories (storage/ bootstrap/cache public/uploads) are web-server writable.</info>");
+
+ return Command::SUCCESS;
}
/**
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "b56ccc782d009482249ce5e3a4b62147",
+ "content-hash": "40bb5069cf724f3ce0428185a73841e7",
"packages": [
{
"name": "graham-campbell/result-type",
],
"time": "2023-02-25T20:23:15+00:00"
},
- {
- "name": "minicli/minicli",
- "version": "3.2.1",
- "source": {
- "type": "git",
- "url": "https://github.com/minicli/minicli.git",
- "reference": "2d31b303461d0ec1f8c6d0be00f8b26be8766fbe"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/minicli/minicli/zipball/2d31b303461d0ec1f8c6d0be00f8b26be8766fbe",
- "reference": "2d31b303461d0ec1f8c6d0be00f8b26be8766fbe",
- "shasum": ""
- },
- "require": {
- "ext-readline": "*",
- "php": ">=8"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.5",
- "pestphp/pest": "^1.0",
- "phpunit/phpunit": "^9.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Minicli\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Experimental micro CLI framework for PHP",
- "homepage": "https://github.com/minicli/minicli",
- "keywords": [
- "cli",
- "command-line"
- ],
- "support": {
- "issues": "https://github.com/minicli/minicli/issues",
- "source": "https://github.com/minicli/minicli/tree/3.2.1"
- },
- "funding": [
- {
- "url": "https://github.com/erikaheidi",
- "type": "github"
- }
- ],
- "time": "2022-09-23T09:04:22+00:00"
- },
{
"name": "phpoption/phpoption",
"version": "1.9.1",
],
"time": "2023-02-25T19:38:58+00:00"
},
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "symfony/console",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/console.git",
+ "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
+ "reference": "c3ebc83d031b71c39da318ca8b7a07ecc67507ed",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/string": "^5.4|^6.0"
+ },
+ "conflict": {
+ "symfony/dependency-injection": "<5.4",
+ "symfony/dotenv": "<5.4",
+ "symfony/event-dispatcher": "<5.4",
+ "symfony/lock": "<5.4",
+ "symfony/process": "<5.4"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0|2.0|3.0"
+ },
+ "require-dev": {
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/lock": "^5.4|^6.0",
+ "symfony/process": "^5.4|^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
+ },
+ "suggest": {
+ "psr/log": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/lock": "",
+ "symfony/process": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Console\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Eases the creation of beautiful and testable command line interfaces",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cli",
+ "command line",
+ "console",
+ "terminal"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/console/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
],
"time": "2022-11-03T14:55:06+00:00"
},
+ {
+ "name": "symfony/polyfill-intl-grapheme",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
+ "reference": "511a08c03c1960e08a883f4cffcacd219b758354"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
+ "reference": "511a08c03c1960e08a883f4cffcacd219b758354",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's grapheme_* functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "grapheme",
+ "intl",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-intl-normalizer",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
+ "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for intl's Normalizer class and related functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "intl",
+ "normalizer",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
],
"time": "2023-01-01T08:36:10+00:00"
},
+ {
+ "name": "symfony/service-contracts",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66",
+ "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "psr/container": "^2.0"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
+ },
+ "suggest": {
+ "symfony/service-implementation": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-30T19:17:58+00:00"
+ },
+ {
+ "name": "symfony/string",
+ "version": "v6.0.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/string.git",
+ "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/string/zipball/d9e72497367c23e08bf94176d2be45b00a9d232a",
+ "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-normalizer": "~1.0",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "symfony/translation-contracts": "<2.0"
+ },
+ "require-dev": {
+ "symfony/error-handler": "^5.4|^6.0",
+ "symfony/http-client": "^5.4|^6.0",
+ "symfony/translation-contracts": "^2.0|^3.0",
+ "symfony/var-exporter": "^5.4|^6.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/functions.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\String\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "grapheme",
+ "i18n",
+ "string",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/string/tree/v6.0.19"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-01-01T08:36:10+00:00"
+ },
{
"name": "vlucas/phpdotenv",
"version": "v5.5.0",