Add new --stdin-from-command functionnality

This commit is contained in:
deajan 2024-09-02 00:23:59 +02:00
parent 415c4fe334
commit 5060d280ca
6 changed files with 90 additions and 26 deletions

View file

@ -7,7 +7,7 @@ __intname__ = "npbackup.configuration"
__author__ = "Orsiris de Jong" __author__ = "Orsiris de Jong"
__copyright__ = "Copyright (C) 2022-2024 NetInvent" __copyright__ = "Copyright (C) 2022-2024 NetInvent"
__license__ = "GPL-3.0-only" __license__ = "GPL-3.0-only"
__build__ = "2024061701" __build__ = "2024090101"
__version__ = "npbackup 3.0.0+" __version__ = "npbackup 3.0.0+"
MIN_CONF_VERSION = 3.0 MIN_CONF_VERSION = 3.0
@ -153,6 +153,7 @@ empty_config_dict = {
"backup_opts": { "backup_opts": {
"paths": [], "paths": [],
"source_type": None, "source_type": None,
"stdin_from_command": None,
"tags": [], "tags": [],
"compression": "auto", "compression": "auto",
"use_fs_snapshot": True, "use_fs_snapshot": True,

View file

@ -1012,8 +1012,9 @@ class NPBackupRunner:
# Possible warnings to add to json output # Possible warnings to add to json output
warnings = [] warnings = []
stdin_from_command = self.repo_config.g("backup_opts.stdin_from_command")
if not read_from_stdin and not stdin_from_command:
# Preflight checks # Preflight checks
if not read_from_stdin:
paths = self.repo_config.g("backup_opts.paths") paths = self.repo_config.g("backup_opts.paths")
if not paths: if not paths:
msg = ( msg = (
@ -1112,7 +1113,17 @@ class NPBackupRunner:
self.restic_runner.verbose = self.verbose self.restic_runner.verbose = self.verbose
# Run backup here # Run backup here
if not read_from_stdin: if stdin_from_command:
self.write_logs(
f"Running backup of given command stdout as name {stdin_filename} to repo {self.repo_config.g('name')}",
level="info"
)
elif stdin_filename:
self.write_logs(
f"Running backup of piped stdin data as name {stdin_filename} to repo {self.repo_config.g('name')}",
level="info",
)
else:
if source_type not in ["folder_list", None]: if source_type not in ["folder_list", None]:
self.write_logs( self.write_logs(
f"Running backup of files in {paths} list to repo {self.repo_config.g('name')}", f"Running backup of files in {paths} list to repo {self.repo_config.g('name')}",
@ -1123,11 +1134,6 @@ class NPBackupRunner:
f"Running backup of {paths} to repo {self.repo_config.g('name')}", f"Running backup of {paths} to repo {self.repo_config.g('name')}",
level="info", level="info",
) )
else:
self.write_logs(
f"Running backup of piped stdin data as name {stdin_filename} to repo {self.repo_config.g('name')}",
level="info",
)
pre_exec_commands_success = True pre_exec_commands_success = True
if pre_exec_commands: if pre_exec_commands:
@ -1149,7 +1155,21 @@ class NPBackupRunner:
level="info", level="info",
) )
if not read_from_stdin: if read_from_stdin:
result = self.restic_runner.backup(
read_from_stdin=read_from_stdin,
stdin_filename=stdin_filename,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
elif stdin_from_command:
result = self.restic_runner.backup(
stdin_from_command=stdin_from_command,
stdin_filename=stdin_filename,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
else:
result = self.restic_runner.backup( result = self.restic_runner.backup(
paths=paths, paths=paths,
source_type=source_type, source_type=source_type,
@ -1163,13 +1183,6 @@ class NPBackupRunner:
tags=tags, tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters, additional_backup_only_parameters=additional_backup_only_parameters,
) )
else:
result = self.restic_runner.backup(
read_from_stdin=read_from_stdin,
stdin_filename=stdin_filename,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
self.write_logs( self.write_logs(
f"Restic output:\n{self.restic_runner.backup_result_content}", level="debug" f"Restic output:\n{self.restic_runner.backup_result_content}", level="debug"

View file

@ -100,6 +100,7 @@ def config_gui(full_config: dict, config_file: str):
"files_from": _t("config_gui.files_from"), "files_from": _t("config_gui.files_from"),
"files_from_verbatim": _t("config_gui.files_from_verbatim"), "files_from_verbatim": _t("config_gui.files_from_verbatim"),
"files_from_raw": _t("config_gui.files_from_raw"), "files_from_raw": _t("config_gui.files_from_raw"),
"stdin_from_command": _t("config_gui.stdin_from_command"),
}, },
"backup_opts.priority": { "backup_opts.priority": {
"low": _t("config_gui.low"), "low": _t("config_gui.low"),
@ -847,6 +848,7 @@ def config_gui(full_config: dict, config_file: str):
list(combo_boxes["backup_opts.source_type"].values()), list(combo_boxes["backup_opts.source_type"].values()),
key="backup_opts.source_type", key="backup_opts.source_type",
size=(48, 1), size=(48, 1),
enable_events=True,
), ),
], ],
[ [
@ -859,12 +861,24 @@ def config_gui(full_config: dict, config_file: str):
expand_y=True, expand_y=True,
) )
], ],
[
sg.Text(_t("config_gui.stdin_from_command"))
],
[
sg.Image(
NON_INHERITED_ICON,
key="inherited.backup_opts.stdin_from_command",
tooltip=_t("config_gui.group_inherited"),
pad=1,
),
sg.Input(key="backup_opts.stdin_from_command", size=(100, 1)),
],
[ [
sg.Input(visible=False, key="--ADD-PATHS-FILE--", enable_events=True), sg.Input(visible=False, key="--ADD-PATHS-FILE--", enable_events=True),
sg.FilesBrowse(_t("generic.add_files"), target="--ADD-PATHS-FILE--"), sg.FilesBrowse(_t("generic.add_files"), target="--ADD-PATHS-FILE--", key="--ADD-PATHS-FILE-BUTTON--"),
sg.Input(visible=False, key="--ADD-PATHS-FOLDER--", enable_events=True), sg.Input(visible=False, key="--ADD-PATHS-FOLDER--", enable_events=True),
sg.FolderBrowse( sg.FolderBrowse(
_t("generic.add_folder"), target="--ADD-PATHS-FOLDER--" _t("generic.add_folder"), target="--ADD-PATHS-FOLDER--", key="--ADD-PATHS-FOLDER-BUTTON--"
), ),
sg.Button(_t("generic.add_manually"), key="--ADD-PATHS-MANUALLY--"), sg.Button(_t("generic.add_manually"), key="--ADD-PATHS-MANUALLY--"),
sg.Button(_t("generic.remove_selected"), key="--REMOVE-PATHS--"), sg.Button(_t("generic.remove_selected"), key="--REMOVE-PATHS--"),
@ -2098,6 +2112,30 @@ Google Cloud storage: GOOGLE_PROJECT_ID GOOGLE_APPLICATION_CREDENTIALS\n\
) )
update_global_gui(full_config, unencrypted=False) update_global_gui(full_config, unencrypted=False)
continue continue
if event == "backup_opts.source_type":
value = get_key_from_value(combo_boxes["backup_opts.source_type"], values["backup_opts.source_type"])
if value == "stdin_from_command":
window["backup_opts.paths"].update(visible=False)
window["--ADD-PATHS-FILE-BUTTON--"].update(disabled=True)
window["--ADD-PATHS-FOLDER-BUTTON--"].update(disabled=True)
window["--ADD-PATHS-MANUALLY--"].update(disabled=True)
window["--REMOVE-PATHS--"].update(disabled=True)
window["backup_opts.stdin_from_command"].update(disabled=False)
elif value == "folder_list":
window["backup_opts.paths"].update(visible=True)
window["--ADD-PATHS-FILE-BUTTON--"].update(disabled=False)
window["--ADD-PATHS-FOLDER-BUTTON--"].update(disabled=False)
window["--ADD-PATHS-MANUALLY--"].update(disabled=False)
window["--REMOVE-PATHS--"].update(disabled=False)
window["backup_opts.stdin_from_command"].update(disabled=True)
elif value in ("files_from", "files_from_verbatim", "files_from_raw"):
window["backup_opts.paths"].update(visible=True)
window["--ADD-PATHS-FILE-BUTTON--"].update(disabled=False)
window["--ADD-PATHS-FOLDER-BUTTON--"].update(disabled=True)
window["--ADD-PATHS-MANUALLY--"].update(disabled=False)
window["--REMOVE-PATHS--"].update(disabled=False)
window["backup_opts.stdin_from_command"].update(disabled=True)
continue
if event in ( if event in (
"--ADD-PATHS-FILE--", "--ADD-PATHS-FILE--",
"--ADD-PATHS-FOLDER--", "--ADD-PATHS-FOLDER--",

View file

@ -295,7 +295,7 @@ class ResticRunner:
if self.additional_parameters if self.additional_parameters
else "" else ""
) )
_cmd = f'"{self._binary}" {additional_parameters}{cmd}{self.generic_arguments}' _cmd = f'"{self._binary}"{additional_parameters}{self.generic_arguments} {cmd}'
self._executor_running = True self._executor_running = True
self.write_logs(f"Running command: [{_cmd}]", level="debug") self.write_logs(f"Running command: [{_cmd}]", level="debug")
@ -781,6 +781,7 @@ class ResticRunner:
tags: List[str] = [], tags: List[str] = [],
one_file_system: bool = False, one_file_system: bool = False,
read_from_stdin: bool = False, read_from_stdin: bool = False,
stdin_from_command: str = None,
stdin_filename: str = "stdin.data", stdin_filename: str = "stdin.data",
additional_backup_only_parameters: str = None, additional_backup_only_parameters: str = None,
) -> Union[bool, str, dict]: ) -> Union[bool, str, dict]:
@ -790,11 +791,9 @@ class ResticRunner:
kwargs = locals() kwargs = locals()
kwargs.pop("self") kwargs.pop("self")
if read_from_stdin: cmd = "backup"
cmd = "backup --stdin"
if stdin_filename: if not read_from_stdin and not stdin_from_command:
cmd += f' --stdin-filename "{stdin_filename}"'
else:
# Handle various source types # Handle various source types
if source_type in [ if source_type in [
"files_from", "files_from",
@ -883,6 +882,8 @@ class ResticRunner:
"Parameter --use-fs-snapshot was given, which is only compatible with Windows", "Parameter --use-fs-snapshot was given, which is only compatible with Windows",
level="warning", level="warning",
) )
for tag in tags: for tag in tags:
if tag: if tag:
tag = tag.strip() tag = tag.strip()
@ -890,6 +891,15 @@ class ResticRunner:
if additional_backup_only_parameters: if additional_backup_only_parameters:
cmd += " {}".format(additional_backup_only_parameters) cmd += " {}".format(additional_backup_only_parameters)
if read_from_stdin:
cmd += " --stdin"
if stdin_filename:
cmd += f' --stdin-filename "{stdin_filename}"'
if stdin_from_command:
if stdin_filename:
cmd += f' --stdin-filename "{stdin_filename}"'
cmd += f" --stdin-from-command -- {stdin_from_command}"
# Run backup without json output, as we could not compute the cloud errors in json output via regexes # Run backup without json output, as we could not compute the cloud errors in json output via regexes
json_output = self.json_output json_output = self.json_output
self.json_output = False self.json_output = False

View file

@ -108,6 +108,7 @@ en:
files_from: From file files_from: From file
files_from_verbatim: From verbatim files_from_verbatim: From verbatim
files_from_raw: From raw files_from_raw: From raw
stdin_from_command: Standard input from command
# retention policiy # retention policiy
retention_policy: Retention policy retention_policy: Retention policy

View file

@ -109,6 +109,7 @@ fr:
files_from: Liste depuis un fichier files_from: Liste depuis un fichier
files_from_verbatim: Liste depuis un fichier "exact" files_from_verbatim: Liste depuis un fichier "exact"
files_from_raw: Liste depuis un fichier "raw" files_from_raw: Liste depuis un fichier "raw"
stdin_from_command: Entrée standard depuis une commande
# retention policy # retention policy
retention_policy: Politique de rétention retention_policy: Politique de rétention