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.operations import operations_gui
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.upgrade_runner import run_upgrade, check_new_version
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()
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:
# Make sure we drop the prefix '/' so sg.TreeData does not get an empty root
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:
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"]:
sg.Popup("main_gui.snapshot_is_empty")
return None, None
snapshot_content = result["output"]
try:
# Since ls returns an iter now, we need to use next
snapshot = next(snapshot_content)
# Exception that happens when restic cannot successfully get snapshot content
except StopIteration:
return None, None
# result is {"result": True, "output": [{snapshot_description}, {entry}, {entry}]}
content = result["output"]
# First entry of snapshot list is the snapshot description
snapshot = content.pop(0)
try:
snap_date = dateutil.parser.parse(snapshot["time"])
except (KeyError, IndexError):
except (KeyError, IndexError, TypeError):
snap_date = "[inconnu]"
try:
short_id = snapshot["short_id"]
except (KeyError, IndexError):
short_id = "[inconnu]"
except (KeyError, IndexError, TypeError):
short_id = None
try:
username = snapshot["username"]
except (KeyError, IndexError):
except (KeyError, IndexError, TypeError):
username = "[inconnu]"
try:
hostname = snapshot["hostname"]
except (KeyError, IndexError):
except (KeyError, IndexError, TypeError):
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}"
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)
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
# 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():
sg.PopupAnimated(
LOADER_ANIMATION,
@ -773,7 +768,7 @@ def _main_gui(viewer_mode: bool):
backup(repo_config)
event = "--STATE-BUTTON--"
if event == "--SEE-CONTENT--":
if not full_config:
if not repo_config:
sg.PopupError(_t("main_gui.no_config"))
continue
if not values["snapshot-list"]:

View file

@ -77,6 +77,7 @@ def gui_thread_runner(
__compact: bool = True,
__autoclose: bool = False,
__gui_msg: str = "",
__stdout: bool = True,
*args,
**kwargs,
):
@ -105,16 +106,17 @@ def gui_thread_runner(
if __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()
runner.stderr = stderr_queue
fn = getattr(runner, __fn_name)
logger.debug(
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
if not __gui_msg:
__gui_msg = "Operation"
@ -191,6 +193,7 @@ def gui_thread_runner(
_t("generic.close"),
key="--EXIT--",
button_color=(TXT_COLOR_LDR, BG_COLOR_LDR),
disabled=True
)
],
]
@ -212,13 +215,14 @@ def gui_thread_runner(
use_custom_titlebar=True,
grab_anywhere=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,
titlebar_icon=OEM_ICON,
)
# Finalize the window
event, values = progress_window.read(timeout=0.01)
read_stdout_queue = True
read_stdout_queue = __stdout
read_stderr_queue = True
read_queues = True
if USE_THREADING:
@ -237,36 +241,38 @@ def gui_thread_runner(
if event == "--EXPAND--":
_upgrade_from_compact_view()
# Read stdout queue
try:
stdout_data = stdout_queue.get(timeout=GUI_CHECK_INTERVAL)
except queue.Empty:
pass
else:
if stdout_data is None:
logger.debug("gui_thread_runner got stdout queue close signal")
read_stdout_queue = False
if read_stdout_queue:
try:
stdout_data = stdout_queue.get(timeout=GUI_CHECK_INTERVAL)
except queue.Empty:
pass
else:
progress_window["-OPERATIONS-PROGRESS-STDOUT-"].Update(
f"\n{stdout_data}", append=True
)
if stdout_data is None:
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
try:
stderr_data = stderr_queue.get(timeout=GUI_CHECK_INTERVAL)
except queue.Empty:
pass
else:
if stderr_data is None:
logger.debug("gui_thread_runner got stderr queue close signal")
read_stderr_queue = False
if read_stderr_queue:
try:
stderr_data = stderr_queue.get(timeout=GUI_CHECK_INTERVAL)
except queue.Empty:
pass
else:
stderr_has_messages = 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
)
if stderr_data is None:
logger.debug("gui_thread_runner got stderr queue close signal")
read_stderr_queue = False
else:
stderr_has_messages = 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
@ -280,6 +286,7 @@ def gui_thread_runner(
# Make sure we will keep the window visible since we have errors
__autoclose = False
progress_window["--EXIT--"].Update(disabled=False)
# Keep the window open until user has done something
progress_window["-LOADER-ANIMATION-"].Update(visible=False)
if not __autoclose or stderr_has_messages:

View file

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

View file

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

View file

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