diff --git a/bin/console b/bin/console index 2902d7e2e..3f4cf5fa5 100755 --- a/bin/console +++ b/bin/console @@ -28,6 +28,7 @@ use PrestaShop\Module\AutoUpgrade\Commands\CheckRequirementsCommand; use PrestaShop\Module\AutoUpgrade\Commands\CreateBackupCommand; +use PrestaShop\Module\AutoUpgrade\Commands\DeleteBackupCommand; use PrestaShop\Module\AutoUpgrade\Commands\ListBackupCommand; use PrestaShop\Module\AutoUpgrade\Commands\RestoreCommand; use PrestaShop\Module\AutoUpgrade\Commands\UpdateCommand; @@ -52,6 +53,7 @@ $application->add(new RestoreCommand()); $application->add(new CheckRequirementsCommand()); $application->add(new CreateBackupCommand()); $application->add(new ListBackupCommand()); +$application->add(new DeleteBackupCommand()); $input = new ArgvInput(); $output = new ConsoleOutput(); diff --git a/classes/Backup/BackupManager.php b/classes/Backup/BackupManager.php index 316bdf942..5265e7591 100644 --- a/classes/Backup/BackupManager.php +++ b/classes/Backup/BackupManager.php @@ -53,7 +53,7 @@ public function deleteBackup(string $backupName): void $filesystem = new Filesystem(); $filesystem->remove([ - $this->backupFinder->getBackupPath() . DIRECTORY_SEPARATOR . BackupFinder::BACKUP_ZIP_NAME_PREFIX . $backupName, + $this->backupFinder->getBackupPath() . DIRECTORY_SEPARATOR . BackupFinder::BACKUP_ZIP_NAME_PREFIX . $backupName . '.zip', $this->backupFinder->getBackupPath() . DIRECTORY_SEPARATOR . $backupName, ]); diff --git a/classes/Commands/AbstractBackupCommand.php b/classes/Commands/AbstractBackupCommand.php new file mode 100644 index 000000000..13798d0de --- /dev/null +++ b/classes/Commands/AbstractBackupCommand.php @@ -0,0 +1,112 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ + +namespace PrestaShop\Module\AutoUpgrade\Commands; + +use DateTime; +use Exception; +use PrestaShop\Module\AutoUpgrade\Backup\BackupFinder; +use PrestaShop\Module\AutoUpgrade\Backup\BackupManager; +use PrestaShop\Module\AutoUpgrade\Exceptions\BackupException; +use PrestaShop\Module\AutoUpgrade\UpgradeContainer; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; + +abstract class AbstractBackupCommand extends AbstractCommand +{ + /** @var BackupFinder */ + protected $backupFinder; + + /** @var BackupManager */ + protected $backupManager; + + protected function setupEnvironment(InputInterface $input, OutputInterface $output): void + { + parent::setupEnvironment($input, $output); + $this->backupFinder = new BackupFinder($this->upgradeContainer->getProperty(UpgradeContainer::BACKUP_PATH)); + $this->backupManager = new BackupManager($this->backupFinder); + } + + /** + * @throws Exception + */ + protected function selectBackupInteractive(InputInterface $input, OutputInterface $output): ?string + { + $backups = $this->backupFinder->getAvailableBackups(); + + if (empty($backups)) { + $this->logger->info('No store backup files found in your dedicated directory'); + + return null; + } + + $formattedBackups = array_map(function ($backupName) { + return $this->backupFinder->parseBackupMetadata($backupName); + }, $backups); + + $this->backupFinder->sortBackupsByNewest($formattedBackups); + + $rows = array_map(function ($backup) { + return $this->formatBackupRow($backup); + }, $formattedBackups); + + $exit = 'Exit the process'; + $rows[] = $exit; + + $helper = $this->getHelper('question'); + $question = new ChoiceQuestion( + 'Please select your backup:', + $rows + ); + + $answer = $helper->ask($input, $output, $question); + + if ($answer === $exit) { + return null; + } + + $key = array_search($answer, $rows); + if ($key === false) { + throw new BackupException('Invalid backup selection.'); + } + + return $formattedBackups[$key]['filename']; + } + + /** + * Formats a backup row for display in the selection prompt. + * + * @param array{datetime: string, version:string, filename: string} $backups + * + * @return string + */ + private function formatBackupRow(array $backups): string + { + return sprintf('Date: %s, Version: %s, File name: %s', $backups['datetime'], $backups['version'], $backups['filename']); + } +} diff --git a/classes/Commands/AbstractCommand.php b/classes/Commands/AbstractCommand.php index b90c4cd41..3bae3145c 100644 --- a/classes/Commands/AbstractCommand.php +++ b/classes/Commands/AbstractCommand.php @@ -52,7 +52,7 @@ abstract class AbstractCommand extends Command /** * @throws Exception */ - protected function setupContainer(InputInterface $input, OutputInterface $output): void + protected function setupEnvironment(InputInterface $input, OutputInterface $output): void { $this->logger = new CliLogger($output); if ($output->isQuiet()) { diff --git a/classes/Commands/CheckRequirementsCommand.php b/classes/Commands/CheckRequirementsCommand.php index e547e3b5e..49c4a68d5 100644 --- a/classes/Commands/CheckRequirementsCommand.php +++ b/classes/Commands/CheckRequirementsCommand.php @@ -33,6 +33,7 @@ use PrestaShop\Module\AutoUpgrade\Services\DistributionApiService; use PrestaShop\Module\AutoUpgrade\Services\PhpVersionResolverService; use PrestaShop\Module\AutoUpgrade\Task\ExitCode; +use PrestaShop\Module\AutoUpgrade\UpgradeContainer; use PrestaShop\Module\AutoUpgrade\UpgradeSelfCheck; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -66,7 +67,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): ?int { try { - $this->setupContainer($input, $output); + $this->setupEnvironment($input, $output); $this->output = $output; $configPath = $input->getOption('config-file-path'); @@ -79,6 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): ?int $this->upgradeContainer->initPrestaShopAutoloader(); $this->upgradeContainer->initPrestaShopCore(); + $this->upgradeContainer->getState()->initDefault($this->upgradeContainer->getProperty(UpgradeContainer::PS_VERSION), $this->upgradeContainer->getUpgrader()->getDestinationVersion()); $distributionApiService = new DistributionApiService(); $phpVersionResolverService = new PhpVersionResolverService( diff --git a/classes/Commands/CreateBackupCommand.php b/classes/Commands/CreateBackupCommand.php index 3e9e8c74e..760e6dca4 100644 --- a/classes/Commands/CreateBackupCommand.php +++ b/classes/Commands/CreateBackupCommand.php @@ -54,7 +54,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): ?int { try { - $this->setupContainer($input, $output); + $this->setupEnvironment($input, $output); $controller = new AllBackupTasks($this->upgradeContainer); $controller->init(); diff --git a/classes/Commands/DeleteBackupCommand.php b/classes/Commands/DeleteBackupCommand.php new file mode 100644 index 000000000..ad13291e2 --- /dev/null +++ b/classes/Commands/DeleteBackupCommand.php @@ -0,0 +1,90 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ + +namespace PrestaShop\Module\AutoUpgrade\Commands; + +use Exception; +use InvalidArgumentException; +use PrestaShop\Module\AutoUpgrade\Task\ExitCode; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class DeleteBackupCommand extends AbstractBackupCommand +{ + /** + * @var string + */ + protected static $defaultName = 'backup:delete'; + + protected function configure(): void + { + $this + ->setDescription('Delete a store backup file.') + ->setHelp( + 'This command allows you to delete a store backup file.' + ) + ->addArgument('admin-dir', InputArgument::REQUIRED, 'The admin directory name.') + ->addOption('backup', null, InputOption::VALUE_REQUIRED, 'Specify the backup name to delete. The allowed values can be found with backup:list command)'); + } + + /** + * @throws Exception + */ + protected function execute(InputInterface $input, OutputInterface $output): ?int + { + try { + $this->setupEnvironment($input, $output); + + $backup = $input->getOption('backup'); + $exitCode = ExitCode::SUCCESS; + + if (!$backup) { + if (!$input->isInteractive()) { + throw new InvalidArgumentException("The '--backup' option is required."); + } + + $backup = $this->selectBackupInteractive($input, $output); + + if (!$backup) { + return $exitCode; + } + } + + $this->backupManager->deleteBackup($backup); + $this->logger->info('The backup file has been successfully deleted'); + + $this->logger->debug('Process completed with exit code: ' . $exitCode); + + return $exitCode; + } catch (Exception $e) { + $this->logger->error('An error occurred during the delete backup process'); + throw $e; + } + } +} diff --git a/classes/Commands/ListBackupCommand.php b/classes/Commands/ListBackupCommand.php index a7c3d3456..7a78d8ff7 100644 --- a/classes/Commands/ListBackupCommand.php +++ b/classes/Commands/ListBackupCommand.php @@ -28,16 +28,14 @@ namespace PrestaShop\Module\AutoUpgrade\Commands; use Exception; -use PrestaShop\Module\AutoUpgrade\Backup\BackupFinder; use PrestaShop\Module\AutoUpgrade\Exceptions\BackupException; use PrestaShop\Module\AutoUpgrade\Task\ExitCode; -use PrestaShop\Module\AutoUpgrade\UpgradeContainer; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class ListBackupCommand extends AbstractCommand +class ListBackupCommand extends AbstractBackupCommand { /** @var string */ protected static $defaultName = 'backup:list'; @@ -56,11 +54,9 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): ?int { try { - $this->setupContainer($input, $output); + $this->setupEnvironment($input, $output); - $backupPath = $this->upgradeContainer->getProperty(UpgradeContainer::BACKUP_PATH); - $backupFinder = new BackupFinder($backupPath); - $backups = $backupFinder->getAvailableBackups(); + $backups = $this->backupFinder->getAvailableBackups(); if (empty($backups)) { $this->logger->info('No store backup files found in your dedicated directory'); @@ -68,7 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output): ?int return ExitCode::SUCCESS; } - $rows = $this->getRows($backupFinder, $backups); + $rows = $this->getRows($backups); $table = new Table($output); $table ->setHeaders(['Date', 'Version', 'File name']) @@ -90,13 +86,13 @@ protected function execute(InputInterface $input, OutputInterface $output): ?int * * @throws BackupException */ - private function getRows(BackupFinder $backupFinder, array $backups): array + private function getRows(array $backups): array { - $rows = array_map(function ($backupName) use ($backupFinder) { - return $backupFinder->parseBackupMetadata($backupName); + $rows = array_map(function ($backupName) { + return $this->backupFinder->parseBackupMetadata($backupName); }, $backups); - $backupFinder->sortBackupsByNewest($rows); + $this->backupFinder->sortBackupsByNewest($rows); foreach ($rows as &$row) { unset($row['timestamp']); diff --git a/classes/Commands/RestoreCommand.php b/classes/Commands/RestoreCommand.php index 8c6b6547e..40a543f0d 100644 --- a/classes/Commands/RestoreCommand.php +++ b/classes/Commands/RestoreCommand.php @@ -29,17 +29,14 @@ use Exception; use InvalidArgumentException; -use PrestaShop\Module\AutoUpgrade\Backup\BackupFinder; -use PrestaShop\Module\AutoUpgrade\Exceptions\BackupException; +use PrestaShop\Module\AutoUpgrade\Task\ExitCode; use PrestaShop\Module\AutoUpgrade\Task\Runner\AllRestoreTasks; -use PrestaShop\Module\AutoUpgrade\UpgradeContainer; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\ChoiceQuestion; -class RestoreCommand extends AbstractCommand +class RestoreCommand extends AbstractBackupCommand { /** * @var string @@ -64,7 +61,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): ?int { try { - $this->setupContainer($input, $output); + $this->setupEnvironment($input, $output); $backup = $input->getOption('backup'); @@ -74,6 +71,10 @@ protected function execute(InputInterface $input, OutputInterface $output): ?int } $backup = $this->selectBackupInteractive($input, $output); + + if (!$backup) { + return ExitCode::SUCCESS; + } } $controller = new AllRestoreTasks($this->upgradeContainer); @@ -90,54 +91,4 @@ protected function execute(InputInterface $input, OutputInterface $output): ?int throw $e; } } - - /** - * @throws Exception - */ - private function selectBackupInteractive(InputInterface $input, OutputInterface $output): string - { - $backupPath = $this->upgradeContainer->getProperty(UpgradeContainer::BACKUP_PATH); - $backupFinder = new BackupFinder($backupPath); - $backups = $backupFinder->getAvailableBackups(); - - if (empty($backups)) { - throw new BackupException('No store backup files found in your dedicated directory'); - } - - $formattedBackups = array_map(function ($backupName) use ($backupFinder) { - return $backupFinder->parseBackupMetadata($backupName); - }, $backups); - - $backupFinder->sortBackupsByNewest($formattedBackups); - - $rows = array_map(function ($backup) { - return $this->formatBackupRow($backup); - }, $formattedBackups); - - $helper = $this->getHelper('question'); - $question = new ChoiceQuestion( - 'Please select your backup:', - $rows - ); - - $answer = $helper->ask($input, $output, $question); - $key = array_search($answer, $rows); - if ($key === false) { - throw new BackupException('Invalid backup selection.'); - } - - return $formattedBackups[$key]['filename']; - } - - /** - * Formats a backup row for display in the selection prompt. - * - * @param array{datetime: string, version:string, filename: string} $backups - * - * @return string - */ - private function formatBackupRow(array $backups): string - { - return sprintf('Date: %s, Version: %s, File name: %s', $backups['datetime'], $backups['version'], $backups['filename']); - } } diff --git a/classes/Commands/UpdateCommand.php b/classes/Commands/UpdateCommand.php index a8defb1fe..32fb32582 100644 --- a/classes/Commands/UpdateCommand.php +++ b/classes/Commands/UpdateCommand.php @@ -75,7 +75,7 @@ protected function execute(InputInterface $input, OutputInterface $output): ?int } try { - $this->setupContainer($input, $output); + $this->setupEnvironment($input, $output); // in the case of commands containing the update status, it is not necessary to update the configuration // also we do not want to repeat the update of the config in the recursive commands diff --git a/classes/Task/Miscellaneous/UpdateConfig.php b/classes/Task/Miscellaneous/UpdateConfig.php index 304cc2bfa..89749498e 100644 --- a/classes/Task/Miscellaneous/UpdateConfig.php +++ b/classes/Task/Miscellaneous/UpdateConfig.php @@ -165,7 +165,7 @@ private function writeConfig(array $config): bool $classConfig = $this->container->getUpgradeConfiguration(); $classConfig->merge($config); - $this->logger->info($this->translator->trans('Configuration successfully updated.') . ' ' . $this->translator->trans('This page will now be reloaded and the module will check if a new version is available.') . ''); + $this->logger->info($this->translator->trans('Configuration successfully updated.')); $this->container->getLogger()->debug('Configuration update: ' . json_encode($classConfig->toArray(), JSON_PRETTY_PRINT));