mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Got restore command to a working state
This commit is contained in:
parent
0c14f22831
commit
c84d8aa4c1
@ -105,10 +105,11 @@ class InitCommand extends Command
|
||||
*/
|
||||
protected function cloneBookStackViaGit(string $installDir): void
|
||||
{
|
||||
$errors = (new ProgramRunner('git', '/usr/bin/git'))
|
||||
$git = (new ProgramRunner('git', '/usr/bin/git'))
|
||||
->withTimeout(240)
|
||||
->withIdleTimeout(15)
|
||||
->runCapturingStdErr([
|
||||
->withIdleTimeout(15);
|
||||
|
||||
$errors = $git->runCapturingStdErr([
|
||||
'clone', '-q',
|
||||
'--branch', 'release',
|
||||
'--single-branch',
|
||||
@ -119,6 +120,12 @@ class InitCommand extends Command
|
||||
if ($errors) {
|
||||
throw new CommandError("Failed git clone with errors:\n" . $errors);
|
||||
}
|
||||
|
||||
// Disable file permission tracking for git repo
|
||||
$git->runCapturingStdErr([
|
||||
'-C', $installDir,
|
||||
'config', 'core.fileMode', 'false'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,6 @@ class RestoreCommand extends Command
|
||||
|
||||
$zipPath = realpath($input->getArgument('backup-zip'));
|
||||
$zip = new BackupZip($zipPath);
|
||||
// TODO - Fix folders not being picked up here:
|
||||
$contents = $zip->getContentsOverview();
|
||||
|
||||
$output->writeln("\n<info>Contents found in the backup ZIP:</info>");
|
||||
@ -79,9 +78,10 @@ class RestoreCommand extends Command
|
||||
}
|
||||
$zip->extractInto($extractDir);
|
||||
|
||||
$envChanges = [];
|
||||
if ($contents['env']['exists']) {
|
||||
$output->writeln("<info>Restoring and merging .env file...</info>");
|
||||
$this->restoreEnv($extractDir, $appDir);
|
||||
$envChanges = $this->restoreEnv($extractDir, $appDir, $output, $interactions);
|
||||
}
|
||||
|
||||
$folderLocations = ['themes', 'public/uploads', 'storage/uploads'];
|
||||
@ -92,18 +92,22 @@ class RestoreCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
$artisan = (new ArtisanRunner($appDir));
|
||||
if ($contents['db']['exists']) {
|
||||
$output->writeln("<info>Restoring database from SQL dump...</info>");
|
||||
$this->restoreDatabase($appDir, $extractDir);
|
||||
|
||||
$output->writeln("<info>Running database migrations...</info>");
|
||||
$artisan = (new ArtisanRunner($appDir));
|
||||
$artisan->run(['migrate', '--force']);
|
||||
}
|
||||
|
||||
// TODO - Handle change of URL?
|
||||
// TODO - Update system URL (via BookStack artisan command) if
|
||||
// there's been a change from old backup env
|
||||
if ($envChanges && $envChanges['old_url'] !== $envChanges['new_url']) {
|
||||
$output->writeln("<info>App URL change made, Updating database with URL change...</info>");
|
||||
$artisan->run([
|
||||
'bookstack:update-url',
|
||||
$envChanges['old_url'], $envChanges['new_url'],
|
||||
]);
|
||||
}
|
||||
|
||||
$output->writeln("<info>Clearing app caches...</info>");
|
||||
$artisan->run(['cache:clear']);
|
||||
@ -118,7 +122,7 @@ class RestoreCommand extends Command
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function restoreEnv(string $extractDir, string $appDir)
|
||||
protected function restoreEnv(string $extractDir, string $appDir, OutputInterface $output, InteractiveConsole $interactions): array
|
||||
{
|
||||
$oldEnv = EnvironmentLoader::load($extractDir);
|
||||
$currentEnv = EnvironmentLoader::load($appDir);
|
||||
@ -149,7 +153,23 @@ class RestoreCommand extends Command
|
||||
copy($appEnvPath, $appEnvPath . '.backup');
|
||||
}
|
||||
|
||||
$oldUrl = $oldEnv['APP_URL'] ?? '';
|
||||
$newUrl = $currentEnv['APP_URL'] ?? '';
|
||||
$returnData = [
|
||||
'old_url' => $oldUrl,
|
||||
'new_url' => $oldUrl,
|
||||
];
|
||||
|
||||
if ($oldUrl !== $newUrl) {
|
||||
$output->writeln("Found different APP_URL values:");
|
||||
$changedUrl = $interactions->choice('Which would you like to use?', array_filter([$oldUrl, $newUrl]));
|
||||
$envContents = preg_replace('/^APP_URL=.*?$/', 'APP_URL="' . $changedUrl . '"', $envContents);
|
||||
$returnData['new_url'] = $changedUrl;
|
||||
}
|
||||
|
||||
file_put_contents($appDir . DIRECTORY_SEPARATOR . '.env', $envContents);
|
||||
|
||||
return $returnData;
|
||||
}
|
||||
|
||||
protected function restoreFolder(string $folderSubPath, string $appDir, string $extractDir): void
|
||||
|
@ -30,15 +30,15 @@ class BackupZip
|
||||
],
|
||||
'themes' => [
|
||||
'desc' => 'Themes Folder',
|
||||
'exists' => $this->zip->locateName('/themes/') !== false,
|
||||
'exists' => $this->hasFolder('themes/'),
|
||||
],
|
||||
'public/uploads' => [
|
||||
'desc' => 'Public File Uploads',
|
||||
'exists' => $this->zip->locateName('/public/uploads/') !== false,
|
||||
'exists' => $this->hasFolder('public/uploads/'),
|
||||
],
|
||||
'storage/uploads' => [
|
||||
'desc' => 'Private File Uploads',
|
||||
'exists' => $this->zip->locateName('/storage/uploads/') !== false,
|
||||
'exists' => $this->hasFolder('storage/uploads/'),
|
||||
],
|
||||
'db' => [
|
||||
'desc' => 'Database Dump',
|
||||
@ -54,4 +54,15 @@ class BackupZip
|
||||
throw new \Exception("Failed extraction of ZIP into [{$directoryPath}].");
|
||||
}
|
||||
}
|
||||
|
||||
protected function hasFolder($folderPath): bool
|
||||
{
|
||||
for ($i = 0; $i < $this->zip->numFiles; $i++) {
|
||||
$filePath = $this->zip->getNameIndex($i);
|
||||
if (str_starts_with($filePath, $folderPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Cli\Services;
|
||||
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@ -9,14 +10,11 @@ use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
class InteractiveConsole
|
||||
{
|
||||
|
||||
|
||||
public function __construct(
|
||||
protected QuestionHelper $helper,
|
||||
protected InputInterface $input,
|
||||
protected OutputInterface $output,
|
||||
)
|
||||
{
|
||||
) {
|
||||
}
|
||||
|
||||
public function confirm(string $text): bool
|
||||
@ -24,4 +22,10 @@ class InteractiveConsole
|
||||
$question = new ConfirmationQuestion($text . " (y/n)\n", false);
|
||||
return $this->helper->ask($this->input, $this->output, $question);
|
||||
}
|
||||
|
||||
public function choice(string $question, array $answers)
|
||||
{
|
||||
$question = new ChoiceQuestion($question, $answers, $answers[0]);
|
||||
return $this->helper->ask($this->input, $this->output, $question);
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ class MySqlRunner
|
||||
'-u', $this->user,
|
||||
'-p' . $this->password,
|
||||
$this->database,
|
||||
'-e' . "'show tables;'"
|
||||
'-e', "show tables;"
|
||||
]);
|
||||
|
||||
return !$output;
|
||||
|
Loading…
Reference in New Issue
Block a user