diff --git a/npbackup/configuration.py b/npbackup/configuration.py index 0c712db..825a82b 100644 --- a/npbackup/configuration.py +++ b/npbackup/configuration.py @@ -157,6 +157,7 @@ empty_config_dict = { "exclude_files_larger_than": None, # allows BytesConverter units "additional_parameters": None, "additional_backup_only_parameters": None, + "additional_restore_only_parameters": None, "minimum_backup_size_error": "10 MiB", # allows BytesConverter units "pre_exec_commands": [], "pre_exec_per_command_timeout": 3600, diff --git a/npbackup/core/runner.py b/npbackup/core/runner.py index 187d51a..51baaa6 100644 --- a/npbackup/core/runner.py +++ b/npbackup/core/runner.py @@ -7,7 +7,7 @@ __intname__ = "npbackup.gui.core.runner" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2022-2025 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2025030601" +__build__ = "2025040901" from typing import Optional, Callable, Union, List, Tuple @@ -1594,10 +1594,35 @@ class NPBackupRunner: @apply_config_to_restic_runner def restore(self, snapshot: str, target: str, restore_includes: List[str]) -> bool: self.write_logs(f"Launching restore to {target}", level="info") + + additional_restore_only_parameters = None + try: + if self.repo_config.g("backup_opts.additional_restore_only_parameters"): + additional_restore_only_parameters = self.repo_config.g( + "backup_opts.additional_restore_only_parameters" + ) + try: + additional_restore_only_parameters = os.path.expanduser( + additional_restore_only_parameters + ) + additional_restore_only_parameters = os.path.expandvars( + additional_restore_only_parameters + ) + except OSError: + self.write_logs( + f"Failed expansion for additional backup parameters: {additional_restore_only_parameters}", + level="error", + ) + except KeyError: + pass + except ValueError: + self.write_logs("Bogus additional backup parameters given", level="warning") + return self.restic_runner.restore( snapshot=snapshot, target=target, includes=restore_includes, + additional_restore_only_parameters=additional_restore_only_parameters, ) @threaded diff --git a/npbackup/gui/config.py b/npbackup/gui/config.py index 3c15c55..3c8efd8 100644 --- a/npbackup/gui/config.py +++ b/npbackup/gui/config.py @@ -1197,6 +1197,22 @@ def config_gui(full_config: dict, config_file: str): key="backup_opts.additional_backup_only_parameters", size=(100, 1) ), ], + [ + sg.Text( + _t("config_gui.additional_restore_only_parameters"), size=(40, 1) + ), + ], + [ + sg.Image( + NON_INHERITED_ICON, + key="inherited.backup_opts.additional_restore_only_parameters", + tooltip=_t("config_gui.group_inherited"), + pad=1, + ), + sg.Input( + key="backup_opts.additional_restore_only_parameters", size=(100, 1) + ), + ], ] exclusions_col = [ diff --git a/npbackup/restic_wrapper/__init__.py b/npbackup/restic_wrapper/__init__.py index 493ac63..b17778c 100644 --- a/npbackup/restic_wrapper/__init__.py +++ b/npbackup/restic_wrapper/__init__.py @@ -7,8 +7,8 @@ __intname__ = "npbackup.restic_wrapper" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2022-2025 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2025040401" -__version__ = "2.5.0" +__build__ = "2025040901" +__version__ = "2.6.0" from typing import Tuple, List, Optional, Callable, Union @@ -1163,7 +1163,10 @@ class ResticRunner: @check_if_init def restore( - self, snapshot: str, target: str, includes: List[str] = None + self, snapshot: str, + target: str, + includes: List[str] = None, + additional_restore_only_parameters: Optional[str] = None, ) -> Union[bool, str, dict]: """ Restore given snapshot to directory @@ -1175,11 +1178,14 @@ class ResticRunner: # Always use case ignore excludes under windows if os.name == "nt": case_ignore_param = "i" - cmd = 'restore "{}" --target "{}"'.format(snapshot, target) + cmd = f'restore' + if additional_restore_only_parameters: + cmd += f" {additional_restore_only_parameters}" + cmd += f'" {snapshot}" --target "{target}"' if includes: for include in includes: if include: - cmd += ' --{}include "{}"'.format(case_ignore_param, include) + cmd += f' --{case_ignore_param}include "{include}"' result, output = self.executor(cmd) if result: msg = "Successfully restored data" diff --git a/npbackup/translations/config_gui.en.yml b/npbackup/translations/config_gui.en.yml index 9bf607d..01e5ee2 100644 --- a/npbackup/translations/config_gui.en.yml +++ b/npbackup/translations/config_gui.en.yml @@ -29,6 +29,7 @@ en: backup_priority: Backup priority additional_parameters: Additional parameters additional_backup_only_parameters: Additional backup only parameters + additional_restore_only_parameters: Additional restore only parameters minimum_backup_age: Minimum delay between two backups backup_repo_uri: backup repo URI / path diff --git a/npbackup/translations/config_gui.fr.yml b/npbackup/translations/config_gui.fr.yml index 3841556..4d3a784 100644 --- a/npbackup/translations/config_gui.fr.yml +++ b/npbackup/translations/config_gui.fr.yml @@ -30,6 +30,7 @@ fr: backup_priority: Priorité de sauvegarde additional_parameters: Paramètres supplémentaires additional_backup_only_parameters: Paramètres supplémentaires de sauvegarde + additional_restore_only_parameters: Paramètres supplémentaires de restauration minimum_backup_age: Délai minimal entre deux sauvegardes backup_repo_uri: URI / chemin local dépot de sauvegarde @@ -123,7 +124,7 @@ fr: hourly: instantanés horaires daily: instantanés journalières weekly: instantanés hebdomadaires - monthly: instantanés mensuelles + monthly: instantanés mensuellesf yearly: instantanés annuelles keep_within: Garder les instantanées dans une période relative au dernier instantané keep_tags: Garder les instantanés avec les tags suivants