Update ls_window since we changed ls output to use live stdout, which is too slow

This commit is contained in:
Orsiris de Jong 2024-01-04 00:19:54 +01:00
parent 5441c82808
commit 2229cec1d7
5 changed files with 60 additions and 52 deletions

View file

@ -47,6 +47,7 @@ from npbackup.customization import (
from npbackup.gui.config import config_gui from npbackup.gui.config import config_gui
from npbackup.gui.operations import operations_gui from npbackup.gui.operations import operations_gui
from npbackup.gui.helpers import get_anon_repo_uri, gui_thread_runner from npbackup.gui.helpers import get_anon_repo_uri, gui_thread_runner
from npbackup.gui.notification import display_notification
from npbackup.core.i18n_helper import _t from npbackup.core.i18n_helper import _t
from npbackup.core.upgrade_runner import run_upgrade, check_new_version from npbackup.core.upgrade_runner import run_upgrade, check_new_version
from npbackup.path_helper import CURRENT_DIR from npbackup.path_helper import CURRENT_DIR
@ -180,9 +181,6 @@ def _make_treedata_from_json(ls_result: List[dict]) -> sg.TreeData:
""" """
treedata = sg.TreeData() treedata = sg.TreeData()
count = 0 count = 0
# First entry of list of list should be the snapshot description and can be discarded
# Since we use an iter now, first result was discarded by ls_window function already
# ls_result.pop(0)
for entry in ls_result: for entry in ls_result:
# Make sure we drop the prefix '/' so sg.TreeData does not get an empty root # Make sure we drop the prefix '/' so sg.TreeData does not get an empty root
entry["path"] = entry["path"].lstrip("/") entry["path"] = entry["path"].lstrip("/")
@ -224,38 +222,35 @@ def _make_treedata_from_json(ls_result: List[dict]) -> sg.TreeData:
def ls_window(repo_config: dict, snapshot_id: str) -> bool: def ls_window(repo_config: dict, snapshot_id: str) -> bool:
result = gui_thread_runner( result = gui_thread_runner(
repo_config, "ls", snapshot=snapshot_id, __autoclose=True, __compact=True repo_config, "ls", snapshot=snapshot_id, __stdout=False, __autoclose=True, __compact=True
) )
if not result["result"]: if not result["result"]:
sg.Popup("main_gui.snapshot_is_empty")
return None, None return None, None
# result is {"result": True, "output": [{snapshot_description}, {entry}, {entry}]}
snapshot_content = result["output"] content = result["output"]
try: # First entry of snapshot list is the snapshot description
# Since ls returns an iter now, we need to use next snapshot = content.pop(0)
snapshot = next(snapshot_content)
# Exception that happens when restic cannot successfully get snapshot content
except StopIteration:
return None, None
try: try:
snap_date = dateutil.parser.parse(snapshot["time"]) snap_date = dateutil.parser.parse(snapshot["time"])
except (KeyError, IndexError): except (KeyError, IndexError, TypeError):
snap_date = "[inconnu]" snap_date = "[inconnu]"
try: try:
short_id = snapshot["short_id"] short_id = snapshot["short_id"]
except (KeyError, IndexError): except (KeyError, IndexError, TypeError):
short_id = "[inconnu]" short_id = None
try: try:
username = snapshot["username"] username = snapshot["username"]
except (KeyError, IndexError): except (KeyError, IndexError, TypeError):
username = "[inconnu]" username = "[inconnu]"
try: try:
hostname = snapshot["hostname"] hostname = snapshot["hostname"]
except (KeyError, IndexError): except (KeyError, IndexError, TypeError):
hostname = "[inconnu]" hostname = "[inconnu]"
backup_id = f"{_t('main_gui.backup_content_from')} {snap_date} {_t('main_gui.run_as')} {username}@{hostname} {_t('main_gui.identified_by')} {short_id}" backup_id = f"{_t('main_gui.backup_content_from')} {snap_date} {_t('main_gui.run_as')} {username}@{hostname} {_t('main_gui.identified_by')} {short_id}"
if not backup_id or not snapshot_content: if not backup_id or not snapshot or not short_id:
sg.PopupError(_t("main_gui.cannot_get_content"), keep_on_top=True) sg.PopupError(_t("main_gui.cannot_get_content"), keep_on_top=True)
return False return False
@ -265,7 +260,7 @@ def ls_window(repo_config: dict, snapshot_id: str) -> bool:
# We get a thread result, hence pylint will complain the thread isn't a tuple # We get a thread result, hence pylint will complain the thread isn't a tuple
# pylint: disable=E1101 (no-member) # pylint: disable=E1101 (no-member)
thread = _make_treedata_from_json(snapshot_content) thread = _make_treedata_from_json(content)
while not thread.done() and not thread.cancelled(): while not thread.done() and not thread.cancelled():
sg.PopupAnimated( sg.PopupAnimated(
LOADER_ANIMATION, LOADER_ANIMATION,
@ -773,7 +768,7 @@ def _main_gui(viewer_mode: bool):
backup(repo_config) backup(repo_config)
event = "--STATE-BUTTON--" event = "--STATE-BUTTON--"
if event == "--SEE-CONTENT--": if event == "--SEE-CONTENT--":
if not full_config: if not repo_config:
sg.PopupError(_t("main_gui.no_config")) sg.PopupError(_t("main_gui.no_config"))
continue continue
if not values["snapshot-list"]: if not values["snapshot-list"]:

View file

@ -77,6 +77,7 @@ def gui_thread_runner(
__compact: bool = True, __compact: bool = True,
__autoclose: bool = False, __autoclose: bool = False,
__gui_msg: str = "", __gui_msg: str = "",
__stdout: bool = True,
*args, *args,
**kwargs, **kwargs,
): ):
@ -105,16 +106,17 @@ def gui_thread_runner(
if __repo_config: if __repo_config:
runner.repo_config = __repo_config runner.repo_config = __repo_config
stdout_queue = queue.Queue() if __stdout:
stdout_queue = queue.Queue()
runner.stdout = stdout_queue
stderr_queue = queue.Queue() stderr_queue = queue.Queue()
runner.stderr = stderr_queue
fn = getattr(runner, __fn_name) fn = getattr(runner, __fn_name)
logger.debug( logger.debug(
f"gui_thread_runner runs {fn.__name__} {'with' if USE_THREADING else 'without'} threads" f"gui_thread_runner runs {fn.__name__} {'with' if USE_THREADING else 'without'} threads"
) )
runner.stdout = stdout_queue
runner.stderr = stderr_queue
stderr_has_messages = False stderr_has_messages = False
if not __gui_msg: if not __gui_msg:
__gui_msg = "Operation" __gui_msg = "Operation"
@ -191,6 +193,7 @@ def gui_thread_runner(
_t("generic.close"), _t("generic.close"),
key="--EXIT--", key="--EXIT--",
button_color=(TXT_COLOR_LDR, BG_COLOR_LDR), button_color=(TXT_COLOR_LDR, BG_COLOR_LDR),
disabled=True
) )
], ],
] ]
@ -212,13 +215,14 @@ def gui_thread_runner(
use_custom_titlebar=True, use_custom_titlebar=True,
grab_anywhere=True, grab_anywhere=True,
keep_on_top=True, keep_on_top=True,
disable_close=True, # Don't allow closing this window via "X" since we still need to update it
background_color=BG_COLOR_LDR, background_color=BG_COLOR_LDR,
titlebar_icon=OEM_ICON, titlebar_icon=OEM_ICON,
) )
# Finalize the window # Finalize the window
event, values = progress_window.read(timeout=0.01) event, values = progress_window.read(timeout=0.01)
read_stdout_queue = True read_stdout_queue = __stdout
read_stderr_queue = True read_stderr_queue = True
read_queues = True read_queues = True
if USE_THREADING: if USE_THREADING:
@ -237,36 +241,38 @@ def gui_thread_runner(
if event == "--EXPAND--": if event == "--EXPAND--":
_upgrade_from_compact_view() _upgrade_from_compact_view()
# Read stdout queue # Read stdout queue
try: if read_stdout_queue:
stdout_data = stdout_queue.get(timeout=GUI_CHECK_INTERVAL) try:
except queue.Empty: stdout_data = stdout_queue.get(timeout=GUI_CHECK_INTERVAL)
pass except queue.Empty:
else: pass
if stdout_data is None:
logger.debug("gui_thread_runner got stdout queue close signal")
read_stdout_queue = False
else: else:
progress_window["-OPERATIONS-PROGRESS-STDOUT-"].Update( if stdout_data is None:
f"\n{stdout_data}", append=True logger.debug("gui_thread_runner got stdout queue close signal")
) read_stdout_queue = False
else:
progress_window["-OPERATIONS-PROGRESS-STDOUT-"].Update(
f"\n{stdout_data}", append=True
)
# Read stderr queue # Read stderr queue
try: if read_stderr_queue:
stderr_data = stderr_queue.get(timeout=GUI_CHECK_INTERVAL) try:
except queue.Empty: stderr_data = stderr_queue.get(timeout=GUI_CHECK_INTERVAL)
pass except queue.Empty:
else: pass
if stderr_data is None:
logger.debug("gui_thread_runner got stderr queue close signal")
read_stderr_queue = False
else: else:
stderr_has_messages = True if stderr_data is None:
# if __compact: logger.debug("gui_thread_runner got stderr queue close signal")
# for key in progress_window.AllKeysDict: read_stderr_queue = False
# progress_window[key].Update(visible=True) else:
progress_window["-OPERATIONS-PROGRESS-STDERR-"].Update( stderr_has_messages = True
f"\n{stderr_data}", append=True # if __compact:
) # for key in progress_window.AllKeysDict:
# progress_window[key].Update(visible=True)
progress_window["-OPERATIONS-PROGRESS-STDERR-"].Update(
f"\n{stderr_data}", append=True
)
read_queues = read_stdout_queue or read_stderr_queue read_queues = read_stdout_queue or read_stderr_queue
@ -280,6 +286,7 @@ def gui_thread_runner(
# Make sure we will keep the window visible since we have errors # Make sure we will keep the window visible since we have errors
__autoclose = False __autoclose = False
progress_window["--EXIT--"].Update(disabled=False)
# Keep the window open until user has done something # Keep the window open until user has done something
progress_window["-LOADER-ANIMATION-"].Update(visible=False) progress_window["-LOADER-ANIMATION-"].Update(visible=False)
if not __autoclose or stderr_has_messages: if not __autoclose or stderr_has_messages:

View file

@ -586,7 +586,10 @@ class ResticRunner:
output_is_list = False output_is_list = False
for line in output: for line in output:
if output_is_list: if output_is_list:
js["output"].append(line) try:
js["output"].append(json.loads(line))
except json.decoder.JSONDecodeError:
js["output"].append(line)
else: else:
try: try:
js["output"] = json.loads(line) js["output"] = json.loads(line)

View file

@ -43,6 +43,8 @@ en:
config_error: Configuration error config_error: Configuration error
no_config: Please load / create a configuration before proceeding no_config: Please load / create a configuration before proceeding
snapshot_is_empty: Snapshot is empty
# logs # logs
last_messages: Last messages last_messages: Last messages
error_messages: Error messages error_messages: Error messages

View file

@ -43,6 +43,7 @@ fr:
config_error: Erreur de configuration config_error: Erreur de configuration
no_config: Veuillez charger / créer une configuration avant de procéder no_config: Veuillez charger / créer une configuration avant de procéder
snapshot_is_empty: L'instantané est vide
# logs # logs
last_messages: Last messages last_messages: Last messages
error_messages: Error messages error_messages: Error messages