diff --git a/borgmatic/actions/browse/archive.py b/borgmatic/actions/browse/archive.py index f64b85a1..5e3cc8f8 100644 --- a/borgmatic/actions/browse/archive.py +++ b/borgmatic/actions/browse/archive.py @@ -1,5 +1,6 @@ import argparse import collections +import enum import json import logging import os @@ -15,6 +16,14 @@ import binaryornot.helpers logger = logging.getLogger(__name__) +class Path_type(enum.Enum): + DIRECTORY = 'd' + LINK = 'l' + PIPE = 'p' + FILE = '-' + + +# A data structure capturing a path stored in a Borg archive. Archive_path = collections.namedtuple( 'Archive_path', ('path_type', 'file_path', 'link_target'), diff --git a/borgmatic/actions/browse/archives_list.py b/borgmatic/actions/browse/archives_list.py index 01c0febf..0e8f8159 100644 --- a/borgmatic/actions/browse/archives_list.py +++ b/borgmatic/actions/browse/archives_list.py @@ -6,7 +6,6 @@ import textual.widgets import borgmatic.actions.browse.bindings import borgmatic.actions.browse.loading -import borgmatic.actions.browse.paths import borgmatic.actions.browse.workers diff --git a/borgmatic/actions/browse/carousel.py b/borgmatic/actions/browse/carousel.py index 2b3f2580..6c5bdec9 100644 --- a/borgmatic/actions/browse/carousel.py +++ b/borgmatic/actions/browse/carousel.py @@ -3,11 +3,12 @@ import os import textual.binding import textual.containers +import borgmatic.actions.browse.archive import borgmatic.actions.browse.archives_list import borgmatic.actions.browse.directory_list import borgmatic.actions.browse.configuration_files_list import borgmatic.actions.browse.file_preview -import borgmatic.actions.browse.paths +import borgmatic.actions.browse.icons import borgmatic.actions.browse.repositories_list @@ -41,8 +42,8 @@ def make_next_panel(focused_panel, option_id): option = focused_panel.get_option(option_id) if option.prompt.startswith( - borgmatic.actions.browse.paths.PATH_TYPE_ICONS[ - borgmatic.actions.browse.paths.Path_type.DIRECTORY.value + borgmatic.actions.browse.icons.PATH_TYPE_ICONS[ + borgmatic.actions.browse.archive.Path_type.DIRECTORY.value ] ): return borgmatic.actions.browse.directory_list.Directory_list( @@ -53,8 +54,8 @@ def make_next_panel(focused_panel, option_id): path_components=(*focused_panel.path_components, option_id), ) elif option.prompt.startswith( - borgmatic.actions.browse.paths.PATH_TYPE_ICONS[ - borgmatic.actions.browse.paths.Path_type.FILE.value + borgmatic.actions.browse.icons.PATH_TYPE_ICONS[ + borgmatic.actions.browse.archive.Path_type.FILE.value ] ): return borgmatic.actions.browse.file_preview.File_preview( diff --git a/borgmatic/actions/browse/configuration_files_list.py b/borgmatic/actions/browse/configuration_files_list.py index 4d7d1a2f..c6da1390 100644 --- a/borgmatic/actions/browse/configuration_files_list.py +++ b/borgmatic/actions/browse/configuration_files_list.py @@ -6,7 +6,6 @@ import textual.widgets import borgmatic.actions.browse.bindings import borgmatic.actions.browse.loading -import borgmatic.actions.browse.paths import borgmatic.actions.browse.workers diff --git a/borgmatic/actions/browse/directory_list.py b/borgmatic/actions/browse/directory_list.py index 70168c74..3e94c2cc 100644 --- a/borgmatic/actions/browse/directory_list.py +++ b/borgmatic/actions/browse/directory_list.py @@ -4,9 +4,10 @@ import os import textual.binding import textual.widgets +import borgmatic.actions.browse.archive import borgmatic.actions.browse.bindings import borgmatic.actions.browse.loading -import borgmatic.actions.browse.paths +import borgmatic.actions.browse.icons import borgmatic.actions.browse.workers @@ -36,7 +37,7 @@ def get_relative_archive_path_components(archive_path, current_directory_path_co def make_directory_list_option(archive_path, archive_path_components): pieces = ( - borgmatic.actions.browse.paths.PATH_TYPE_ICONS.get( + borgmatic.actions.browse.icons.PATH_TYPE_ICONS.get( archive_path.path_type if len(archive_path_components) == 1 else 'd', '❓' ), archive_path_components[0], @@ -100,8 +101,8 @@ class Directory_list(textual.widgets.OptionList): self.border_title = ' '.join( ( - borgmatic.actions.browse.paths.PATH_TYPE_ICONS[ - borgmatic.actions.browse.paths.Path_type.DIRECTORY.value + borgmatic.actions.browse.icons.PATH_TYPE_ICONS[ + borgmatic.actions.browse.archive.Path_type.DIRECTORY.value ], os.path.sep.join(self.path_components) if self.path_components @@ -112,7 +113,7 @@ class Directory_list(textual.widgets.OptionList): if self.path_components: self.add_option( textual.widgets.option_list.Option( - f'{borgmatic.actions.browse.paths.PATH_TYPE_ICONS[borgmatic.actions.browse.paths.Path_type.DIRECTORY.value]} ..', + f'{borgmatic.actions.browse.icons.PATH_TYPE_ICONS[borgmatic.actions.browse.archive.Path_type.DIRECTORY.value]} ..', id='..', ), ) diff --git a/borgmatic/actions/browse/file_preview.py b/borgmatic/actions/browse/file_preview.py index 3d0ac8e3..b653a4cc 100644 --- a/borgmatic/actions/browse/file_preview.py +++ b/borgmatic/actions/browse/file_preview.py @@ -4,8 +4,9 @@ import os import textual.binding import textual.widgets +import borgmatic.actions.browse.archive import borgmatic.actions.browse.loading -import borgmatic.actions.browse.paths +import borgmatic.actions.browse.icons import borgmatic.actions.browse.workers @@ -35,8 +36,8 @@ class File_preview(textual.widgets.RichLog): super().__init__(classes='panel') self.border_title = ' '.join( ( - borgmatic.actions.browse.paths.PATH_TYPE_ICONS[ - borgmatic.actions.browse.paths.Path_type.FILE.value + borgmatic.actions.browse.icons.PATH_TYPE_ICONS[ + borgmatic.actions.browse.archive.Path_type.FILE.value ], self.file_path, 'preview', diff --git a/borgmatic/actions/browse/icons.py b/borgmatic/actions/browse/icons.py new file mode 100644 index 00000000..2d621d38 --- /dev/null +++ b/borgmatic/actions/browse/icons.py @@ -0,0 +1,9 @@ +import borgmatic.actions.browse.archive + + +PATH_TYPE_ICONS = { + borgmatic.actions.browse.archive.Path_type.DIRECTORY.value: '📁', + borgmatic.actions.browse.archive.Path_type.LINK.value: '🔗', + borgmatic.actions.browse.archive.Path_type.PIPE.value: '🚰', + borgmatic.actions.browse.archive.Path_type.FILE.value: '📄', +} diff --git a/borgmatic/actions/browse/paths.py b/borgmatic/actions/browse/paths.py deleted file mode 100644 index b458ebde..00000000 --- a/borgmatic/actions/browse/paths.py +++ /dev/null @@ -1,16 +0,0 @@ -import enum - - -class Path_type(enum.Enum): - DIRECTORY = 'd' - LINK = 'l' - PIPE = 'p' - FILE = '-' - - -PATH_TYPE_ICONS = { - Path_type.DIRECTORY.value: '📁', - Path_type.LINK.value: '🔗', - Path_type.PIPE.value: '🚰', - Path_type.FILE.value: '📄', -} diff --git a/borgmatic/actions/browse/repositories_list.py b/borgmatic/actions/browse/repositories_list.py index 086d4408..8d01e466 100644 --- a/borgmatic/actions/browse/repositories_list.py +++ b/borgmatic/actions/browse/repositories_list.py @@ -6,7 +6,6 @@ import textual.widgets import borgmatic.actions.browse.bindings import borgmatic.actions.browse.loading -import borgmatic.actions.browse.paths import borgmatic.actions.browse.workers diff --git a/tests/unit/commands/test_borgmatic.py b/tests/unit/commands/test_borgmatic.py index 73ae1a09..69b84168 100644 --- a/tests/unit/commands/test_borgmatic.py +++ b/tests/unit/commands/test_borgmatic.py @@ -2095,6 +2095,44 @@ def test_collect_highlander_action_summary_logs_error_on_run_show_failure(): assert {log.levelno for log in logs} == {logging.CRITICAL} +def test_collect_highlander_action_summary_logs_nothing_additional_for_success_with_browse(): + flexmock(module.borgmatic.actions.browse.run).should_receive('run_browse') + arguments = { + 'browse': flexmock(), + 'global': flexmock(), + } + + logs = tuple( + module.collect_highlander_action_summary_logs( + {'test.yaml': {}}, + arguments=arguments, + configuration_parse_errors=False, + ), + ) + assert not logs + + +def test_collect_highlander_action_summary_logs_error_on_run_browse_failure(): + flexmock(module.borgmatic.actions.browse.run).should_receive('run_browse').and_raise( + ValueError, + ) + arguments = { + 'browse': flexmock(), + 'global': flexmock(), + } + + logs = tuple( + module.collect_highlander_action_summary_logs( + {'test.yaml': {}}, + arguments=arguments, + configuration_parse_errors=False, + ), + ) + + assert {log.levelno for log in logs} == {logging.CRITICAL} + + + def test_collect_configuration_run_summary_logs_info_for_success(): flexmock(module.validate).should_receive('guard_configuration_contains_repository') flexmock(module.command).should_receive('filter_hooks').with_args(