Browse action MVC refactoring into multiple files.

This commit is contained in:
Dan Helfman
2026-05-14 22:53:59 -07:00
parent e339ce2fd1
commit 1286ccce46
4 changed files with 135 additions and 127 deletions
+61
View File
@@ -0,0 +1,61 @@
import argparse
import json
import logging
import borgmatic.borg.repo_list
import borgmatic.borg.version
logger = logging.getLogger(__name__)
def get_repository_archives(config, repository):
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
logger.answer('Listing repository')
repo_list_arguments = argparse.Namespace(
repository=repository['path'],
short=None,
format=None,
json=True,
prefix=None,
match_archives=None,
sort_by=None,
first=None,
last=None,
)
global_arguments = argparse.Namespace()
local_path = config.get('local_path', 'borg')
remote_path = config.get('remote_path')
local_borg_version = borgmatic.borg.version.local_borg_version(config, local_path)
return json.loads(
borgmatic.borg.repo_list.list_repository(
repository['path'],
config,
local_borg_version,
repo_list_arguments,
global_arguments,
local_path,
remote_path,
)
)
def get_archive_files(config, repository, archive):
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
logger.answer(f"Listing archive {archive['archive']}")
global_arguments = argparse.Namespace()
local_path = config.get('local_path', 'borg')
remote_path = config.get('remote_path')
local_borg_version = borgmatic.borg.version.local_borg_version(config, local_path)
return borgmatic.borg.list.capture_archive_listing(
repository['path'],
archive['archive'],
config,
local_borg_version,
global_arguments,
local_path=local_path,
remote_path=remote_path,
)
@@ -1,16 +1,10 @@
import argparse
import contextlib
import enum
import functools
import json
import os
import logging
import borgmatic.actions.pattern
import borgmatic.borg.diff
import borgmatic.borg.repo_list
import borgmatic.borg.version
import borgmatic.logger
import borgmatic.actions.browse.controller
import rich.text
import textual._context
@@ -19,8 +13,6 @@ import textual.binding
import textual.reactive
import textual.widgets
logger = logging.getLogger(__name__)
class Node_type(enum.Enum):
CONFIGURATION = 0
@@ -50,37 +42,9 @@ PATH_TYPE_EXPANDED_ICONS = {Node_type.DIRECTORY: '📂'}
@textual.work(thread=True)
async def get_repository_archives(browse_tree, repository_node, config, repository, timer):
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
logger.answer('Listing repository')
repo_list_arguments = argparse.Namespace(
repository=repository['path'],
short=None,
format=None,
json=True,
prefix=None,
match_archives=None,
sort_by=None,
first=None,
last=None,
)
global_arguments = argparse.Namespace()
local_path = config.get('local_path', 'borg')
remote_path = config.get('remote_path')
local_borg_version = borgmatic.borg.version.local_borg_version(config, local_path)
archives_data = borgmatic.actions.browse.controller.get_repository_archives(config, repository)
archives_data = json.loads(
borgmatic.borg.repo_list.list_repository(
repository['path'],
config,
local_borg_version,
repo_list_arguments,
global_arguments,
local_path,
remote_path,
)
)
browse_tree.app.call_from_thread(add_repository_archives, repository_node, archives_data, timer)
browse_tree.app.call_from_thread(add_repository_archives, repository_node, archives_data, timer)
def add_repository_archives(repository_node, archives_data, timer):
@@ -105,28 +69,12 @@ def add_repository_archives(repository_node, archives_data, timer):
@textual.work(thread=True)
def get_archive_files(browse_tree, archive_node, config, repository, archive, timer):
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
logger.answer(f"Listing archive {archive['archive']}")
files_data = borgmatic.actions.browse.controller.get_archive_files(config, repository, archive)
global_arguments = argparse.Namespace()
local_path = config.get('local_path', 'borg')
remote_path = config.get('remote_path')
local_borg_version = borgmatic.borg.version.local_borg_version(config, local_path)
file_data = borgmatic.borg.list.capture_archive_listing(
repository['path'],
archive['archive'],
config,
local_borg_version,
global_arguments,
local_path=local_path,
remote_path=remote_path,
)
browse_tree.app.call_from_thread(add_archive_files, archive_node, file_data, timer)
browse_tree.app.call_from_thread(add_archive_files, archive_node, files_data, timer)
def add_archive_files(archive_node, file_data, timer):
def add_archive_files(archive_node, files_data, timer):
config = archive_node.data['config']
repository = archive_node.data['repository']
archive = archive_node.data['archive']
@@ -136,7 +84,7 @@ def add_archive_files(archive_node, file_data, timer):
for child in archive_node.children:
child.remove()
for file in file_data:
for file in files_data:
archive_node.add(
file['path'],
data={
@@ -242,6 +190,71 @@ def unexpand_path(config_path):
return config_path
class Browse_app(textual.app.App):
BINDINGS = [
textual.binding.Binding(key='escape', action='quit', description='quit'),
textual.binding.Binding(
key='alt+m', action='command_palette', description='menu', show=False
),
]
COMMAND_PALETTE_BINDING = 'alt+m'
def __init__(self, configs):
self.configs = configs
super().__init__()
def compose(self):
tree = Browse_tree()
tree.styles.border = ('round', 'gray')
for config_path, config in self.configs.items():
config_node = tree.root.add(
unexpand_path(config_path), data={'type': Node_type.CONFIGURATION, 'config': config}
)
for repository in config['repositories']:
config_node.add(
repository['path'],
data={'type': Node_type.REPOSITORY, 'config': config, 'repository': repository},
)
first_child = tree.root.children[0]
tree.select_node(first_child)
tree.scroll_to_node(first_child)
yield textual.widgets.Header()
yield tree
log_widget = textual.widgets.RichLog(markup=True)
log_widget.styles.border = ('round', 'gray')
yield log_widget
yield textual.widgets.Footer()
handler = Browse_log_handler(self, log_widget)
handler.setFormatter(Rich_color_formatter())
logger = logging.getLogger()
logger.setLevel(min(handler.level for handler in logger.handlers))
logger.addHandler(handler)
# Remove the console log handler so it doesn't try to log all over our UI; we have our own
# log handler for surfacing logs within the UI.
with contextlib.suppress(StopIteration):
console_handler = next(
handler
for handler in logging.getLogger().handlers
if isinstance(handler, borgmatic.logger.Multi_stream_handler)
)
logger.removeHandler(console_handler)
def on_mount(self):
self.title = 'borgmatic browse'
self.theme = 'ansi-light'
tree = self.query_one(textual.widgets.Tree)
for child in tree.root.children:
child.expand()
class Browse_log_handler(logging.Handler):
def __init__(self, app, log_widget):
self.app = app
@@ -286,72 +299,6 @@ class Rich_color_formatter(logging.Formatter):
return f'[{color}]{super().format(record)}[/{color}]'
class Browse_app(textual.app.App):
BINDINGS = [
textual.binding.Binding(key='escape', action='quit', description='quit'),
textual.binding.Binding(
key='alt+m', action='command_palette', description='menu', show=False
),
]
COMMAND_PALETTE_BINDING = 'alt+m'
def __init__(self, configs):
self.configs = configs
super().__init__()
def compose(self):
tree = Browse_tree()
tree.styles.border = ('round', 'gray')
for config_path, config in self.configs.items():
config_node = tree.root.add(
unexpand_path(config_path), data={'type': Node_type.CONFIGURATION, 'config': config}
)
for repository in config['repositories']:
config_node.add(
repository['path'],
data={'type': Node_type.REPOSITORY, 'config': config, 'repository': repository},
)
first_child = tree.root.children[0]
tree.select_node(first_child)
tree.scroll_to_node(first_child)
yield textual.widgets.Header()
yield tree
log_widget = textual.widgets.RichLog(markup=True)
log_widget.styles.border = ('round', 'gray')
yield log_widget
yield textual.widgets.Footer()
logger = logging.getLogger()
handler = Browse_log_handler(self, log_widget)
handler.setFormatter(Rich_color_formatter())
logger.setLevel(min(handler.level for handler in logger.handlers))
logger.addHandler(handler)
# Remove the console log handler so it doesn't try to log all over our UI; we have our own
# log handler for surfacing logs within the UI.
with contextlib.suppress(StopIteration):
console_handler = next(
handler
for handler in logging.getLogger().handlers
if isinstance(handler, borgmatic.logger.Multi_stream_handler)
)
logger.removeHandler(console_handler)
def on_mount(self):
self.title = 'borgmatic browse'
self.theme = 'ansi-light'
tree = self.query_one(textual.widgets.Tree)
for child in tree.root.children:
child.expand()
def run_browse(
diff_arguments,
global_arguments,
+2 -2
View File
@@ -12,7 +12,7 @@ import ruamel.yaml
import borgmatic.actions.borg
import borgmatic.actions.break_lock
import borgmatic.actions.browse
import borgmatic.actions.browse.view
import borgmatic.actions.change_passphrase
import borgmatic.actions.check
import borgmatic.actions.compact
@@ -899,7 +899,7 @@ def collect_highlander_action_summary_logs(configs, arguments, configuration_par
return
if 'browse' in arguments:
borgmatic.actions.browse.run_browse(
borgmatic.actions.browse.view.run_browse(
arguments['browse'],
arguments['global'],
configs,