mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-07-22 02:03:01 +02:00
Binary versus text file detection for borgmatic browse.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
.
|
||||
apprise
|
||||
attrs
|
||||
binaryornot
|
||||
certifi
|
||||
charset-normalizer
|
||||
click
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# uv pip compile --annotation-style line binary_requirements.in -o binary_requirements.txt
|
||||
apprise==1.10.0 # via -r binary_requirements.in
|
||||
attrs==26.1.0 # via jsonschema, referencing, -r binary_requirements.in
|
||||
binaryornot==0.6.0 # via -r binary_requirements.in
|
||||
. # via -r binary_requirements.in
|
||||
certifi==2026.5.20 # via apprise, requests, -r binary_requirements.in
|
||||
charset-normalizer==3.4.7 # via requests, -r binary_requirements.in
|
||||
|
||||
@@ -7,6 +7,9 @@ import borgmatic.borg.extract
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.borg.version
|
||||
|
||||
import binaryornot.helpers
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -82,6 +85,10 @@ READLINES_HINT_BYTES = 100000
|
||||
|
||||
|
||||
def get_archive_file_content(config, repository, archive_name, file_path):
|
||||
'''
|
||||
Given a configuration dict, a repository dict, an archive name in that repository, and a file
|
||||
path in that archive, return the file's contents or None if the file can't be loaded.
|
||||
'''
|
||||
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
|
||||
logger.info(f'Getting archive content of file {file_path}')
|
||||
local_path = config.get('local_path', 'borg')
|
||||
@@ -102,10 +109,16 @@ def get_archive_file_content(config, repository, archive_name, file_path):
|
||||
extract_to_stdout=True,
|
||||
).stdout.readlines(READLINES_HINT_BYTES)
|
||||
|
||||
content = ''.join(line.decode() for line in lines)
|
||||
content = b''.join(lines)
|
||||
|
||||
return (
|
||||
content
|
||||
if len(content) < READLINES_HINT_BYTES
|
||||
else f'{content}[... truncated for display ...]'
|
||||
)
|
||||
if binaryornot.helpers.is_binary_string(content):
|
||||
return None
|
||||
|
||||
try:
|
||||
return (
|
||||
content.decode()
|
||||
if len(content) < READLINES_HINT_BYTES
|
||||
else f'{content.decode()}\n[... truncated for display ...]'
|
||||
)
|
||||
except UnicodeDecodeError:
|
||||
return None
|
||||
|
||||
@@ -15,6 +15,12 @@ OPTION_LIST_BINDINGS = (
|
||||
textual.binding.Binding(
|
||||
key='down,j', action='cursor_down', description='scroll down', show=True, priority=True
|
||||
),
|
||||
textual.binding.Binding(
|
||||
key='pageup', action='page_up', description='page up', show=True, priority=True
|
||||
),
|
||||
textual.binding.Binding(
|
||||
key='pagedown', action='page_down', description='page down', show=True, priority=True
|
||||
),
|
||||
textual.binding.Binding(
|
||||
key='enter', action='select', description='select', show=True, priority=True
|
||||
),
|
||||
@@ -55,7 +61,7 @@ class Repositories_list(textual.widgets.OptionList):
|
||||
),
|
||||
classes='panel',
|
||||
)
|
||||
self.border_title = 'repositories'
|
||||
self.border_title = '📦 repositories'
|
||||
|
||||
|
||||
class Archives_list(textual.widgets.OptionList):
|
||||
@@ -66,7 +72,7 @@ class Archives_list(textual.widgets.OptionList):
|
||||
self.repository = repository
|
||||
|
||||
super().__init__(classes='panel')
|
||||
self.border_title = 'archives'
|
||||
self.border_title = '📚 archives'
|
||||
self.highlighted_option_changed = False
|
||||
|
||||
timer = borgmatic.actions.browse.loading.add_inline_loading_indicator(self)
|
||||
@@ -128,10 +134,10 @@ class File_preview(textual.widgets.RichLog):
|
||||
BINDINGS = [
|
||||
*textual.widgets.RichLog.BINDINGS,
|
||||
textual.binding.Binding(
|
||||
key='up', action='scroll_up', description='scroll up', show=True, priority=True
|
||||
key='up,k', action='scroll_up', description='scroll up', show=True, priority=True
|
||||
),
|
||||
textual.binding.Binding(
|
||||
key='down', action='scroll_down', description='scroll down', show=True, priority=True
|
||||
key='down,j', action='scroll_down', description='scroll down', show=True, priority=True
|
||||
),
|
||||
textual.binding.Binding(
|
||||
key='pageup', action='page_up', description='page up', show=True, priority=True
|
||||
@@ -175,4 +181,4 @@ class File_preview(textual.widgets.RichLog):
|
||||
class Logs(textual.widgets.RichLog):
|
||||
def __init__(self):
|
||||
super().__init__(markup=True, id='logs', classes='panel')
|
||||
self.border_title = 'logs'
|
||||
self.border_title = '🪵 logs'
|
||||
|
||||
@@ -4,11 +4,13 @@ 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: '📄',
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ def add_archive_files(
|
||||
)
|
||||
|
||||
for path_type, file_path, link_target in file_type_paths:
|
||||
pieces = (borgmatic.actions.browse.paths.PATH_TYPE_ICONS.get(path_type, '?'), file_path) + (
|
||||
pieces = (borgmatic.actions.browse.paths.PATH_TYPE_ICONS.get(path_type, '❓'), file_path) + (
|
||||
('→', link_target) if link_target else ()
|
||||
)
|
||||
highlighted_option = directory_list.highlighted_option
|
||||
@@ -88,6 +88,10 @@ def load_file_preview(browse_app, file_preview, config, repository, archive_name
|
||||
)
|
||||
|
||||
browse_app.call_from_thread(timer.stop)
|
||||
syntax_lexer = rich.syntax.Syntax.guess_lexer(file_path, file_content)
|
||||
browse_app.call_from_thread(file_preview.clear)
|
||||
browse_app.call_from_thread(file_preview.write, rich.syntax.Syntax(file_content, syntax_lexer))
|
||||
|
||||
if file_content is None:
|
||||
browse_app.call_from_thread(file_preview.write, 'Cannot load a preview for this file')
|
||||
else:
|
||||
syntax_lexer = rich.syntax.Syntax.guess_lexer(file_path, file_content)
|
||||
browse_app.call_from_thread(file_preview.write, rich.syntax.Syntax(file_content, syntax_lexer))
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ validate-borgmatic-config = "borgmatic.commands.validate_config:main"
|
||||
|
||||
[project.optional-dependencies]
|
||||
Apprise = ["apprise"]
|
||||
browse = ["textual"]
|
||||
browse = ["textual", "binaryornot"]
|
||||
browse-dev = ["textual-dev"]
|
||||
|
||||
[project.urls]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
apprise
|
||||
attrs
|
||||
binaryornot
|
||||
certifi
|
||||
charset-normalizer
|
||||
click>=8.1.8
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# uv pip compile --annotation-style line test_requirements.in -o test_requirements.txt
|
||||
apprise==1.10.0 # via -r test_requirements.in
|
||||
attrs==26.1.0 # via jsonschema, referencing, -r test_requirements.in
|
||||
binaryornot==0.6.0 # via -r test_requirements.in
|
||||
certifi==2026.5.20 # via apprise, requests, -r test_requirements.in
|
||||
charset-normalizer==3.4.7 # via requests, -r test_requirements.in
|
||||
click>=8.1.8
|
||||
|
||||
Reference in New Issue
Block a user