mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-07-22 10:13:00 +02:00
Compare commits
77
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4af31db99c | ||
|
|
7cd9e6b361 | ||
|
|
4ee057a909 | ||
|
|
3e7e7879bc | ||
|
|
d29cfaf227 | ||
|
|
23a8d665d6 | ||
|
|
2a026a4842 | ||
|
|
16c8f81a5a | ||
|
|
1670ba2aeb | ||
|
|
5accda1a65 | ||
|
|
ec8e52944c | ||
|
|
30ca942f76 | ||
|
|
9748a0298a | ||
|
|
dc91f81a39 | ||
|
|
64ceebb2c8 | ||
|
|
7439d7cb8f | ||
|
|
f832a361ed | ||
|
|
3a4bdfb3c5 | ||
|
|
ed955c2a73 | ||
|
|
174aa3d522 | ||
|
|
5a74b3d081 | ||
|
|
a876ce2058 | ||
|
|
e82c1bb195 | ||
|
|
16061f4f6d | ||
|
|
59e6e61786 | ||
|
|
b7d0f006d6 | ||
|
|
6869a5d5f2 | ||
|
|
9da6d0f90a | ||
|
|
ac65e65302 | ||
|
|
8820a1eeab | ||
|
|
3abe025a80 | ||
|
|
b979e0356d | ||
|
|
ea0ed8345a | ||
|
|
4b8a6d1a34 | ||
|
|
60201541e0 | ||
|
|
bfd79a5500 | ||
|
|
43e995a4f3 | ||
|
|
94a2d68198 | ||
|
|
c9ba0762f0 | ||
|
|
13031a4ce4 | ||
|
|
9a2e853ea7 | ||
|
|
b1f42eb233 | ||
|
|
7e7c3c273e | ||
|
|
704db9c9d7 | ||
|
|
61d86c55b4 | ||
|
|
ecedccadee | ||
|
|
006825838f | ||
|
|
1102bf3787 | ||
|
|
220c76b3c0 | ||
|
|
9aea0b1d90 | ||
|
|
b6ab326bb4 | ||
|
|
c4170bb126 | ||
|
|
9935d0ef8d | ||
|
|
ec11e8817d | ||
|
|
73222e7b5b | ||
|
|
fd98f4fdd1 | ||
|
|
16e743d8d9 | ||
|
|
e93fe4cc15 | ||
|
|
da0698f6e5 | ||
|
|
5075c1e539 | ||
|
|
4b4851e78a | ||
|
|
8e91af6820 | ||
|
|
9be1698762 | ||
|
|
9310b42d9f | ||
|
|
d1d757a5d1 | ||
|
|
3f4a87517b | ||
|
|
a2dcd4747f | ||
|
|
0396a89f72 | ||
|
|
f170ef19df | ||
|
|
9729809f6f | ||
|
|
dfb3c0830e | ||
|
|
b22a068a60 | ||
|
|
1286ccce46 | ||
|
|
e339ce2fd1 | ||
|
|
aaf5812a3f | ||
|
|
47a6691886 | ||
|
|
596d59ef60 |
@@ -1,4 +1,6 @@
|
||||
2.1.6.dev0
|
||||
2.1.6
|
||||
* #1256: Fix a race condition in which borgmatic sometimes swallows Borg error output without
|
||||
logging it.
|
||||
* #1300: Fix the "source_directories_must_exist" option to support source directories relative to a
|
||||
"working_directory".
|
||||
* #1301: Expand the "patterns_from" and "exclude_from" options to support paths containing tildes
|
||||
@@ -8,6 +10,16 @@
|
||||
* #1303: For the MariaDB hook, include only a subset of system data when dumping the "mysql" system
|
||||
database (or "all" databases), so the dump is actually restorable. See the documentation for more
|
||||
information: https://torsion.org/borgmatic/reference/configuration/data-sources/mariadb/
|
||||
* #1314: Add a minimal stand-alone borgmatic binary in addition to the standard one. The minimal
|
||||
binary omits support for the Apprise monitoring hook.
|
||||
* Add an experimental "browse" action providing a console UI for browsing your backups. See the
|
||||
documentation for more information:
|
||||
https://torsion.org/borgmatic/how-to/inspect-your-backups/#browsing-backups
|
||||
* #1308: Update the Apprise monitoring hook's "url" option to support loading credentials with the
|
||||
"{credential ...}" syntax. See the documentation for more information:
|
||||
https://torsion.org/borgmatic/reference/configuration/credentials/
|
||||
* #1309: Add a "--quick-stats" flag and corresponding "quick_statistics" option for showing only
|
||||
abbreviated statistics for the "create" action. Borg 1.4.5+ only.
|
||||
* Update the KeePassXC credential hook to support KeePassXC's secret service integration. See the
|
||||
documentation for more information:
|
||||
https://torsion.org/borgmatic/reference/configuration/credentials/keepassxc/
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
apprise==1.10.0 # via -r binary_requirements.in
|
||||
attrs==26.1.0 # via jsonschema, referencing, -r binary_requirements.in
|
||||
. # via -r binary_requirements.in
|
||||
certifi==2026.4.22 # via apprise, requests, -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
|
||||
click==8.3.3 # via apprise, -r binary_requirements.in
|
||||
idna==3.13 # via requests, -r binary_requirements.in
|
||||
click==8.4.1 # via apprise, -r binary_requirements.in
|
||||
idna==3.16 # via requests, -r binary_requirements.in
|
||||
jsonschema==4.26.0 # via borgmatic, -r binary_requirements.in
|
||||
jsonschema-specifications==2025.9.1 # via jsonschema, -r binary_requirements.in
|
||||
markdown==3.10.2 # via apprise, -r binary_requirements.in
|
||||
@@ -14,8 +14,8 @@ oauthlib==3.3.1 # via requests-oauthlib, -r binary_requirements.in
|
||||
packaging==26.2 # via borgmatic, -r binary_requirements.in
|
||||
pyyaml==6.0.3 # via apprise, -r binary_requirements.in
|
||||
referencing==0.37.0 # via jsonschema, jsonschema-specifications, -r binary_requirements.in
|
||||
requests==2.33.1 # via apprise, borgmatic, requests-oauthlib, -r binary_requirements.in
|
||||
requests==2.34.2 # via apprise, borgmatic, requests-oauthlib, -r binary_requirements.in
|
||||
requests-oauthlib==2.0.0 # via apprise, -r binary_requirements.in
|
||||
rpds-py==0.30.0 # via jsonschema, referencing, -r binary_requirements.in
|
||||
ruamel-yaml==0.19.1 # via borgmatic, -r binary_requirements.in
|
||||
urllib3==2.6.3 # via requests, -r binary_requirements.in
|
||||
urllib3==2.7.0 # via requests, -r binary_requirements.in
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import signal
|
||||
|
||||
import textual.app
|
||||
import textual.binding
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.carousel
|
||||
import borgmatic.actions.browse.configuration_files_list
|
||||
import borgmatic.actions.browse.logs
|
||||
import borgmatic.actions.browse.repositories_list
|
||||
|
||||
|
||||
class Browse_app(textual.app.App):
|
||||
'''
|
||||
The main app / entry point for the browse action UI.
|
||||
'''
|
||||
|
||||
BINDINGS = (
|
||||
textual.binding.Binding(key='q', action='quit', description='quit'),
|
||||
textual.binding.Binding(key='v', action='toggle_logs', description='view logs'),
|
||||
textual.binding.Binding(
|
||||
key='c', action='command_palette', description='commands', show=False
|
||||
),
|
||||
)
|
||||
COMMAND_PALETTE_BINDING = 'c'
|
||||
CSS = '''
|
||||
.panel {
|
||||
border: round $primary;
|
||||
border-title-color: $text-primary;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#logs {
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
display: none;
|
||||
}
|
||||
'''
|
||||
|
||||
def __init__(self, configs):
|
||||
self.configs = configs
|
||||
|
||||
super().__init__()
|
||||
|
||||
def get_system_commands(self, screen): # pragma: no cover
|
||||
'''
|
||||
Remove the screenshot system command because it produces broken screenshots. (Emoji
|
||||
weirdness, etc.) Also remove minimize and maximize because they don't accomplish much with
|
||||
out particular layout.
|
||||
'''
|
||||
yield from (
|
||||
command
|
||||
for command in super().get_system_commands(screen)
|
||||
if command.title not in {'Screenshot', 'Minimize', 'Maximize'}
|
||||
)
|
||||
|
||||
def compose(self):
|
||||
'''
|
||||
Compose a UI consisting of:
|
||||
|
||||
* a header with the application name
|
||||
* a carousel container that contains the main UI panels
|
||||
* a logs panel where Python logs show up (panel hidden by default)
|
||||
* a footer with available keys listed
|
||||
'''
|
||||
yield textual.widgets.Header()
|
||||
yield borgmatic.actions.browse.carousel.Carousel(
|
||||
[
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list(
|
||||
self.configs
|
||||
)
|
||||
]
|
||||
if len(self.configs) > 1
|
||||
else [
|
||||
borgmatic.actions.browse.repositories_list.Repositories_list(
|
||||
next(iter(self.configs.values()))
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
logs_panel = borgmatic.actions.browse.logs.Logs()
|
||||
yield logs_panel
|
||||
yield textual.widgets.Footer()
|
||||
|
||||
borgmatic.actions.browse.logs.log_to_widget(logs_panel)
|
||||
|
||||
def on_mount(self):
|
||||
'''
|
||||
Set the application title, which ends up in the header.
|
||||
'''
|
||||
self.title = 'borgmatic browse'
|
||||
|
||||
def action_toggle_logs(self):
|
||||
'''
|
||||
Toggle the show/hide status of the logs panel.
|
||||
'''
|
||||
logs_panel = self.query_one('#logs')
|
||||
logs_panel.styles.display = 'none' if logs_panel.styles.display == 'block' else 'block'
|
||||
|
||||
def exit(self): # pragma: no cover
|
||||
'''
|
||||
Exit the application. But first raise a SIGTERM (handled in borgmatic/signals.py) to
|
||||
encourage a fast exit by killing any ongoing Borg subprocesses.
|
||||
'''
|
||||
signal.raise_signal(signal.SIGTERM)
|
||||
|
||||
super().exit()
|
||||
@@ -0,0 +1,143 @@
|
||||
import argparse
|
||||
import collections
|
||||
import enum
|
||||
import json
|
||||
import logging
|
||||
|
||||
import binaryornot.helpers
|
||||
|
||||
import borgmatic.borg.extract
|
||||
import borgmatic.borg.list
|
||||
import borgmatic.borg.repo_list
|
||||
import borgmatic.borg.version
|
||||
|
||||
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'),
|
||||
)
|
||||
|
||||
|
||||
def get_repository_archives(config, repository):
|
||||
'''
|
||||
Given a configuration dict and a repository dict, return a list of the repository's archives,
|
||||
one dict per archive.
|
||||
'''
|
||||
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
|
||||
logger.info('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_paths(config, repository, archive_name):
|
||||
'''
|
||||
Given a configuration dict, a repository dict, and an archive name in that repository, get a
|
||||
generator of files, directories, symlinks, etc. found in the archive, each as an Archive_path
|
||||
instance.
|
||||
'''
|
||||
with borgmatic.logger.Log_prefix(repository.get('label', repository['path'])):
|
||||
logger.info(f'Listing archive {archive_name}')
|
||||
|
||||
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 (
|
||||
Archive_path(
|
||||
path_data['type'],
|
||||
path_data['path'],
|
||||
path_data.get('linktarget'),
|
||||
)
|
||||
for path_data in borgmatic.borg.list.capture_archive_listing(
|
||||
repository['path'],
|
||||
archive_name,
|
||||
config,
|
||||
local_borg_version,
|
||||
global_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
READLINES_HINT_BYTES = 100000
|
||||
TRUNCATION_MESSAGE = '[... truncated for display ...]'
|
||||
|
||||
|
||||
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, e.g.
|
||||
because it's binary or can't be decoded.
|
||||
|
||||
If the file is too large, then truncate the returned content.
|
||||
'''
|
||||
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')
|
||||
remote_path = config.get('remote_path')
|
||||
|
||||
lines = borgmatic.borg.extract.extract_archive(
|
||||
dry_run=False,
|
||||
repository=repository['path'],
|
||||
archive=archive_name,
|
||||
paths=(file_path,),
|
||||
config=config,
|
||||
local_borg_version=borgmatic.borg.version.local_borg_version(config, local_path),
|
||||
global_arguments=argparse.Namespace(),
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
destination_path=None,
|
||||
strip_components=None,
|
||||
extract_to_stdout=True,
|
||||
).stdout.readlines(READLINES_HINT_BYTES)
|
||||
|
||||
content = b''.join(lines)
|
||||
|
||||
if binaryornot.helpers.is_binary_string(content):
|
||||
return None
|
||||
|
||||
try:
|
||||
return (
|
||||
content.decode()
|
||||
if len(content) < READLINES_HINT_BYTES
|
||||
else f'{content.decode()}\n{TRUNCATION_MESSAGE}'
|
||||
)
|
||||
except UnicodeDecodeError:
|
||||
return None
|
||||
@@ -0,0 +1,89 @@
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.bindings
|
||||
import borgmatic.actions.browse.loading
|
||||
import borgmatic.actions.browse.workers
|
||||
|
||||
|
||||
class Archives_list(textual.widgets.OptionList):
|
||||
'''
|
||||
A widget for selecting a single Borg archive from among the archives in a repository. The item
|
||||
selection event is handled in a Carousel instance, the parent widget of an Archives_list.
|
||||
'''
|
||||
|
||||
BINDINGS = borgmatic.actions.browse.bindings.OPTION_LIST_BINDINGS
|
||||
|
||||
def __init__(self, config, repository):
|
||||
'''
|
||||
Given a configuration dict and a repository dict, prepare to load the archives from the
|
||||
repository for eventual display in this widget. Actual loading kicks off in on_mount()
|
||||
below.
|
||||
'''
|
||||
self.config = config
|
||||
self.repository = repository
|
||||
|
||||
super().__init__(classes='panel')
|
||||
self.border_title = '📚 archives'
|
||||
self.highlighted_option_changed = False
|
||||
self.archive_loaded = borgmatic.actions.browse.workers.Archive_loaded(
|
||||
self, 'archive loaded'
|
||||
)
|
||||
|
||||
self.loading_timer = borgmatic.actions.browse.loading.add_inline_loading_indicator(self)
|
||||
|
||||
def on_mount(self):
|
||||
'''
|
||||
When this widget gets mounted in the DOM, subscribe to archive loaded events so that we can
|
||||
find out about archives as they load. Also start loading archives from the repository.
|
||||
|
||||
Loading is started *after* subscribing to the archive loaded signal so that there's not a
|
||||
gap where we might miss out on signal publishes.
|
||||
'''
|
||||
self.archive_loaded.subscribe(self, self.on_archive_loaded)
|
||||
|
||||
borgmatic.actions.browse.workers.add_repository_archives(
|
||||
self.app,
|
||||
archive_loaded=self.archive_loaded,
|
||||
config=self.config,
|
||||
repository=self.repository,
|
||||
)
|
||||
|
||||
def on_archive_loaded(self, archive_name):
|
||||
'''
|
||||
When an archive loads, add it as an option to this archives list. But if we get a
|
||||
signal that all path loading is complete, stop and remove our loading indicator.
|
||||
'''
|
||||
if archive_name is borgmatic.actions.browse.workers.LOADING_DONE:
|
||||
self.loading_timer.stop()
|
||||
self.remove_option('loading-indicator')
|
||||
return
|
||||
|
||||
label_pieces = (
|
||||
(archive_name, '[dim](latest)[/dim]') if len(self.options) == 1 else (archive_name,)
|
||||
)
|
||||
highlighted_option = self.highlighted_option
|
||||
|
||||
loading_indicator = self.get_option('loading-indicator')
|
||||
self.remove_option('loading-indicator')
|
||||
self.add_options(
|
||||
(
|
||||
textual.widgets.option_list.Option(' '.join(label_pieces), id=archive_name),
|
||||
loading_indicator,
|
||||
),
|
||||
)
|
||||
|
||||
# Retain the highlighted option position even as other options load around it.
|
||||
self.highlighted = (
|
||||
self.get_option_index(highlighted_option.id)
|
||||
if highlighted_option and self.highlighted_option_changed
|
||||
else 0
|
||||
)
|
||||
|
||||
def on_option_list_option_highlighted(self, event):
|
||||
'''
|
||||
When the highlighted option changes, record that fact. This flag is consumed in
|
||||
borgmatic.actions.browse.workers.add_repository_archives() in order to retain the
|
||||
highlighted option even as other options load around it.
|
||||
'''
|
||||
if self.highlighted not in {None, 0}:
|
||||
self.highlighted_option_changed = True
|
||||
@@ -0,0 +1,22 @@
|
||||
import textual.binding
|
||||
import textual.widgets
|
||||
|
||||
OPTION_LIST_BINDINGS = (
|
||||
*textual.widgets.OptionList.BINDINGS,
|
||||
textual.binding.Binding(
|
||||
key='up,k', action='cursor_up', description='scroll up', show=True, priority=True
|
||||
),
|
||||
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
|
||||
),
|
||||
textual.binding.Binding(key='right,l', action='select', description='select', show=False),
|
||||
)
|
||||
@@ -0,0 +1,153 @@
|
||||
import os
|
||||
|
||||
import textual.binding
|
||||
import textual.containers
|
||||
|
||||
import borgmatic.actions.browse.archive
|
||||
import borgmatic.actions.browse.archives_list
|
||||
import borgmatic.actions.browse.configuration_files_list
|
||||
import borgmatic.actions.browse.directory_list
|
||||
import borgmatic.actions.browse.file_preview
|
||||
import borgmatic.actions.browse.icons
|
||||
import borgmatic.actions.browse.repositories_list
|
||||
|
||||
|
||||
def make_next_panel(focused_panel, option_id):
|
||||
'''
|
||||
Given a focused panel widget and the selected option ID, return the next panel corresponding to
|
||||
that selection. This is the mechanism by which the user can successively drill down from
|
||||
configuration file to repository to archive to root directory to non-root directory or file.
|
||||
|
||||
If the particular option ID on the focused panel doesn't have a supported next panel, then
|
||||
return None.
|
||||
'''
|
||||
if isinstance(
|
||||
focused_panel, borgmatic.actions.browse.configuration_files_list.Configuration_files_list
|
||||
):
|
||||
return borgmatic.actions.browse.repositories_list.Repositories_list(
|
||||
config=focused_panel.configs[option_id]
|
||||
)
|
||||
|
||||
if isinstance(focused_panel, borgmatic.actions.browse.repositories_list.Repositories_list):
|
||||
return borgmatic.actions.browse.archives_list.Archives_list(
|
||||
config=focused_panel.config, repository=focused_panel.repositories[option_id]
|
||||
)
|
||||
|
||||
if isinstance(focused_panel, borgmatic.actions.browse.archives_list.Archives_list):
|
||||
return borgmatic.actions.browse.directory_list.Directory_list(
|
||||
config=focused_panel.config, repository=focused_panel.repository, archive_name=option_id
|
||||
)
|
||||
|
||||
if isinstance(focused_panel, borgmatic.actions.browse.directory_list.Directory_list):
|
||||
option = focused_panel.get_option(option_id)
|
||||
|
||||
if option.prompt.startswith(
|
||||
borgmatic.actions.browse.icons.PATH_TYPE_ICONS[
|
||||
borgmatic.actions.browse.archive.Path_type.DIRECTORY.value
|
||||
]
|
||||
):
|
||||
return borgmatic.actions.browse.directory_list.Directory_list(
|
||||
focused_panel.config,
|
||||
focused_panel.repository,
|
||||
focused_panel.archive_name,
|
||||
path_loaded=focused_panel.path_loaded,
|
||||
path_components=(*focused_panel.path_components, option_id),
|
||||
)
|
||||
|
||||
if option.prompt.startswith(
|
||||
borgmatic.actions.browse.icons.PATH_TYPE_ICONS[
|
||||
borgmatic.actions.browse.archive.Path_type.FILE.value
|
||||
]
|
||||
):
|
||||
return borgmatic.actions.browse.file_preview.File_preview(
|
||||
focused_panel.config,
|
||||
focused_panel.repository,
|
||||
focused_panel.archive_name,
|
||||
file_path=os.path.sep.join((*focused_panel.path_components, option_id)),
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class Carousel(textual.containers.Horizontal):
|
||||
BINDINGS = (
|
||||
textual.binding.Binding(
|
||||
key='left,h', action='previous', description='previous', priority=True
|
||||
),
|
||||
)
|
||||
|
||||
def __init__(self, panels):
|
||||
self.panels = panels
|
||||
self.focused_panel = panels[0]
|
||||
|
||||
super().__init__()
|
||||
|
||||
def compose(self):
|
||||
'''
|
||||
Compose with each of the contained panels and focus the first one.
|
||||
'''
|
||||
yield from self.panels
|
||||
|
||||
self.focused_panel.focus()
|
||||
|
||||
def action_previous(self):
|
||||
'''
|
||||
Make the previous panel into the focused panel.
|
||||
'''
|
||||
previous_panel_index = self.panels.index(self.focused_panel) - 1
|
||||
|
||||
if previous_panel_index < 0:
|
||||
return
|
||||
|
||||
self.focused_panel.styles.display = 'none'
|
||||
|
||||
self.focused_panel = self.panels[previous_panel_index]
|
||||
self.focused_panel.styles.display = 'block'
|
||||
self.focused_panel.focus()
|
||||
|
||||
def action_next(self, option_id):
|
||||
'''
|
||||
Hide the current focused panel and create the next one.
|
||||
'''
|
||||
next_panel_index = self.panels.index(self.focused_panel) + 1
|
||||
|
||||
if next_panel_index < len(self.panels):
|
||||
next_panel = self.panels[next_panel_index]
|
||||
next_panel.styles.display = 'block'
|
||||
else:
|
||||
next_panel = make_next_panel(self.focused_panel, option_id)
|
||||
|
||||
if next_panel is None:
|
||||
self.notify('Cannot display this content', severity='warning')
|
||||
return
|
||||
|
||||
self.panels.append(next_panel)
|
||||
next_panel.highlighted = 0
|
||||
|
||||
self.focused_panel.styles.display = 'none'
|
||||
self.focused_panel = next_panel
|
||||
self.focused_panel.focus()
|
||||
self.mount(self.focused_panel)
|
||||
|
||||
def on_option_list_option_highlighted(self, event):
|
||||
'''
|
||||
The highlighted option has changed, so truncate any next panels.
|
||||
'''
|
||||
next_panel_index = self.panels.index(self.focused_panel) + 1
|
||||
|
||||
del self.panels[next_panel_index:]
|
||||
|
||||
def on_option_list_option_selected(self, event):
|
||||
'''
|
||||
An option has been selected, so advance to the next panel—unless the option selected is
|
||||
"..", in which case go to the previous panel.
|
||||
'''
|
||||
if (
|
||||
event.option_list != self.focused_panel or event.option_id == 'loading-indicator'
|
||||
): # pragma: no cover
|
||||
return
|
||||
|
||||
if event.option_id == '..':
|
||||
self.action_previous()
|
||||
else:
|
||||
self.action_next(event.option_id)
|
||||
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.bindings
|
||||
|
||||
|
||||
class Configuration_files_list(textual.widgets.OptionList):
|
||||
'''
|
||||
A widget for selecting a single borgmatic configuration file from among available configuration
|
||||
files. The item selection event is handled in a Carousel instance, the parent widget of an
|
||||
Configuration_files_list.
|
||||
'''
|
||||
|
||||
BINDINGS = borgmatic.actions.browse.bindings.OPTION_LIST_BINDINGS
|
||||
|
||||
def __init__(self, configs):
|
||||
'''
|
||||
Given a dict mapping from configuration path to corresponding configuration dict, add each
|
||||
configuration path as an option to this widget.
|
||||
'''
|
||||
self.configs = configs
|
||||
home_directory = os.path.expanduser('~')
|
||||
|
||||
super().__init__(
|
||||
*(
|
||||
textual.widgets.option_list.Option(unexpanded_path, id=config_path)
|
||||
for config_path in configs
|
||||
for unexpanded_path in (config_path.replace(home_directory, '~'),)
|
||||
),
|
||||
classes='panel',
|
||||
)
|
||||
self.border_title = '📄 configuration files'
|
||||
@@ -0,0 +1,211 @@
|
||||
import os
|
||||
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.bindings
|
||||
import borgmatic.actions.browse.icons
|
||||
import borgmatic.actions.browse.loading
|
||||
import borgmatic.actions.browse.workers
|
||||
|
||||
|
||||
def get_relative_archive_path_components(archive_path, current_directory_path_components):
|
||||
'''
|
||||
Given an Archive_path instance and a tuple of path components for the currently browsed
|
||||
directory, get the path components as a tuple for the archive path relative to that directory.
|
||||
|
||||
For instance, given an archive path with a path of 'foo/bar/baz/quux.txt' and current
|
||||
directory path components of ('foo', 'bar'), return ('baz', 'quux.txt').
|
||||
|
||||
If the archive path is not actually relative to the current directory, return None.
|
||||
'''
|
||||
archive_path_components = tuple(archive_path.file_path.split(os.path.sep))
|
||||
|
||||
if not current_directory_path_components:
|
||||
return archive_path_components
|
||||
|
||||
# If the loaded path doesn't match this directory list's own path, then we don't care about
|
||||
# it for purposes of displaying this particular directory.
|
||||
if (
|
||||
tuple(archive_path_components[: len(current_directory_path_components)])
|
||||
!= current_directory_path_components
|
||||
):
|
||||
return None
|
||||
|
||||
# Strip off the portion of the archive path that matches the directory list's own path.
|
||||
return archive_path_components[len(current_directory_path_components) :]
|
||||
|
||||
|
||||
def make_directory_list_option(archive_path, relative_path_components):
|
||||
'''
|
||||
Given an Archive_path instance and a tuple of relative path components for it, make a
|
||||
textual.widgets.option_list.Option for the path. Use an the icon based on whether this looks
|
||||
like a terminal filename or a directory.
|
||||
'''
|
||||
pieces = (
|
||||
borgmatic.actions.browse.icons.PATH_TYPE_ICONS.get(
|
||||
archive_path.path_type if len(relative_path_components) == 1 else 'd', '❓'
|
||||
),
|
||||
relative_path_components[0],
|
||||
) + (('→', archive_path.link_target) if archive_path.link_target else ())
|
||||
|
||||
return textual.widgets.option_list.Option(
|
||||
prompt=' '.join(pieces), id=relative_path_components[0]
|
||||
)
|
||||
|
||||
|
||||
def add_archive_paths(
|
||||
directory_list,
|
||||
config,
|
||||
repository,
|
||||
archive_name,
|
||||
archive_paths,
|
||||
):
|
||||
'''
|
||||
Given a DirectoryList instance, a configuration dict, a repository dict, an archive name, and a
|
||||
sequence of ArchivePath instances, add the paths to the directory list as options, sorting and
|
||||
deduplicating the resulting directory list's options.
|
||||
|
||||
After all of this reshuffling, make sure the original highlighted option remains highlighted.
|
||||
'''
|
||||
highlighted_option = directory_list.highlighted_option
|
||||
original_options_count = len(directory_list.options)
|
||||
|
||||
sorted_options = sorted(
|
||||
(
|
||||
*directory_list.options,
|
||||
*(
|
||||
make_directory_list_option(archive_path, relative_path_components)
|
||||
for archive_path in archive_paths
|
||||
for relative_path_components in (
|
||||
get_relative_archive_path_components(
|
||||
archive_path,
|
||||
directory_list.path_components,
|
||||
),
|
||||
)
|
||||
if relative_path_components
|
||||
if relative_path_components[0] not in directory_list._id_to_option
|
||||
),
|
||||
),
|
||||
# The loading indicator "option" always goes to the bottom.
|
||||
key=lambda option: ((option.id == 'loading-indicator'), option.prompt),
|
||||
)
|
||||
|
||||
# If there aren't actually any options to add (due to deduplication), bail.
|
||||
if len(sorted_options) == original_options_count:
|
||||
return
|
||||
|
||||
# Retain the highlighted option position even as other options load around it.
|
||||
directory_list.set_options(sorted_options)
|
||||
directory_list.highlighted = (
|
||||
directory_list.get_option_index(highlighted_option.id)
|
||||
if highlighted_option and directory_list.highlighted_option_changed
|
||||
else 0
|
||||
)
|
||||
|
||||
|
||||
class Directory_list(textual.widgets.OptionList):
|
||||
'''
|
||||
A widget for selecting a path from among the contents of a particular directory in a Borg
|
||||
archive. The item selection event is handled in a Carousel instance, the parent widget of a
|
||||
Directory_list.
|
||||
'''
|
||||
|
||||
BINDINGS = borgmatic.actions.browse.bindings.OPTION_LIST_BINDINGS
|
||||
|
||||
def __init__(self, config, repository, archive_name, path_loaded=None, path_components=None):
|
||||
'''
|
||||
Given a configuration dict, a repository dict, an archive name, an optional
|
||||
Archive_path_loaded instance for signalling new paths as they load, and an optional tuple of
|
||||
path components indicating this directory's position in the backed up filesystem, prepare to
|
||||
load paths from the archive for eventual display in this widget. Actual loading kicks off in
|
||||
on_mount() below.
|
||||
'''
|
||||
self.config = config
|
||||
self.repository = repository
|
||||
self.archive_name = archive_name
|
||||
self.path_components = path_components or ()
|
||||
self.highlighted_option_changed = False
|
||||
|
||||
super().__init__(classes='panel')
|
||||
|
||||
self.border_title = ' '.join(
|
||||
(
|
||||
'📁',
|
||||
os.path.sep.join(self.path_components)
|
||||
if self.path_components
|
||||
else f'{archive_name}',
|
||||
)
|
||||
)
|
||||
|
||||
if self.path_components:
|
||||
self.add_option(
|
||||
textual.widgets.option_list.Option(
|
||||
'📁 ..',
|
||||
id='..',
|
||||
),
|
||||
)
|
||||
|
||||
self.path_loaded = path_loaded or borgmatic.actions.browse.workers.Archive_path_loaded(
|
||||
self, 'archive path loaded'
|
||||
)
|
||||
|
||||
if not self.path_loaded.complete:
|
||||
self.timer = borgmatic.actions.browse.loading.add_inline_loading_indicator(self)
|
||||
|
||||
def on_mount(self):
|
||||
'''
|
||||
When this widget gets mounted in the DOM, subscribe to path loaded events so that we can
|
||||
find out about relevant archive paths as they load. And if this is a root directory list,
|
||||
start loading paths from the archive. If this is a non-root directory list, add any already
|
||||
loaded archive paths to this widget as options.
|
||||
|
||||
Loading is started *after* subscribing to path loaded signals so that there's not a gap
|
||||
where we might miss out on any paths.
|
||||
'''
|
||||
self.path_loaded.subscribe(self, self.on_archive_path_loaded)
|
||||
|
||||
if self.path_components:
|
||||
add_archive_paths(
|
||||
directory_list=self,
|
||||
config=self.config,
|
||||
repository=self.repository,
|
||||
archive_name=self.archive_name,
|
||||
archive_paths=borgmatic.actions.browse.workers.get_paths(
|
||||
self.path_loaded.path_hierarchy, self.path_components
|
||||
),
|
||||
)
|
||||
else:
|
||||
borgmatic.actions.browse.workers.load_archive_paths(
|
||||
self.app,
|
||||
path_loaded=self.path_loaded,
|
||||
config=self.config,
|
||||
repository=self.repository,
|
||||
archive_name=self.archive_name,
|
||||
)
|
||||
|
||||
def on_archive_path_loaded(self, data):
|
||||
'''
|
||||
When an archive path loads, add it as an option to this directory list. But if we get a
|
||||
signal that all path loading is complete, stop and remove our loading indicator.
|
||||
'''
|
||||
if data is borgmatic.actions.browse.workers.LOADING_DONE:
|
||||
self.timer.stop()
|
||||
self.remove_option('loading-indicator')
|
||||
return
|
||||
|
||||
add_archive_paths(
|
||||
directory_list=self,
|
||||
config=self.config,
|
||||
repository=self.repository,
|
||||
archive_name=self.archive_name,
|
||||
archive_paths=(data,),
|
||||
)
|
||||
|
||||
def on_option_list_option_highlighted(self, event):
|
||||
'''
|
||||
When the highlighted option changes, record that fact. This flag is consumed in
|
||||
add_archive_paths() in order to retain the highlighted option even as other options load
|
||||
around it.
|
||||
'''
|
||||
if self.highlighted not in {None, 0}:
|
||||
self.highlighted_option_changed = True
|
||||
@@ -0,0 +1,87 @@
|
||||
import logging
|
||||
|
||||
import rich.syntax
|
||||
import textual.binding
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.loading
|
||||
import borgmatic.actions.browse.workers
|
||||
|
||||
logger = logging.getLogger('__name__')
|
||||
|
||||
|
||||
class File_preview(textual.widgets.RichLog):
|
||||
'''
|
||||
A widget for extracting and previewing the contents of a file stored in a Borg archive.
|
||||
'''
|
||||
|
||||
BINDINGS = (
|
||||
*textual.widgets.RichLog.BINDINGS,
|
||||
textual.binding.Binding(
|
||||
key='up,k', action='scroll_up', description='scroll up', show=True, priority=True
|
||||
),
|
||||
textual.binding.Binding(
|
||||
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
|
||||
),
|
||||
textual.binding.Binding(
|
||||
key='pagedown', action='page_down', description='page down', show=True, priority=True
|
||||
),
|
||||
)
|
||||
|
||||
def __init__(self, config, repository, archive_name, file_path):
|
||||
'''
|
||||
Given a configuration dict, a repository dict, an archive name, and the path of a file in
|
||||
the archive, prepare to load the file's contents for eventual display in this widget. Actual
|
||||
loading kicks off in on_mount() below.
|
||||
'''
|
||||
self.config = config
|
||||
self.repository = repository
|
||||
self.archive_name = archive_name
|
||||
self.file_path = file_path
|
||||
|
||||
super().__init__(classes='panel')
|
||||
self.border_title = f'📄 {self.file_path} preview'
|
||||
self.auto_scroll = False
|
||||
self.file_preview_loaded = borgmatic.actions.browse.workers.File_preview_loaded(
|
||||
self, 'file preview loaded'
|
||||
)
|
||||
|
||||
self.loading_timer = borgmatic.actions.browse.loading.add_inline_loading_indicator(self)
|
||||
|
||||
def on_mount(self):
|
||||
'''
|
||||
When this widget gets mounted in the DOM, subscribe to archive loaded events so that we can
|
||||
find out about archives as they load. Also start loading file contents from the archive.
|
||||
|
||||
Loading is started *after* subscribing to the file preview loaded signal so that there's not
|
||||
a gap where we might miss out on signal publishes.
|
||||
'''
|
||||
self.file_preview_loaded.subscribe(self, self.on_file_preview_loaded)
|
||||
|
||||
borgmatic.actions.browse.workers.load_file_preview(
|
||||
self.app,
|
||||
file_preview_loaded=self.file_preview_loaded,
|
||||
config=self.config,
|
||||
repository=self.repository,
|
||||
archive_name=self.archive_name,
|
||||
file_path=self.file_path,
|
||||
)
|
||||
|
||||
def on_file_preview_loaded(self, file_contents):
|
||||
'''
|
||||
When a file loads, write its contents (syntax highlighted) to this file preview widget.
|
||||
'''
|
||||
self.loading_timer.stop()
|
||||
self.clear()
|
||||
|
||||
if file_contents is None:
|
||||
self.write('Cannot display a preview for this file')
|
||||
else:
|
||||
# Only pass the file path and not its contents to guess_lexer(). Passing the contents is
|
||||
# more accurate, but also much slower.
|
||||
self.write(
|
||||
rich.syntax.Syntax(file_contents, rich.syntax.Syntax.guess_lexer(self.file_path))
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
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: '📄',
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import contextlib
|
||||
import functools
|
||||
import logging
|
||||
|
||||
import textual.widgets
|
||||
import textual.widgets.option_list
|
||||
|
||||
LOADING_DOT_INTERVAL_SECONDS = 0.3
|
||||
|
||||
|
||||
logger = logging.getLogger('__name__')
|
||||
|
||||
|
||||
def update_inline_loading_indicator(widget):
|
||||
'''
|
||||
Given a textual.widgets.OptionList or a textual.widgets.RichLog instance, animate the existing
|
||||
loading indicator inside it.
|
||||
'''
|
||||
if isinstance(widget, textual.widgets.OptionList):
|
||||
with contextlib.suppress(textual.widgets.option_list.OptionDoesNotExist):
|
||||
widget.replace_option_prompt(
|
||||
'loading-indicator',
|
||||
(str(widget.get_option('loading-indicator').prompt) + '.').replace('....', ''),
|
||||
)
|
||||
elif isinstance(widget, textual.widgets.RichLog):
|
||||
with contextlib.suppress(IndexError):
|
||||
loading_message = str(widget.lines[0].text)
|
||||
widget.clear()
|
||||
widget.write((loading_message + '.').replace('....', ''))
|
||||
else:
|
||||
raise ValueError(f'Unsupported widget type: {type(widget)}')
|
||||
|
||||
|
||||
LOADING_MESSAGE = '⏳ loading...'
|
||||
|
||||
|
||||
def add_inline_loading_indicator(widget):
|
||||
'''
|
||||
Given a textual.widgets.OptionList or a textual.widgets.RichLog instance, add a loading
|
||||
indicator to it.
|
||||
'''
|
||||
if isinstance(widget, textual.widgets.OptionList):
|
||||
loading_option = textual.widgets.option_list.Option(LOADING_MESSAGE, id='loading-indicator')
|
||||
widget.add_option(loading_option)
|
||||
widget.highlighted = None
|
||||
elif isinstance(widget, textual.widgets.RichLog):
|
||||
widget.write(LOADING_MESSAGE)
|
||||
else:
|
||||
raise ValueError(f'Unsupported widget type: {type(widget)}')
|
||||
|
||||
return widget.set_interval(
|
||||
LOADING_DOT_INTERVAL_SECONDS,
|
||||
functools.partial(update_inline_loading_indicator, widget),
|
||||
)
|
||||
@@ -0,0 +1,102 @@
|
||||
import contextlib
|
||||
import logging
|
||||
|
||||
import textual._context
|
||||
import textual.widgets
|
||||
import textual.worker
|
||||
|
||||
import borgmatic.logger
|
||||
|
||||
|
||||
class Rich_color_formatter(logging.Formatter):
|
||||
'''
|
||||
A Python logging formatter that formats log records with Rich-compatible color markup according
|
||||
to their levels.
|
||||
'''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.prefix = None
|
||||
super().__init__(
|
||||
'{prefix}{message}',
|
||||
*args,
|
||||
style='{',
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def format(self, record):
|
||||
'''
|
||||
Given a log record, format it with Rich-compatibe color markup corresponding to its log
|
||||
level.
|
||||
'''
|
||||
borgmatic.logger.add_custom_log_levels()
|
||||
|
||||
color = {
|
||||
logging.CRITICAL: 'bright_red',
|
||||
logging.ERROR: 'bright_red',
|
||||
logging.WARNING: 'bright_yellow',
|
||||
logging.ANSWER: 'bright_magenta',
|
||||
logging.INFO: 'bright_green',
|
||||
logging.DEBUG: 'bright_cyan',
|
||||
}.get(record.levelno)
|
||||
record.prefix = f'{self.prefix}: ' if self.prefix else ''
|
||||
|
||||
return f'[{color}]{super().format(record)}[/{color}]'
|
||||
|
||||
|
||||
class Browse_log_handler(logging.Handler):
|
||||
'''
|
||||
A Python log handler that writes any log records to a logging widget.
|
||||
'''
|
||||
|
||||
def __init__(self, logs_widget):
|
||||
'''
|
||||
Given a logs widget, save it for use below.
|
||||
'''
|
||||
self.logs_widget = logs_widget
|
||||
|
||||
super().__init__()
|
||||
|
||||
def emit(self, record):
|
||||
'''
|
||||
Given a log record, format it and log it to the logs widgets. This works whether or not the
|
||||
logging is happening in the main thread.
|
||||
'''
|
||||
message = self.format(record)
|
||||
|
||||
try:
|
||||
textual.worker.get_current_worker()
|
||||
self.logs_widget.app.call_from_thread(self.logs_widget.write, message)
|
||||
except (RuntimeError, textual.worker.NoActiveWorker):
|
||||
with contextlib.suppress(textual._context.NoActiveAppError):
|
||||
self.logs_widget.write(message)
|
||||
|
||||
|
||||
def log_to_widget(logs_widget):
|
||||
'''
|
||||
Given a Textual RichLog logs widget, add a log handler and formatter that logs to it. Also
|
||||
remove the default borgmatic console log handler so it doesn't try to log all over our UI.
|
||||
'''
|
||||
handler = Browse_log_handler(logs_widget)
|
||||
handler.setFormatter(Rich_color_formatter())
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(min(handler.level for handler in logger.handlers))
|
||||
logger.addHandler(handler)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class Logs(textual.widgets.RichLog):
|
||||
'''
|
||||
A widget for viewing borgmatic logs in realtime. The log level is determined by borgmatic's
|
||||
current verbosity level.
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(markup=True, id='logs', classes='panel')
|
||||
self.border_title = '🪵 logs'
|
||||
@@ -0,0 +1,30 @@
|
||||
import textual.widgets
|
||||
|
||||
import borgmatic.actions.browse.bindings
|
||||
|
||||
|
||||
class Repositories_list(textual.widgets.OptionList):
|
||||
'''
|
||||
A widget for selecting a single Borg repository from among the repositories in a borgmatic
|
||||
configuration file. The item selection event is handled in a Carousel instance, the parent
|
||||
widget of a Repositories_list.
|
||||
'''
|
||||
|
||||
BINDINGS = borgmatic.actions.browse.bindings.OPTION_LIST_BINDINGS
|
||||
|
||||
def __init__(self, config):
|
||||
'''
|
||||
Given a configuration dict, populate the repositories in this widget.
|
||||
'''
|
||||
self.config = config
|
||||
self.repositories = config['repositories']
|
||||
|
||||
super().__init__(
|
||||
*(
|
||||
textual.widgets.option_list.Option(label, id=index)
|
||||
for index, repository in enumerate(self.repositories)
|
||||
for label in (repository.get('label', repository.get('path')),)
|
||||
),
|
||||
classes='panel',
|
||||
)
|
||||
self.border_title = '📦 repositories'
|
||||
@@ -0,0 +1,29 @@
|
||||
import logging
|
||||
|
||||
|
||||
def run_browse(
|
||||
diff_arguments,
|
||||
global_arguments,
|
||||
configs,
|
||||
):
|
||||
'''
|
||||
Run the "browse" action for the given borgmatic configurations. This launches a console UI.
|
||||
|
||||
Raise ValueError if the Textual library (a prerequisite for this action) can't be imported.
|
||||
'''
|
||||
if not configs:
|
||||
return
|
||||
|
||||
logging.getLogger('asyncio').setLevel(logging.WARNING)
|
||||
|
||||
try:
|
||||
import textual # noqa: F401, PLC0415
|
||||
except ImportError: # pragma: no cover
|
||||
raise ValueError(
|
||||
'Unable to import the Textual library for the browse action; try installing "borgmatic[browse]"'
|
||||
)
|
||||
|
||||
import borgmatic.actions.browse.app # noqa: PLC0415
|
||||
|
||||
app = borgmatic.actions.browse.app.Browse_app(configs)
|
||||
app.run()
|
||||
@@ -0,0 +1,192 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import textual
|
||||
import textual.signal
|
||||
|
||||
import borgmatic.actions.browse.archive
|
||||
|
||||
logger = logging.getLogger('__name__')
|
||||
|
||||
|
||||
LOADING_DONE = object()
|
||||
|
||||
|
||||
class Archive_loaded(textual.signal.Signal):
|
||||
'''
|
||||
A signal that publishes when each subsequent archive is loaded from a repository, intended for
|
||||
consumption in widgets that display archives as they are loaded. This signal also publishes
|
||||
when loading is complete.
|
||||
|
||||
Each subscribed callback call includes the archive as an archive name string. Given the lack of
|
||||
other identifying information (configuration file, repository), there should be a separate
|
||||
Archive_loaded instance per repository.
|
||||
'''
|
||||
|
||||
|
||||
@textual.work(thread=True)
|
||||
def add_repository_archives(browse_app, archive_loaded, config, repository):
|
||||
'''
|
||||
Given a running Browse_app instance, an Archive_loaded instance, a configuration dict, and a
|
||||
repository dict, load a list of the archives from the repository and add them as options in the
|
||||
archives list. Reverse the order so the most recent archive is first.
|
||||
|
||||
This function runs in a separate thread from the main UI. When loading is complete, publish a
|
||||
loading done signal.
|
||||
'''
|
||||
archives_data = borgmatic.actions.browse.archive.get_repository_archives(config, repository)
|
||||
|
||||
# Reverse the archives, so the common case of accessing the latest archive is easy because it's
|
||||
# at the top.
|
||||
for archive in reversed(archives_data['archives']):
|
||||
archive_loaded.publish(archive['archive'])
|
||||
|
||||
archive_loaded.publish(LOADING_DONE)
|
||||
|
||||
|
||||
def record_path(archive_path, hierarchy, path_components):
|
||||
'''
|
||||
Given an Archive_path instance, a dict capturing a filesystem hierarchy of paths, and a tuple of
|
||||
path components for the archive path, set the archive path into the hierarchy data structure.
|
||||
|
||||
For instance, if given an archive path and path components representing "foo/bar/baz.txt",
|
||||
produce a hierarchy that looks like:
|
||||
|
||||
{'foo': {'bar': {'baz.txt': Archive_path('-', 'foo/bar/baz.txt', '')}}}
|
||||
|
||||
Note that the hierarchy is modified in place, so any existing paths there are retained.
|
||||
'''
|
||||
if len(path_components) == 1:
|
||||
hierarchy[path_components[0]] = {} if archive_path.path_type == 'd' else archive_path
|
||||
return
|
||||
|
||||
record_path(archive_path, hierarchy.setdefault(path_components[0], {}), path_components[1:])
|
||||
|
||||
|
||||
def get_paths(hierarchy, path_components, full_path_components=None):
|
||||
'''
|
||||
Given a dict capturing a filesystem hierarchy of paths (or a subset thereof), a tuple of path
|
||||
components for a directory path relative to the hierarchy root, and an optional tuple of
|
||||
*absolute* path components for the same path (if different), return a generator of the
|
||||
contained file and directory Archive_path instances from the hierarchy.
|
||||
|
||||
For instance, given the following hierarchy:
|
||||
|
||||
{'foo': {'bar': {'baz.txt': Archive_path('-', 'foo/bar/baz.txt', ''), 'quux': {}}}}
|
||||
|
||||
... and path components of ('foo', 'bar'), return a generator with the following:
|
||||
|
||||
* Archive_path('-', 'foo/bar/baz.txt', '')
|
||||
* Archive_path('d', 'foo/bar/quux', '')
|
||||
|
||||
The given absolute path components are use to construct directory paths like that last archive
|
||||
path.
|
||||
'''
|
||||
if full_path_components is None:
|
||||
full_path_components = path_components
|
||||
|
||||
if len(path_components) == 1:
|
||||
try:
|
||||
return (
|
||||
archive_path
|
||||
if isinstance(archive_path, borgmatic.actions.browse.archive.Archive_path)
|
||||
else borgmatic.actions.browse.archive.Archive_path(
|
||||
'd', os.path.join(*full_path_components, component), ''
|
||||
)
|
||||
for component, archive_path in hierarchy[path_components[0]].items()
|
||||
)
|
||||
except KeyError:
|
||||
raise ValueError(f'Unknown file or directory: {path_components[0]}')
|
||||
|
||||
try:
|
||||
return get_paths(hierarchy[path_components[0]], path_components[1:], full_path_components)
|
||||
except KeyError:
|
||||
raise ValueError(f'Unknown directory: {path_components[0]}')
|
||||
|
||||
|
||||
class Archive_path_loaded(textual.signal.Signal):
|
||||
'''
|
||||
A signal that publishes when each subsequent path is loaded from an archive, intended for
|
||||
consumption in widgets that display paths as they are loaded. This signal also tracks the
|
||||
complete filesystem hierarchy seen thus far, so new widgets that get created after loading has
|
||||
started can "catch up" with existing known paths. Lastly, this signal publishes and tracks when
|
||||
loading is complete.
|
||||
|
||||
Each subscrided callback call includes the loaded path as an Archive_path instance. There is
|
||||
intended to be a separate Archive_path_loaded instance per archive, but that instance should be
|
||||
shared among several different widgets for the same archive for performance reasons.
|
||||
'''
|
||||
|
||||
def __init__(self, owner, name):
|
||||
self.path_hierarchy = {}
|
||||
self.complete = False
|
||||
|
||||
super().__init__(owner, name)
|
||||
|
||||
def publish(self, archive_path):
|
||||
'''
|
||||
Publish the given archive path to subscribers and record its path locally. But if the
|
||||
archive path is actually LOADING_DONE, then record loading as complete.
|
||||
'''
|
||||
super().publish(archive_path)
|
||||
|
||||
if archive_path is LOADING_DONE:
|
||||
self.complete = True
|
||||
else:
|
||||
record_path(
|
||||
archive_path, self.path_hierarchy, archive_path.file_path.split(os.path.sep)
|
||||
)
|
||||
|
||||
|
||||
@textual.work(thread=True)
|
||||
def load_archive_paths(browse_app, path_loaded, config, repository, archive_name):
|
||||
'''
|
||||
Given a running Browse_app instance, an Archive_path_loaded instance, a configuration dict, a
|
||||
repository dict, and an archive name, load the paths in this archive and publish each one via
|
||||
the Archive_path_loaded signal, so interested widgets can subscribe. Also send a "loading done"
|
||||
signal when loading completes.
|
||||
|
||||
This function runs in a separate thread from the main UI. When loading is complete, publish a
|
||||
loading done signal.
|
||||
'''
|
||||
for archive_path in borgmatic.actions.browse.archive.get_archive_paths(
|
||||
config, repository, archive_name
|
||||
):
|
||||
path_loaded.publish(archive_path)
|
||||
|
||||
path_loaded.publish(LOADING_DONE)
|
||||
|
||||
|
||||
class File_preview_loaded(textual.signal.Signal):
|
||||
'''
|
||||
A signal that publishes when file contents are loaded from an archive, intended for consumption
|
||||
in widgets that display loaded files. This signal also publishes when loading is complete.
|
||||
|
||||
Each published callback includes a the file's contents as a string. Given the lack of other
|
||||
identifying information (configuration file, repository, archive), there should be a separate
|
||||
Archive_loaded instance per previewed file.
|
||||
'''
|
||||
|
||||
|
||||
@textual.work(thread=True)
|
||||
def load_file_preview(
|
||||
browse_app,
|
||||
file_preview_loaded,
|
||||
config,
|
||||
repository,
|
||||
archive_name,
|
||||
file_path,
|
||||
):
|
||||
'''
|
||||
Given a running Browse_app instance, a File_preview_loaded instance, a configuration dict, a
|
||||
repository dict, an archive name, and the path of a file in that archive, load the contents of
|
||||
the file and write it into the given file preview widget.
|
||||
|
||||
This function runs in a separate thread from the main UI. When loading is complete, publish a
|
||||
loading done signal.
|
||||
'''
|
||||
file_contents = borgmatic.actions.browse.archive.get_archive_file_content(
|
||||
config, repository, archive_name, file_path
|
||||
)
|
||||
|
||||
file_preview_loaded.publish(file_contents)
|
||||
@@ -374,7 +374,9 @@ def create_archive(
|
||||
|
||||
if json:
|
||||
output_log_level = None
|
||||
elif config.get('list_details') or (config.get('statistics') and not dry_run):
|
||||
elif config.get('list_details') or (
|
||||
(config.get('statistics') or config.get('quick_statistics')) and not dry_run
|
||||
):
|
||||
output_log_level = logging.ANSWER
|
||||
else:
|
||||
output_log_level = logging.INFO
|
||||
@@ -386,6 +388,11 @@ def create_archive(
|
||||
create_flags += (
|
||||
(('--info',) if logger.getEffectiveLevel() == logging.INFO and not json else ())
|
||||
+ (('--stats',) if config.get('statistics') and not json and not dry_run else ())
|
||||
+ (
|
||||
('--quick-stats',)
|
||||
if config.get('quick_statistics') and not json and not dry_run
|
||||
else ()
|
||||
)
|
||||
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) and not json else ())
|
||||
+ (('--progress',) if config.get('progress') else ())
|
||||
+ (('--json',) if json else ())
|
||||
|
||||
@@ -115,10 +115,10 @@ def capture_archive_listing(
|
||||
Given a local or remote repository path, an archive name, a configuration dict, the local Borg
|
||||
version, global arguments as an argparse.Namespace, the archive paths (or Borg patterns) in
|
||||
which to list files, the Borg path format indicating keys to include in the output, and local
|
||||
and remote Borg paths, capture the output of listing that archive and return it as a sequence of
|
||||
dicts, one per path.
|
||||
and remote Borg paths, capture the output of listing that archive and return it as a generator
|
||||
of dicts, one per path.
|
||||
'''
|
||||
return tuple(
|
||||
return (
|
||||
json.loads(entry)
|
||||
for entry in execute_command_and_capture_output(
|
||||
make_list_command(
|
||||
|
||||
@@ -31,9 +31,10 @@ ACTION_ALIASES = {
|
||||
'transfer': [],
|
||||
'break-lock': [],
|
||||
'key': [],
|
||||
'borg': [],
|
||||
'recreate': [],
|
||||
'diff': [],
|
||||
'browse': [],
|
||||
'borg': [],
|
||||
}
|
||||
|
||||
|
||||
@@ -324,7 +325,7 @@ def make_argument_description(schema, flag_name):
|
||||
' To specify a different list element, replace the "[0]" with another array index ("[1]", "[2]", etc.).',
|
||||
)
|
||||
|
||||
if example and schema_type in ('array', 'object'): # noqa: PLR6201
|
||||
if example and schema_type in ('array', 'object'):
|
||||
example_buffer = io.StringIO()
|
||||
yaml = ruamel.yaml.YAML(typ='safe')
|
||||
yaml.default_flow_style = True
|
||||
@@ -896,6 +897,13 @@ def make_parsers(schema, unparsed_arguments): # noqa: PLR0915
|
||||
action='store_true',
|
||||
help='Display statistics of archive',
|
||||
)
|
||||
create_group.add_argument(
|
||||
'--quick-stats',
|
||||
dest='quick_statistics',
|
||||
default=None,
|
||||
action='store_true',
|
||||
help='Display statistics of archive, skipping repository-wide "All archives" and chunk index statistics [Borg 1.4.5+ only]',
|
||||
)
|
||||
create_group.add_argument(
|
||||
'--list',
|
||||
'--files',
|
||||
@@ -1997,8 +2005,9 @@ def make_parsers(schema, unparsed_arguments): # noqa: PLR0915
|
||||
diff_parser = action_parsers.add_parser(
|
||||
'diff',
|
||||
aliases=ACTION_ALIASES['diff'],
|
||||
help='This command finds differences (file contents, user/group/mode) between archives',
|
||||
description='This command finds differences (file contents, user/group/mode) between archives',
|
||||
help='Find differences (file contents, user/group/mode) between archives',
|
||||
description='Find differences (file contents, user/group/mode) between archives',
|
||||
add_help=False,
|
||||
)
|
||||
diff_group = diff_parser.add_argument_group('diff arguments')
|
||||
diff_group.add_argument(
|
||||
@@ -2035,6 +2044,18 @@ def make_parsers(schema, unparsed_arguments): # noqa: PLR0915
|
||||
action='store_true',
|
||||
help='Run the diff according to borgmatic configured patterns (ie do not diff entire archives)',
|
||||
)
|
||||
diff_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||
|
||||
browse_parser = action_parsers.add_parser(
|
||||
'browse',
|
||||
aliases=ACTION_ALIASES['browse'],
|
||||
help='Browse repositories, archives, and files in a console UI',
|
||||
description='Browse repositories, archives, and files in a console UI',
|
||||
add_help=False,
|
||||
)
|
||||
browse_group = browse_parser.add_argument_group('browse arguments')
|
||||
browse_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||
|
||||
borg_parser = action_parsers.add_parser(
|
||||
'borg',
|
||||
aliases=ACTION_ALIASES['borg'],
|
||||
@@ -2107,7 +2128,7 @@ def parse_arguments(schema, *unparsed_arguments):
|
||||
)
|
||||
|
||||
if (
|
||||
('list' in arguments and 'repo-info' in arguments and arguments['list'].json) # noqa: PLR0916
|
||||
('list' in arguments and 'repo-info' in arguments and arguments['list'].json)
|
||||
or ('list' in arguments and 'info' in arguments and arguments['list'].json)
|
||||
or ('repo-info' in arguments and 'info' in arguments and arguments['repo-info'].json)
|
||||
):
|
||||
@@ -2125,7 +2146,7 @@ def parse_arguments(schema, *unparsed_arguments):
|
||||
'With the repo-list action, only one of --prefix or --match-archives flags can be used.',
|
||||
)
|
||||
|
||||
if 'info' in arguments and ( # noqa: PLR0916
|
||||
if 'info' in arguments and (
|
||||
(arguments['info'].archive and arguments['info'].prefix)
|
||||
or (arguments['info'].archive and arguments['info'].match_archives)
|
||||
or (arguments['info'].prefix and arguments['info'].match_archives)
|
||||
|
||||
@@ -12,6 +12,7 @@ import ruamel.yaml
|
||||
|
||||
import borgmatic.actions.borg
|
||||
import borgmatic.actions.break_lock
|
||||
import borgmatic.actions.browse.run
|
||||
import borgmatic.actions.change_passphrase
|
||||
import borgmatic.actions.check
|
||||
import borgmatic.actions.compact
|
||||
@@ -211,7 +212,7 @@ def run_configuration(config_filename, config, config_paths, arguments): # noqa
|
||||
f"Skipping {'/'.join(skip_actions)} action{'s' if len(skip_actions) > 1 else ''} due to configured skip_actions",
|
||||
)
|
||||
|
||||
try: # noqa: PLR1702
|
||||
try:
|
||||
with (
|
||||
Monitoring_hooks(config_filename, config, arguments, global_arguments),
|
||||
borgmatic.hooks.command.Before_after_hooks(
|
||||
@@ -825,8 +826,8 @@ def collect_highlander_action_summary_logs(configs, arguments, configuration_par
|
||||
try:
|
||||
if 'bootstrap' in arguments:
|
||||
try:
|
||||
# No configuration file is needed for bootstrap.
|
||||
local_borg_version = borg_version.local_borg_version(
|
||||
# No configuration file is needed for bootstrap.
|
||||
{},
|
||||
arguments['bootstrap'].local_path,
|
||||
)
|
||||
@@ -897,6 +898,13 @@ def collect_highlander_action_summary_logs(configs, arguments, configuration_par
|
||||
|
||||
return
|
||||
|
||||
if 'browse' in arguments:
|
||||
borgmatic.actions.browse.run.run_browse(
|
||||
arguments['browse'],
|
||||
arguments['global'],
|
||||
configs,
|
||||
)
|
||||
|
||||
except (
|
||||
CalledProcessError,
|
||||
ValueError,
|
||||
|
||||
@@ -1091,6 +1091,15 @@ properties:
|
||||
Corresponds to the "--stats" flag on those actions. Defaults to
|
||||
false.
|
||||
example: true
|
||||
quick_statistics:
|
||||
type: boolean
|
||||
description: |
|
||||
Display statistics for an archive when running supported actions,
|
||||
skipping the repository-wide "All archives" and chunk index
|
||||
statistics to save some time. Corresponds to the "--quick-stats"
|
||||
flag on those actions. Defaults to false. (This option is supported
|
||||
for Borg 1.4.5+ only.)
|
||||
example: true
|
||||
list_details:
|
||||
type: boolean
|
||||
description: |
|
||||
@@ -1131,8 +1140,9 @@ properties:
|
||||
- info
|
||||
- break-lock
|
||||
- key
|
||||
- borg
|
||||
- diff
|
||||
- browse
|
||||
- borg
|
||||
description: |
|
||||
List of one or more actions to skip running for this configuration
|
||||
file, even if specified on the command-line (explicitly or
|
||||
@@ -1348,8 +1358,9 @@ properties:
|
||||
- info
|
||||
- break-lock
|
||||
- key
|
||||
- borg
|
||||
- diff
|
||||
- browse
|
||||
- borg
|
||||
description: |
|
||||
List of actions for which the commands will be
|
||||
run. Defaults to running for all actions.
|
||||
@@ -1414,8 +1425,9 @@ properties:
|
||||
- info
|
||||
- break-lock
|
||||
- key
|
||||
- borg
|
||||
- diff
|
||||
- browse
|
||||
- borg
|
||||
description: |
|
||||
Only trigger the hook when borgmatic is run with
|
||||
particular actions listed here. Defaults to
|
||||
@@ -2825,7 +2837,9 @@ properties:
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
description: URL of this Apprise service.
|
||||
description: |
|
||||
URL of this Apprise service. Supports the
|
||||
"{credential ...}" syntax.
|
||||
example: "gotify://hostname/token"
|
||||
label:
|
||||
type: string
|
||||
|
||||
+31
-7
@@ -372,13 +372,21 @@ def log_buffer_lines(
|
||||
yield log_record.getMessage()
|
||||
|
||||
|
||||
def raise_for_process_errors(buffer_readers, process_metadatas, borg_local_path, borg_exit_codes):
|
||||
def raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level,
|
||||
borg_local_path,
|
||||
borg_exit_codes,
|
||||
capture_stderr=False,
|
||||
):
|
||||
'''
|
||||
Given a dict from buffer object to Buffer_reader, a dict from subprocess.Popen() instance to
|
||||
Process_metadata instance, Borg's local path, a sequence of exit code configuration dicts, check
|
||||
the given processes for error or warning exit codes. If found, vent or kill any running
|
||||
processes. In the case of an error exit code, raise. In the case of warning, return
|
||||
Exit_status.WARNING. Otherwise, return None.
|
||||
Process_metadata instance, a requested output log level for stdout, Borg's local path, a
|
||||
sequence of exit code configuration dicts, and whether to capture stderr, check the given
|
||||
processes for error or warning exit codes. If found, vent or kill any running processes and
|
||||
drain any remaining buffer lines. In the case of an error exit code, raise. In the case of
|
||||
warning, return Exit_status.WARNING. Otherwise, return None.
|
||||
'''
|
||||
result_status = None
|
||||
|
||||
@@ -404,6 +412,13 @@ def raise_for_process_errors(buffer_readers, process_metadatas, borg_local_path,
|
||||
result_status = Exit_status.WARNING
|
||||
continue
|
||||
|
||||
# Drain and log remaining buffer lines, so no output gets lost. But swallow captured output,
|
||||
# since we're raising below instead of yielding captured lines.
|
||||
tuple(
|
||||
log_remaining_buffer_lines(
|
||||
buffer_readers, process_metadatas, output_log_level, borg_local_path, capture_stderr
|
||||
)
|
||||
)
|
||||
last_lines = process_metadatas[process].last_lines
|
||||
|
||||
# If an error occurs, include its output in the raised exception so that we don't
|
||||
@@ -429,6 +444,9 @@ def log_remaining_buffer_lines(
|
||||
whether to capture stderr, drain and log any remaining output lines from the buffers until
|
||||
they're empty. Additionally, for any log records with a log level the same as the output log
|
||||
level, yield those log messages for capture.
|
||||
|
||||
The main difference between this function and log_buffer_lines() is that this one doesn't just
|
||||
do one "turn of the crank" of logging buffer output; it completely drains any remaining output.
|
||||
'''
|
||||
for output_buffer, reader in buffer_readers.items():
|
||||
if not reader.process:
|
||||
@@ -446,6 +464,7 @@ def log_remaining_buffer_lines(
|
||||
borg_local_path=borg_local_path,
|
||||
command=reader.process.args,
|
||||
),
|
||||
last_lines=process_metadatas[reader.process].last_lines,
|
||||
)
|
||||
|
||||
if (
|
||||
@@ -494,7 +513,7 @@ def log_outputs(
|
||||
for buffer in output_buffers_for_process(process, exclude_stdouts)
|
||||
}
|
||||
|
||||
# Log output lines for each process until they all exit.
|
||||
# Log output lines for each process until they all exit or one errors.
|
||||
while True:
|
||||
yield from log_buffer_lines(
|
||||
buffer_readers, process_metadatas, output_log_level, borg_local_path, capture_stderr
|
||||
@@ -502,7 +521,12 @@ def log_outputs(
|
||||
|
||||
if (
|
||||
raise_for_process_errors(
|
||||
buffer_readers, process_metadatas, borg_local_path, borg_exit_codes
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level,
|
||||
borg_local_path,
|
||||
borg_exit_codes,
|
||||
capture_stderr,
|
||||
)
|
||||
== Exit_status.WARNING
|
||||
):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import operator
|
||||
|
||||
import borgmatic.hooks.credential.parse
|
||||
import borgmatic.hooks.monitoring.logs
|
||||
import borgmatic.hooks.monitoring.monitor
|
||||
|
||||
@@ -44,7 +45,9 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||
import apprise # noqa: PLC0415
|
||||
from apprise import NotifyFormat, NotifyType # noqa: PLC0415
|
||||
except ImportError: # pragma: no cover
|
||||
logger.warning('Unable to import Apprise in monitoring hook')
|
||||
logger.warning(
|
||||
'Unable to import Apprise in its monitoring hook; try installing "borgmatic[Apprise]"'
|
||||
)
|
||||
return
|
||||
|
||||
state_to_notify_type = {
|
||||
@@ -76,7 +79,12 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||
logger.info(f'Pinging Apprise services: {labels_string}{dry_run_string}')
|
||||
|
||||
apprise_object = apprise.Apprise()
|
||||
apprise_object.add(list(map(operator.itemgetter('url'), hook_config.get('services'))))
|
||||
apprise_object.add(
|
||||
[
|
||||
borgmatic.hooks.credential.parse.resolve_credential(service['url'], config)
|
||||
for service in hook_config.get('services')
|
||||
]
|
||||
)
|
||||
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
+1
-1
@@ -169,7 +169,7 @@ class Json_formatter(logging.Formatter):
|
||||
def __init__(self, fmt='{message}', *args, style='{', **kwargs):
|
||||
super().__init__(*args, fmt=fmt, style=style, **kwargs)
|
||||
|
||||
def format(self, record): # noqa: PLR6301
|
||||
def format(self, record):
|
||||
return log_record_to_json(record)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ RUN apk add --no-cache py3-pip py3-ruamel.yaml py3-ruamel.yaml.clib
|
||||
RUN pip install --break-system-packages --no-cache /app && borgmatic config generate && borgmatic config generate --destination /etc/borgmatic --split && chmod +r /etc/borgmatic/*.yaml
|
||||
RUN mkdir /command-line \
|
||||
&& borgmatic --help > /command-line/global.txt \
|
||||
&& for action in repo-create transfer create prune compact check delete extract config "config bootstrap" "config generate" "config validate" "config show" export-tar mount umount repo-delete restore repo-list list repo-info info break-lock "key export" "key import" "key change-passphrase" recreate diff borg; do \
|
||||
&& for action in repo-create transfer create prune compact check delete extract config "config bootstrap" "config generate" "config validate" "config show" export-tar mount umount repo-delete restore repo-list list repo-info info break-lock "key export" "key import" "key change-passphrase" recreate diff browse borg; do \
|
||||
borgmatic $action --help > /command-line/${action/ /-}.txt; done
|
||||
RUN /app/docs/fetch-contributors >> /contributors.html
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Here's the command-line help for this action in the [most recent version of
|
||||
borgmatic](https://projects.torsion.org/borgmatic-collective/borgmatic/releases).
|
||||
If you're using an older version, some of these flags may not work, and you
|
||||
should instead run the action with `--help` to see the flags specific to your
|
||||
borgmatic version.
|
||||
If you're using an older version, some of these flags may not work (or the action
|
||||
may be missing entirely). You should instead run the action with `--help` to see
|
||||
the flags and actions specific to your borgmatic version.
|
||||
|
||||
@@ -31,7 +31,7 @@ changes work:
|
||||
```bash
|
||||
cd borgmatic
|
||||
uv tool update-shell
|
||||
uv tool install --editable .
|
||||
uv tool install --editable .[dev]
|
||||
```
|
||||
|
||||
Or to work on the [Apprise
|
||||
@@ -39,7 +39,14 @@ hook](https://torsion.org/borgmatic/reference/configuration/monitoring/apprise/)
|
||||
change that last line to:
|
||||
|
||||
```bash
|
||||
uv tool install --editable .[Apprise]
|
||||
uv tool install --editable .[dev,Apprise]
|
||||
```
|
||||
|
||||
Or to work on the [browse
|
||||
action](https://torsion.org/borgmatic/reference/command-line/actions/browse/):
|
||||
|
||||
```bash
|
||||
uv tool install --editable .[dev,browse]
|
||||
```
|
||||
|
||||
To get oriented with the borgmatic source code, have a look at the [source
|
||||
|
||||
@@ -135,3 +135,52 @@ is, patterns are _not_ taken into consideration. If you require this, supply the
|
||||
|
||||
See the [Borg](https://borgbackup.readthedocs.io/en/stable/usage/diff.html)
|
||||
documentation for information on output format, what is compared, and more.
|
||||
|
||||
|
||||
## Browsing backups
|
||||
|
||||
<span class="minilink minilink-addedin">New in version 2.1.6</span> <span
|
||||
class="minilink minilink-addedin">Experimental feature</span> borgmatic has an
|
||||
experimental console UI for browsing your repositories, archives, and files.
|
||||
Here's what it looks like:
|
||||
|
||||
<img src="https://torsion.org/borgmatic/static/browse.png" alt="borgmatic browse screenshot" style="width: 100%">
|
||||
|
||||
This feature is not intended to be a general-purpose Borg UI with every
|
||||
borgmatic feature, but rather it's for use cases like quickly looking at the
|
||||
contents of your backups when you're feeling too lazy to type out a full
|
||||
borgmatic command-line.
|
||||
|
||||
Depending on how you installed borgmatic, it may not have come with the
|
||||
necessary Python libraries to support the browse action. (borgmatic's
|
||||
[stand-alone
|
||||
binary](https://projects.torsion.org/borgmatic-collective/borgmatic/releases)
|
||||
does not currently include them.) If you originally [installed borgmatic with
|
||||
uv](https://torsion.org/borgmatic/how-to/install-borgmatic/), run the following
|
||||
to install the libraries needed for the browse action:
|
||||
|
||||
```bash
|
||||
sudo uv tool install borgmatic[browse]
|
||||
```
|
||||
|
||||
Omit `sudo` if borgmatic is installed as a non-root user.
|
||||
|
||||
Once the libraries are installed, run the following to access the browse action:
|
||||
|
||||
```bash
|
||||
borgmatic browse
|
||||
```
|
||||
|
||||
This launches a console UI where you can select a borgmatic configuration file
|
||||
(if there's more than one), select a Borg repository, select an archive in that
|
||||
repository, and even browse the backed up files in that archive.
|
||||
|
||||
Use the keyboard or the mouse to navigate the UI. The footer at the bottom of
|
||||
the screen shows some of the available keys. Logs show up directly in the UI at
|
||||
the [selected
|
||||
verbosity](https://torsion.org/borgmatic/reference/command-line/logging/),
|
||||
although logs are hidden by default.
|
||||
|
||||
Please [provide
|
||||
feedback](https://torsion.org/borgmatic/#support-and-contributing) if you find
|
||||
this feature useful—or even if you don't, but would like it to become useful.
|
||||
|
||||
@@ -98,7 +98,7 @@ installing borgmatic:
|
||||
|
||||
#### Etc.
|
||||
|
||||
* [stand-alone Linux binary](https://projects.torsion.org/borgmatic-collective/borgmatic/releases) (This is a beta feature!)
|
||||
* [stand-alone Linux binary](https://projects.torsion.org/borgmatic-collective/borgmatic/releases) (This is a beta feature! The minimal binary omits [Apprise support](https://torsion.org/borgmatic/reference/configuration/monitoring/apprise/).)
|
||||
* [Ansible role](https://github.com/borgbase/ansible-role-borgbackup)
|
||||
* [pipx](https://pipx.pypa.io/stable/)
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: browse
|
||||
eleventyNavigation:
|
||||
key: browse
|
||||
parent: 🎬 Actions
|
||||
---
|
||||
|
||||
<span class="minilink minilink-addedin">Experimental feature</span> {% include snippet/command-line/sample.md %}
|
||||
|
||||
```
|
||||
{% include borgmatic/command-line/browse.txt %}
|
||||
```
|
||||
|
||||
|
||||
## Related documentation
|
||||
|
||||
* [Inspect your backups](https://torsion.org/borgmatic/how-to/inspect-your-backups/)
|
||||
@@ -24,9 +24,14 @@ databases](https://torsion.org/borgmatic/how-to/backup-your-databases/#all-datab
|
||||
borgmatic excludes most data coming from [MariaDB system
|
||||
databases](https://mariadb.com/docs/server/reference/system-tables),
|
||||
because much of it is populated on MariaDB startup and thus not restorable (or
|
||||
just unnecessary to backup). The system data that borgmatic does include in
|
||||
these dumps are: users, roles, grants, user-defined functions, and remote
|
||||
servers.
|
||||
just unnecessary to backup).
|
||||
|
||||
The system data that borgmatic does include in these dumps are: users, roles,
|
||||
grants, user-defined functions, and remote servers—all from the `mysql` system
|
||||
database. This omits all other data from the `mysql` database, which includes
|
||||
index and table statistics, time zones, and installed server plugins. It also
|
||||
excludes the separate `information_schema`, `performance_schema`, and `sys`
|
||||
system databases. This is not currently configurable.
|
||||
|
||||
Within a Borg archive, you can find this data stored in a dump named `mysql`—the
|
||||
name of the system table this data comes from. And if you'd like to dump this
|
||||
|
||||
@@ -5,9 +5,9 @@ eleventyNavigation:
|
||||
parent: 🚨 Monitoring
|
||||
---
|
||||
<span class="minilink minilink-addedin">New in version 1.8.4</span>
|
||||
[Apprise](https://github.com/caronc/apprise/wiki) is a local notification library
|
||||
[Apprise](https://appriseit.com/) is a local notification library
|
||||
that "allows you to send a notification to almost all of the most popular
|
||||
[notification services](https://github.com/caronc/apprise/wiki) available to
|
||||
[notification services](https://appriseit.com/services/) available to
|
||||
us today such as: Telegram, Discord, Slack, Amazon SNS, Gotify, etc."
|
||||
|
||||
Depending on how you installed borgmatic, it may not have come with Apprise.
|
||||
@@ -22,7 +22,7 @@ sudo uv tool install borgmatic[Apprise]
|
||||
Omit `sudo` if borgmatic is installed as a non-root user.
|
||||
|
||||
Once Apprise is installed, configure borgmatic to notify one or more [Apprise
|
||||
services](https://github.com/caronc/apprise/wiki). For example:
|
||||
services](https://appriseit.com/services/). For example:
|
||||
|
||||
```yaml
|
||||
apprise:
|
||||
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
+7
-4
@@ -1,17 +1,18 @@
|
||||
[project]
|
||||
name = "borgmatic"
|
||||
version = "2.1.6.dev0"
|
||||
version = "2.1.6"
|
||||
authors = [
|
||||
{ name="Dan Helfman", email="witten@torsion.org" },
|
||||
]
|
||||
description = "Simple, configuration-driven backup software for servers and workstations"
|
||||
license = "GPL-3.0-or-later"
|
||||
license-files = ["LICENSE"]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: System Administrators",
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
"Programming Language :: Python",
|
||||
"Topic :: Security :: Cryptography",
|
||||
"Topic :: System :: Archiving :: Backup",
|
||||
@@ -30,6 +31,8 @@ validate-borgmatic-config = "borgmatic.commands.validate_config:main"
|
||||
|
||||
[project.optional-dependencies]
|
||||
Apprise = ["apprise"]
|
||||
browse = ["textual", "binaryornot"]
|
||||
browse-dev = ["textual-dev"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://torsion.org/borgmatic"
|
||||
@@ -44,7 +47,7 @@ namespaces = false
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = "tests"
|
||||
addopts = "--cov-report term-missing:skip-covered --cov=borgmatic --no-cov-on-fail --cov-fail-under=100 --ignore=tests/end-to-end --timeout=120"
|
||||
addopts = "--cov-report term-missing:skip-covered --cov=borgmatic --no-cov-on-fail --cov-fail-under=100 --ignore=tests/end-to-end --timeout=120 --asyncio-mode=auto"
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
@@ -54,7 +57,7 @@ exclude = ["*.*/*"]
|
||||
quote-style = "preserve"
|
||||
|
||||
[tool.ruff.lint]
|
||||
preview = true
|
||||
preview = false
|
||||
extend-select = [
|
||||
"A", # flake8-builtins: builtin shadowing
|
||||
"B", # flake8-bugbear: bugs and design problems
|
||||
|
||||
+12
-3
@@ -43,15 +43,19 @@ twine upload -r pypi --username __token__ "$wheel_path"
|
||||
scripts/export-docs-from-image
|
||||
docs_path=dist/borgmatic-docs.tar.gz
|
||||
|
||||
# Build stand-alone binary.
|
||||
# Build stand-alone binaries.
|
||||
uv venv --python 3.13 --clear binary
|
||||
source binary/bin/activate
|
||||
uv pip install -r binary_requirements.txt nuitka[onefile]
|
||||
nuitka --mode=onefile --enable-plugin=upx --include-package-data=borgmatic --include-data-dir=borgmatic.egg-info=borgmatic.egg-info --include-package=borgmatic.hooks --include-package=apprise --no-deployment-flag=self-execution borgmatic/commands/borgmatic.py
|
||||
deactivate
|
||||
rm -fr binary borgmatic.build borgmatic.dist
|
||||
rm -fr borgmatic.build borgmatic.dist
|
||||
standalone_binary_path="dist/borgmatic-${version}-binary-linux-glibc-x86_64"
|
||||
mv borgmatic.bin "$standalone_binary_path"
|
||||
nuitka --mode=onefile --enable-plugin=upx --include-package-data=borgmatic --include-data-dir=borgmatic.egg-info=borgmatic.egg-info --include-package=borgmatic.hooks --no-deployment-flag=self-execution borgmatic/commands/borgmatic.py
|
||||
rm -fr binary borgmatic.build borgmatic.dist
|
||||
deactivate
|
||||
standalone_minimal_binary_path="dist/borgmatic-${version}-minimal-binary-linux-glibc-x86_64"
|
||||
mv borgmatic.bin "$standalone_minimal_binary_path"
|
||||
|
||||
# Set release changelogs on projects.torsion.org and GitHub.
|
||||
release_changelog="$(cat NEWS | sed '/^$/q' | grep -v '^\S')"
|
||||
@@ -83,6 +87,11 @@ curl --silent --request POST \
|
||||
--header "Authorization: token $projects_token" \
|
||||
--header "Accept: application/json" \
|
||||
--form attachment=@"$standalone_binary_path"
|
||||
curl --silent --request POST \
|
||||
"https://projects.torsion.org/api/v1/repos/borgmatic-collective/borgmatic/releases/$release_id/assets?name=$(basename $standalone_minimal_binary_path)" \
|
||||
--header "Authorization: token $projects_token" \
|
||||
--header "Accept: application/json" \
|
||||
--form attachment=@"$standalone_minimal_binary_path"
|
||||
|
||||
github-release create --token="$github_token" --owner=witten --repo=borgmatic --tag="$version" --target_commit="main" \
|
||||
--name="borgmatic $version" --body="$release_changelog"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
apprise
|
||||
attrs
|
||||
binaryornot
|
||||
certifi
|
||||
charset-normalizer
|
||||
click>=8.1.8
|
||||
@@ -16,13 +17,16 @@ packaging
|
||||
pluggy
|
||||
pygments
|
||||
pytest
|
||||
pytest-asyncio
|
||||
pytest-cov
|
||||
pytest-timeout
|
||||
pyyaml>5.0.0
|
||||
referencing
|
||||
requests
|
||||
requests-oauthlib
|
||||
rich
|
||||
rpds-py
|
||||
ruamel-yaml>0.15.0
|
||||
textual
|
||||
typing-extensions
|
||||
urllib3
|
||||
|
||||
+18
-8
@@ -2,29 +2,39 @@
|
||||
# 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
|
||||
certifi==2026.4.22 # via apprise, requests, -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
|
||||
codespell==2.4.2 # via -r test_requirements.in
|
||||
coverage==7.13.5 # via pytest-cov, -r test_requirements.in
|
||||
coverage==7.14.0 # via pytest-cov, -r test_requirements.in
|
||||
flexmock==0.13.0 # via -r test_requirements.in
|
||||
idna==3.13 # via requests, -r test_requirements.in
|
||||
idna==3.16 # via requests, -r test_requirements.in
|
||||
iniconfig==2.3.0 # via pytest, -r test_requirements.in
|
||||
jsonschema==4.26.0 # via -r test_requirements.in
|
||||
jsonschema-specifications==2025.9.1 # via jsonschema, -r test_requirements.in
|
||||
linkify-it-py==2.1.0 # via markdown-it-py
|
||||
markdown==3.10.2 # via apprise, -r test_requirements.in
|
||||
markdown-it-py==4.2.0 # via mdit-py-plugins, rich, textual
|
||||
mdit-py-plugins==0.6.1 # via textual
|
||||
mdurl==0.1.2 # via markdown-it-py
|
||||
oauthlib==3.3.1 # via requests-oauthlib, -r test_requirements.in
|
||||
packaging==26.2 # via pytest, -r test_requirements.in
|
||||
platformdirs==4.9.6 # via textual
|
||||
pluggy==1.6.0 # via pytest, pytest-cov, -r test_requirements.in
|
||||
pygments==2.20.0 # via pytest, -r test_requirements.in
|
||||
pytest==9.0.3 # via pytest-cov, pytest-timeout, -r test_requirements.in
|
||||
pygments==2.20.0 # via pytest, rich, textual, -r test_requirements.in
|
||||
pytest==9.0.3 # via pytest-asyncio, pytest-cov, pytest-timeout, -r test_requirements.in
|
||||
pytest-asyncio==1.3.0 # via -r test_requirements.in
|
||||
pytest-cov==7.1.0 # via -r test_requirements.in
|
||||
pytest-timeout==2.4.0 # via -r test_requirements.in
|
||||
pyyaml>5.0.0
|
||||
referencing==0.37.0 # via jsonschema, jsonschema-specifications, -r test_requirements.in
|
||||
requests==2.33.1 # via apprise, requests-oauthlib, -r test_requirements.in
|
||||
requests==2.34.2 # via apprise, requests-oauthlib, -r test_requirements.in
|
||||
requests-oauthlib==2.0.0 # via apprise, -r test_requirements.in
|
||||
rich==15.0.0 # via textual, -r test_requirements.in
|
||||
rpds-py==0.30.0 # via jsonschema, referencing, -r test_requirements.in
|
||||
ruamel-yaml>0.15.0
|
||||
typing-extensions==4.15.0 # via -r test_requirements.in
|
||||
urllib3==2.6.3 # via requests, -r test_requirements.in
|
||||
textual==8.2.7 # via -r test_requirements.in
|
||||
typing-extensions==4.15.0 # via textual, -r test_requirements.in
|
||||
uc-micro-py==2.0.0 # via linkify-it-py
|
||||
urllib3==2.7.0 # via requests, -r test_requirements.in
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
import borgmatic.actions.browse.app
|
||||
import borgmatic.actions.browse.configuration_files_list
|
||||
import borgmatic.actions.browse.logs
|
||||
import borgmatic.actions.browse.repositories_list
|
||||
|
||||
|
||||
async def test_browse_app_with_multiple_configs_uses_configuration_files_list():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test():
|
||||
app.query_one(selector='Header')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].configs == app.configs
|
||||
|
||||
app.query_one(selector='Logs')
|
||||
app.query_one(selector='Footer')
|
||||
|
||||
|
||||
async def test_browse_app_with_one_config_uses_repositories_list():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test():
|
||||
app.query_one(selector='Header')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
assert isinstance(
|
||||
carousel.panels[0], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[0].config == app.configs['test1.yaml']
|
||||
|
||||
app.query_one(selector='Logs')
|
||||
app.query_one(selector='Footer')
|
||||
|
||||
|
||||
async def test_browse_app_key_toggles_logs_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
logs_panel = app.query_one('#logs')
|
||||
|
||||
await pilot.press('v')
|
||||
await pilot.pause()
|
||||
assert logs_panel.styles.display == 'block'
|
||||
@@ -0,0 +1,86 @@
|
||||
import textual.app
|
||||
import textual.widgets.option_list
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import archives_list as module
|
||||
|
||||
|
||||
async def test_archives_list_on_mount_does_not_raise():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
flexmock(archives_list.archive_loaded).should_receive('subscribe')
|
||||
|
||||
async with textual.app.App().run_test():
|
||||
archives_list.on_mount()
|
||||
|
||||
|
||||
def test_archives_list_on_archive_loaded_with_loading_done_removes_loading_indicator():
|
||||
loading_timer = flexmock()
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive(
|
||||
'add_inline_loading_indicator'
|
||||
).and_return(loading_timer)
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
flexmock(loading_timer).should_receive('stop')
|
||||
flexmock(archives_list).should_receive('remove_option').with_args('loading-indicator').once()
|
||||
flexmock(archives_list).should_receive('add_options').never()
|
||||
|
||||
archives_list.on_archive_loaded(module.borgmatic.actions.browse.workers.LOADING_DONE)
|
||||
|
||||
|
||||
def test_archives_list_on_archive_loaded_adds_archive_name():
|
||||
loading_timer = flexmock()
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive(
|
||||
'add_inline_loading_indicator'
|
||||
).and_return(loading_timer)
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
flexmock(loading_timer).should_receive('stop').never()
|
||||
loading_indicator = flexmock()
|
||||
flexmock(archives_list).should_receive('get_option').and_return(loading_indicator)
|
||||
flexmock(archives_list).should_receive('remove_option').with_args('loading-indicator').once()
|
||||
flexmock(archives_list).should_receive('add_options').once()
|
||||
|
||||
archives_list.on_archive_loaded('archive')
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_none_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.highlighted = None
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_zero_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.highlighted = 0
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_existing_option_and_highlighted_zero_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.add_option(textual.widgets.option_list.Option('zero', id='zero'))
|
||||
archives_list.highlighted = 0
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_archives_list_on_option_list_option_highlighted_with_highlighted_non_zero_marks_it_changed():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
|
||||
archives_list = module.Archives_list(config=flexmock(), repository=flexmock())
|
||||
archives_list.add_option(textual.widgets.option_list.Option('zero', id='zero'))
|
||||
archives_list.add_option(textual.widgets.option_list.Option('one', id='one'))
|
||||
archives_list.highlighted = 1
|
||||
archives_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert archives_list.highlighted_option_changed is True
|
||||
@@ -0,0 +1,522 @@
|
||||
import pytest
|
||||
import textual.widgets.option_list
|
||||
from flexmock import flexmock
|
||||
|
||||
import borgmatic.actions.browse.app
|
||||
import borgmatic.actions.browse.archive
|
||||
import borgmatic.actions.browse.carousel
|
||||
import borgmatic.actions.browse.loading
|
||||
import borgmatic.actions.browse.logs
|
||||
import borgmatic.actions.browse.workers
|
||||
from borgmatic.actions.browse import carousel as module
|
||||
|
||||
|
||||
def test_make_next_panel_with_configuration_files_list_returns_repositories_list():
|
||||
configs = {'test.yaml': {'repositories': [{'path': 'test.borg'}]}}
|
||||
|
||||
repositories_list = module.make_next_panel(
|
||||
focused_panel=borgmatic.actions.browse.configuration_files_list.Configuration_files_list(
|
||||
configs
|
||||
),
|
||||
option_id='test.yaml',
|
||||
)
|
||||
|
||||
assert isinstance(
|
||||
repositories_list, borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert repositories_list.config == configs['test.yaml']
|
||||
|
||||
|
||||
def test_make_next_panel_with_repositories_list_returns_archives_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(borgmatic.actions.browse.archives_list.Archives_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
|
||||
archives_list = module.make_next_panel(
|
||||
focused_panel=borgmatic.actions.browse.repositories_list.Repositories_list(config),
|
||||
option_id=0,
|
||||
)
|
||||
|
||||
assert isinstance(archives_list, borgmatic.actions.browse.archives_list.Archives_list)
|
||||
assert archives_list.config == config
|
||||
assert archives_list.repository == config['repositories'][0]
|
||||
|
||||
|
||||
def test_make_next_panel_with_archives_list_returns_directory_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_archive_paths')
|
||||
flexmock(borgmatic.actions.browse.archives_list.Archives_list).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
directory_list = module.make_next_panel(
|
||||
focused_panel=borgmatic.actions.browse.archives_list.Archives_list(
|
||||
config, config['repositories'][0]
|
||||
),
|
||||
option_id='archive',
|
||||
)
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.directory_list.Directory_list)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
|
||||
|
||||
def test_make_next_panel_with_root_directory_list_and_selected_directory_option_returns_new_directory_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_archive_paths')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('Archive_path_loaded').replace_with(
|
||||
flexmock(
|
||||
path_hierarchy={
|
||||
'etc': {},
|
||||
},
|
||||
complete=False,
|
||||
),
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
focused_panel = borgmatic.actions.browse.directory_list.Directory_list(
|
||||
config, config['repositories'][0], 'archive'
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt='📁 etc'))
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='etc')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.directory_list.Directory_list)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.path_components == ('etc',)
|
||||
|
||||
|
||||
def test_make_next_panel_with_non_root_directory_list_and_selected_directory_option_returns_new_directory_list():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_archive_paths')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('Archive_path_loaded').replace_with(
|
||||
flexmock(
|
||||
path_hierarchy={
|
||||
'etc': {
|
||||
'borgmatic': {},
|
||||
},
|
||||
},
|
||||
complete=False,
|
||||
),
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
focused_panel = borgmatic.actions.browse.directory_list.Directory_list(
|
||||
config,
|
||||
config['repositories'][0],
|
||||
'archive',
|
||||
path_components=('etc',),
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(flexmock(prompt='📁 borgmatic'))
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='borgmatic')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.directory_list.Directory_list)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.path_components == ('etc', 'borgmatic')
|
||||
|
||||
|
||||
def test_make_next_panel_with_root_directory_list_and_selected_file_option_returns_new_file_preview():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_archive_paths')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_file_preview')
|
||||
flexmock(borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
flexmock(borgmatic.actions.browse.file_preview.File_preview).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.directory_list.Directory_list(
|
||||
config, config['repositories'][0], 'archive'
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(
|
||||
flexmock(prompt='📄 config.yaml')
|
||||
)
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='config.yaml')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.file_preview.File_preview)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.file_path == 'config.yaml'
|
||||
|
||||
|
||||
def test_make_next_panel_with_non_root_directory_list_and_selected_file_option_returns_new_file_preview():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_archive_paths')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_file_preview')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('Archive_path_loaded').replace_with(
|
||||
flexmock(
|
||||
path_hierarchy={
|
||||
'etc': {
|
||||
'borgmatic': {
|
||||
'config.yaml': borgmatic.actions.browse.archive.Archive_path(
|
||||
'-', 'config.yaml', ''
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
complete=False,
|
||||
),
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
flexmock(borgmatic.actions.browse.file_preview.File_preview).should_receive('app').and_return(
|
||||
flexmock()
|
||||
)
|
||||
focused_panel = borgmatic.actions.browse.directory_list.Directory_list(
|
||||
config,
|
||||
config['repositories'][0],
|
||||
'archive',
|
||||
path_components=('etc', 'borgmatic'),
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(
|
||||
flexmock(prompt='📄 config.yaml')
|
||||
)
|
||||
|
||||
directory_list = module.make_next_panel(focused_panel=focused_panel, option_id='config.yaml')
|
||||
|
||||
assert isinstance(directory_list, borgmatic.actions.browse.file_preview.File_preview)
|
||||
assert directory_list.config == config
|
||||
assert directory_list.repository == config['repositories'][0]
|
||||
assert directory_list.archive_name == 'archive'
|
||||
assert directory_list.file_path == 'etc/borgmatic/config.yaml'
|
||||
|
||||
|
||||
def test_make_next_panel_with_unsupported_focused_panel_returns_none():
|
||||
assert module.make_next_panel(focused_panel=flexmock(), option_id='hmmm') is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('icon', ('🔗', '🚰', '🐙'))
|
||||
def test_make_next_panel_with_directory_list_and_unsupported_selected_option_returns_none(icon):
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('load_archive_paths')
|
||||
flexmock(borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
focused_panel = borgmatic.actions.browse.directory_list.Directory_list(
|
||||
config, config['repositories'][0], 'archive'
|
||||
)
|
||||
flexmock(focused_panel).should_receive('get_option').and_return(
|
||||
flexmock(prompt=f'{icon} config.yaml')
|
||||
)
|
||||
|
||||
assert module.make_next_panel(focused_panel=focused_panel, option_id='config.yaml') is None
|
||||
|
||||
|
||||
async def test_carousel_previous_action_with_multiple_configs_does_not_raise():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('left')
|
||||
|
||||
|
||||
async def test_carousel_previous_action_with_one_config_does_not_raise():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('left')
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_multiple_configs_advances_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 2
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'none'
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[1], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[1].styles.display == 'block'
|
||||
assert carousel.panels[1].highlighted == 0
|
||||
assert app.focused == carousel.panels[1]
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_one_config_advances_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 2
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'none'
|
||||
|
||||
assert isinstance(carousel.panels[1], borgmatic.actions.browse.archives_list.Archives_list)
|
||||
assert carousel.panels[1].styles.display == 'block'
|
||||
assert carousel.panels[1].highlighted == 0
|
||||
assert app.focused == carousel.panels[1]
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_no_next_panel_does_not_advance():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
flexmock(borgmatic.actions.browse.workers).should_receive('add_repository_archives')
|
||||
flexmock(module).should_receive('make_next_panel')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_next_action_and_previous_action_returns_to_original_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
await pilot.press('left')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 2
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert carousel.panels[0].highlighted == 0
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[1], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[1].styles.display == 'none'
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_next_action_and_previous_action_and_next_action_reuses_next_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
flexmock(borgmatic.actions.browse.carousel).should_call('make_next_panel').once()
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
await pilot.press('left')
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 2
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'none'
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[1], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[1].styles.display == 'block'
|
||||
assert carousel.panels[1].highlighted == 0
|
||||
assert app.focused == carousel.panels[1]
|
||||
|
||||
|
||||
async def test_carousel_next_action_with_multiple_configs_and_no_next_panel_does_not_advance():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
flexmock(module).should_receive('make_next_panel').and_return(None)
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert carousel.panels[0].highlighted == 0
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_next_action_and_previous_action_and_down_truncates_next_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
await pilot.press('left')
|
||||
await pilot.press('down')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert carousel.panels[0].highlighted == 1
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_down_does_not_raise():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('down')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert carousel.panels[0].highlighted == 1
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_up_does_not_raise():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('down')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
assert len(carousel.panels) == 1
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert carousel.panels[0].highlighted == 1
|
||||
assert app.focused == carousel.panels[0]
|
||||
|
||||
|
||||
async def test_carousel_next_action_and_select_dot_dot_returns_to_original_panel():
|
||||
app = borgmatic.actions.browse.app.Browse_app(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
flexmock(borgmatic.actions.browse.logs).should_receive('log_to_widget')
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.press('enter')
|
||||
|
||||
carousel = app.query_one(selector='Carousel')
|
||||
carousel.panels[1].options[0] = textual.widgets.option_list.Option('..', id='..')
|
||||
|
||||
await pilot.press('enter')
|
||||
|
||||
assert len(carousel.panels) == 2
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[0],
|
||||
borgmatic.actions.browse.configuration_files_list.Configuration_files_list,
|
||||
)
|
||||
assert carousel.panels[0].styles.display == 'block'
|
||||
assert carousel.panels[0].highlighted == 0
|
||||
|
||||
assert isinstance(
|
||||
carousel.panels[1], borgmatic.actions.browse.repositories_list.Repositories_list
|
||||
)
|
||||
assert carousel.panels[1].styles.display == 'none'
|
||||
assert app.focused == carousel.panels[0]
|
||||
@@ -0,0 +1,34 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import configuration_files_list as module
|
||||
|
||||
|
||||
def test_configuration_files_list_adds_config_paths_as_options():
|
||||
flexmock(module.os.path).should_receive('expanduser').and_return('/home/user')
|
||||
|
||||
configuration_files_list = module.Configuration_files_list(
|
||||
configs={
|
||||
'test1.yaml': {'repositories': [{'path': 'test1.borg'}]},
|
||||
'test2.yaml': {'repositories': [{'path': 'test2.borg'}]},
|
||||
}
|
||||
)
|
||||
|
||||
assert len(configuration_files_list.options) == 2
|
||||
assert configuration_files_list.options[0].prompt == 'test1.yaml'
|
||||
assert configuration_files_list.options[0].id == 'test1.yaml'
|
||||
assert configuration_files_list.options[1].prompt == 'test2.yaml'
|
||||
assert configuration_files_list.options[1].id == 'test2.yaml'
|
||||
|
||||
|
||||
def test_configuration_files_list_collapses_home_directory_in_config_path_option():
|
||||
flexmock(module.os.path).should_receive('expanduser').and_return('/home/user')
|
||||
|
||||
configuration_files_list = module.Configuration_files_list(
|
||||
configs={
|
||||
'/home/user/test.yaml': {'repositories': [{'path': '/home/user/test.borg'}]},
|
||||
}
|
||||
)
|
||||
|
||||
assert len(configuration_files_list.options) == 1
|
||||
assert configuration_files_list.options[0].prompt == '~/test.yaml'
|
||||
assert configuration_files_list.options[0].id == '/home/user/test.yaml'
|
||||
@@ -0,0 +1,287 @@
|
||||
import textual.widgets
|
||||
import textual.widgets.option_list
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import directory_list as module
|
||||
|
||||
|
||||
def test_add_archive_paths_with_only_duplicate_paths_bails():
|
||||
directory_list = textual.widgets.OptionList()
|
||||
directory_list.path_components = ('etc',)
|
||||
directory_list.add_option(textual.widgets.option_list.Option('foo', id='foo'))
|
||||
directory_list.add_option(textual.widgets.option_list.Option('bar', id='bar'))
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(directory_list).should_receive('set_options').never()
|
||||
|
||||
module.add_archive_paths(
|
||||
directory_list=directory_list,
|
||||
config=config,
|
||||
repository=config['repositories'][0],
|
||||
archive_name='archive',
|
||||
archive_paths=(
|
||||
flexmock(path_type='-', file_path='etc/foo/one.txt', link_target=''),
|
||||
flexmock(path_type='-', file_path='etc/foo/two.txt', link_target=''),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_add_archive_paths_adds_ands_sorts_and_filters_and_deduplicates():
|
||||
directory_list = textual.widgets.OptionList()
|
||||
directory_list.path_components = ('etc',)
|
||||
directory_list.add_option(textual.widgets.option_list.Option('📄 foo', id='foo'))
|
||||
directory_list.add_option(textual.widgets.option_list.Option('📄 bar', id='bar'))
|
||||
directory_list.highlighted = 1
|
||||
directory_list.highlighted_option_changed = True
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
|
||||
module.add_archive_paths(
|
||||
directory_list=directory_list,
|
||||
config=config,
|
||||
repository=config['repositories'][0],
|
||||
archive_name='archive',
|
||||
archive_paths=(
|
||||
flexmock(path_type='d', file_path='etc/quux', link_target=''),
|
||||
flexmock(path_type='-', file_path='etc/foo', link_target=''),
|
||||
flexmock(path_type='-', file_path='etc/baz', link_target=''),
|
||||
flexmock(path_type='d', file_path='root/nope', link_target=''),
|
||||
flexmock(path_type='d', file_path='etc/other', link_target=''),
|
||||
),
|
||||
)
|
||||
|
||||
assert len(directory_list.options) == 5
|
||||
assert directory_list.options[0].prompt == '📁 other'
|
||||
assert directory_list.options[0].id == 'other'
|
||||
assert directory_list.options[1].prompt == '📁 quux'
|
||||
assert directory_list.options[1].id == 'quux'
|
||||
assert directory_list.options[2].prompt == '📄 bar'
|
||||
assert directory_list.options[2].id == 'bar'
|
||||
assert directory_list.options[3].prompt == '📄 baz'
|
||||
assert directory_list.options[3].id == 'baz'
|
||||
assert directory_list.options[4].prompt == '📄 foo'
|
||||
assert directory_list.options[4].id == 'foo'
|
||||
assert directory_list.highlighted == 2
|
||||
|
||||
|
||||
def test_add_archive_paths_highlights_first_option_if_highlight_has_not_changed():
|
||||
directory_list = textual.widgets.OptionList()
|
||||
directory_list.path_components = ('etc',)
|
||||
directory_list.add_option(textual.widgets.option_list.Option('📄 foo', id='foo'))
|
||||
directory_list.add_option(textual.widgets.option_list.Option('📄 bar', id='bar'))
|
||||
directory_list.highlighted = None
|
||||
directory_list.highlighted_option_changed = False
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
|
||||
module.add_archive_paths(
|
||||
directory_list=directory_list,
|
||||
config=config,
|
||||
repository=config['repositories'][0],
|
||||
archive_name='archive',
|
||||
archive_paths=(flexmock(path_type='-', file_path='etc/baz', link_target=''),),
|
||||
)
|
||||
|
||||
assert len(directory_list.options) == 3
|
||||
assert directory_list.options[0].prompt == '📄 bar'
|
||||
assert directory_list.options[0].id == 'bar'
|
||||
assert directory_list.options[1].prompt == '📄 baz'
|
||||
assert directory_list.options[1].id == 'baz'
|
||||
assert directory_list.options[2].prompt == '📄 foo'
|
||||
assert directory_list.options[2].id == 'foo'
|
||||
assert directory_list.highlighted == 0
|
||||
|
||||
|
||||
def test_add_archive_paths_retains_loading_indicator_at_bottom():
|
||||
directory_list = textual.widgets.OptionList()
|
||||
directory_list.path_components = ('etc',)
|
||||
directory_list.add_option(textual.widgets.option_list.Option('📄 foo', id='foo'))
|
||||
directory_list.add_option(textual.widgets.option_list.Option('📄 bar', id='bar'))
|
||||
directory_list.add_option(
|
||||
textual.widgets.option_list.Option('loading!!!', id='loading-indicator')
|
||||
)
|
||||
directory_list.highlighted = 0
|
||||
directory_list.highlighted_option_changed = True
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
|
||||
module.add_archive_paths(
|
||||
directory_list=directory_list,
|
||||
config=config,
|
||||
repository=config['repositories'][0],
|
||||
archive_name='archive',
|
||||
archive_paths=(flexmock(path_type='-', file_path='etc/baz', link_target=''),),
|
||||
)
|
||||
|
||||
assert len(directory_list.options) == 4
|
||||
assert directory_list.options[0].prompt == '📄 bar'
|
||||
assert directory_list.options[0].id == 'bar'
|
||||
assert directory_list.options[1].prompt == '📄 baz'
|
||||
assert directory_list.options[1].id == 'baz'
|
||||
assert directory_list.options[2].prompt == '📄 foo'
|
||||
assert directory_list.options[2].id == 'foo'
|
||||
assert directory_list.options[3].prompt == 'loading!!!'
|
||||
assert directory_list.options[3].id == 'loading-indicator'
|
||||
assert directory_list.highlighted == 2
|
||||
|
||||
|
||||
def test_directory_list_with_root_directory_adds_loading_indicator():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive(
|
||||
'add_inline_loading_indicator'
|
||||
).once()
|
||||
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(), repository=flexmock(), archive_name='archive'
|
||||
)
|
||||
assert directory_list.border_title == '📁 archive'
|
||||
assert len(directory_list.options) == 0
|
||||
assert not directory_list.path_loaded.complete
|
||||
|
||||
|
||||
def test_directory_list_with_already_complete_loading_skips_loading_indicator():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive(
|
||||
'add_inline_loading_indicator'
|
||||
).never()
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('load_archive_paths').never()
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=True),
|
||||
path_components=('etc',),
|
||||
)
|
||||
assert directory_list.border_title == '📁 etc'
|
||||
assert len(directory_list.options) == 1
|
||||
assert directory_list.options[0].prompt == '📁 ..'
|
||||
assert directory_list.options[0].id == '..'
|
||||
|
||||
|
||||
def test_directory_list_on_mount_with_root_directory_loads_archive_paths():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('load_archive_paths').once()
|
||||
flexmock(module).should_receive('add_archive_paths').never()
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(), repository=flexmock(), archive_name='archive'
|
||||
)
|
||||
flexmock(directory_list.path_loaded).should_receive('subscribe')
|
||||
|
||||
directory_list.on_mount()
|
||||
|
||||
|
||||
def test_directory_list_on_mount_with_non_root_directory_adds_archive_paths():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('load_archive_paths').never()
|
||||
flexmock(module).should_receive('add_archive_paths').once()
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=False, path_hierarchy={'etc': {}}),
|
||||
path_components=('etc',),
|
||||
)
|
||||
flexmock(directory_list.path_loaded).should_receive('subscribe')
|
||||
|
||||
directory_list.on_mount()
|
||||
|
||||
|
||||
def test_on_archive_path_loaded_with_loading_done_signal_removes_loading_indicator():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
flexmock(module).should_receive('add_archive_paths').never()
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=False, path_hierarchy={'etc': {}}),
|
||||
path_components=('etc',),
|
||||
)
|
||||
directory_list.timer = flexmock(stop=lambda: None)
|
||||
flexmock(directory_list).should_receive('remove_option').once()
|
||||
|
||||
directory_list.on_archive_path_loaded(data=module.borgmatic.actions.browse.workers.LOADING_DONE)
|
||||
|
||||
|
||||
def test_on_archive_path_loaded_with_path_loaded_signal_adds_archive_path():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
flexmock(module).should_receive('add_archive_paths').once()
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=False, path_hierarchy={'etc': {}}),
|
||||
path_components=('etc',),
|
||||
)
|
||||
flexmock(directory_list).should_receive('remove_option').never()
|
||||
|
||||
directory_list.on_archive_path_loaded(data=flexmock())
|
||||
|
||||
|
||||
def test_directory_list_on_option_list_option_highlighted_with_highlighted_none_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=False, path_hierarchy={'etc': {}}),
|
||||
path_components=('etc',),
|
||||
)
|
||||
directory_list.highlighted = None
|
||||
|
||||
directory_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert directory_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_directory_list_on_option_list_option_highlighted_with_highlighted_zero_marks_it_unchanged():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=False, path_hierarchy={'etc': {}}),
|
||||
path_components=('etc',),
|
||||
)
|
||||
directory_list.add_option(textual.widgets.option_list.Option('zero', id='zero'))
|
||||
directory_list.highlighted = 0
|
||||
|
||||
directory_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert directory_list.highlighted_option_changed is False
|
||||
|
||||
|
||||
def test_directory_list_on_option_list_option_highlighted_with_highlighted_non_zero_marks_it_changed():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.directory_list.Directory_list).should_receive(
|
||||
'app'
|
||||
).and_return(flexmock())
|
||||
directory_list = module.Directory_list(
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
path_loaded=flexmock(complete=False, path_hierarchy={'etc': {}}),
|
||||
path_components=('etc',),
|
||||
)
|
||||
directory_list.add_option(textual.widgets.option_list.Option('zero', id='zero'))
|
||||
directory_list.add_option(textual.widgets.option_list.Option('one', id='one'))
|
||||
directory_list.highlighted = 1
|
||||
|
||||
directory_list.on_option_list_option_highlighted(event=flexmock())
|
||||
|
||||
assert directory_list.highlighted_option_changed is True
|
||||
@@ -0,0 +1,53 @@
|
||||
import textual.widgets.option_list
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import file_preview as module
|
||||
|
||||
|
||||
def test_file_preview_does_not_raise():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
|
||||
module.File_preview(
|
||||
config=flexmock(), repository=flexmock(), archive_name='archive', file_path='foo/bar.txt'
|
||||
)
|
||||
|
||||
|
||||
async def test_file_preview_on_mount_does_not_raise():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive('add_inline_loading_indicator')
|
||||
flexmock(module.borgmatic.actions.browse.workers).should_receive('load_file_preview')
|
||||
file_preview = module.File_preview(
|
||||
config=flexmock(), repository=flexmock(), archive_name='archive', file_path='foo.txt'
|
||||
)
|
||||
flexmock(file_preview.file_preview_loaded).should_receive('subscribe')
|
||||
|
||||
async with textual.app.App().run_test():
|
||||
file_preview.on_mount()
|
||||
|
||||
|
||||
def test_file_preview_on_file_preview_loaded_with_none_file_contents_displays_error():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive(
|
||||
'add_inline_loading_indicator'
|
||||
).and_return(flexmock(stop=lambda: None))
|
||||
file_preview = module.File_preview(
|
||||
config=flexmock(), repository=flexmock(), archive_name='archive', file_path='foo.txt'
|
||||
)
|
||||
flexmock(file_preview).should_receive('write').with_args(
|
||||
'Cannot display a preview for this file'
|
||||
).once()
|
||||
|
||||
file_preview.on_file_preview_loaded(None)
|
||||
|
||||
|
||||
def test_file_preview_on_file_preview_loaded_with_file_contents_displays_contents():
|
||||
flexmock(module.borgmatic.actions.browse.loading).should_receive(
|
||||
'add_inline_loading_indicator'
|
||||
).and_return(flexmock(stop=lambda: None))
|
||||
file_preview = module.File_preview(
|
||||
config=flexmock(), repository=flexmock(), archive_name='archive', file_path='foo.txt'
|
||||
)
|
||||
flexmock(file_preview).should_receive('write').with_args(
|
||||
'Cannot display a preview for this file'
|
||||
).never()
|
||||
flexmock(file_preview).should_receive('write').once()
|
||||
|
||||
file_preview.on_file_preview_loaded('hi')
|
||||
@@ -0,0 +1,97 @@
|
||||
import pytest
|
||||
import textual.app
|
||||
import textual.widgets
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import loading as module
|
||||
|
||||
|
||||
def test_update_inline_loading_indicator_with_option_list_adds_a_dot():
|
||||
widget = textual.widgets.OptionList()
|
||||
widget.add_option(textual.widgets.option_list.Option('HOLD.', id='loading-indicator'))
|
||||
|
||||
module.update_inline_loading_indicator(widget)
|
||||
|
||||
assert len(widget.options) == 1
|
||||
assert widget.options[0].prompt == 'HOLD..'
|
||||
|
||||
|
||||
def test_update_inline_loading_indicator_with_option_list_wraps_dots_beyond_three():
|
||||
widget = textual.widgets.OptionList()
|
||||
widget.add_option(textual.widgets.option_list.Option('HOLD...', id='loading-indicator'))
|
||||
|
||||
module.update_inline_loading_indicator(widget)
|
||||
|
||||
assert len(widget.options) == 1
|
||||
assert widget.options[0].prompt == 'HOLD'
|
||||
|
||||
|
||||
def test_update_inline_loading_indicator_with_option_list_and_missing_indicator_does_not_raise():
|
||||
widget = textual.widgets.OptionList()
|
||||
|
||||
module.update_inline_loading_indicator(widget)
|
||||
|
||||
assert len(widget.options) == 0
|
||||
|
||||
|
||||
async def test_update_inline_loading_indicator_with_rich_log_adds_a_dot():
|
||||
async with textual.app.App().run_test():
|
||||
widget = textual.widgets.RichLog()
|
||||
widget._size_known = True
|
||||
widget.write('HOLD.')
|
||||
|
||||
module.update_inline_loading_indicator(widget)
|
||||
|
||||
assert str(widget.lines[0].text) == 'HOLD..'
|
||||
|
||||
|
||||
async def test_update_inline_loading_indicator_with_rich_log_wraps_dots_beyond_three():
|
||||
async with textual.app.App().run_test():
|
||||
widget = textual.widgets.RichLog()
|
||||
widget._size_known = True
|
||||
widget.write('HOLD...')
|
||||
|
||||
module.update_inline_loading_indicator(widget)
|
||||
|
||||
assert str(widget.lines[0].text) == 'HOLD'
|
||||
|
||||
|
||||
def test_update_inline_loading_indicator_with_rich_log_and_missing_indicator_does_not_raise():
|
||||
widget = textual.widgets.RichLog()
|
||||
|
||||
module.update_inline_loading_indicator(widget)
|
||||
|
||||
assert len(widget.lines) == 0
|
||||
|
||||
|
||||
def test_update_inline_loading_indicator_with_unsupported_widget_type_raises():
|
||||
with pytest.raises(ValueError):
|
||||
module.update_inline_loading_indicator(flexmock())
|
||||
|
||||
|
||||
def test_add_inline_loading_indicator_with_option_list_adds_loading_indicator_option():
|
||||
widget = textual.widgets.OptionList()
|
||||
flexmock(widget).should_receive('set_interval')
|
||||
|
||||
module.add_inline_loading_indicator(widget)
|
||||
|
||||
assert len(widget.options) == 1
|
||||
assert widget.options[0].prompt == module.LOADING_MESSAGE
|
||||
assert widget.options[0].id == 'loading-indicator'
|
||||
assert widget.highlighted is None
|
||||
|
||||
|
||||
async def test_add_inline_loading_indicator_with_rich_log_writes_loading_indicator_text():
|
||||
async with textual.app.App().run_test():
|
||||
widget = textual.widgets.RichLog()
|
||||
widget._size_known = True
|
||||
flexmock(widget).should_receive('set_interval')
|
||||
|
||||
module.add_inline_loading_indicator(widget)
|
||||
|
||||
assert str(widget.lines[0].text) == module.LOADING_MESSAGE
|
||||
|
||||
|
||||
def test_add_inline_loading_indicator_with_unsupported_widget_type_raises():
|
||||
with pytest.raises(ValueError):
|
||||
module.add_inline_loading_indicator(flexmock())
|
||||
@@ -0,0 +1,37 @@
|
||||
import contextlib
|
||||
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import logs as module
|
||||
|
||||
|
||||
def test_log_to_widget_adds_our_handler_and_removes_default_handler():
|
||||
default_handler = module.borgmatic.logger.Multi_stream_handler({})
|
||||
root_logger = module.logging.getLogger()
|
||||
root_logger.addHandler(default_handler)
|
||||
browse_log_handler = None
|
||||
|
||||
try:
|
||||
module.log_to_widget(flexmock())
|
||||
|
||||
with contextlib.suppress(StopIteration):
|
||||
browse_log_handler = next(
|
||||
handler
|
||||
for handler in root_logger.handlers
|
||||
if isinstance(handler, module.Browse_log_handler)
|
||||
)
|
||||
|
||||
assert browse_log_handler
|
||||
finally:
|
||||
if browse_log_handler:
|
||||
root_logger.removeHandler(browse_log_handler)
|
||||
|
||||
assert not any(
|
||||
handler
|
||||
for handler in root_logger.handlers
|
||||
if isinstance(handler, module.borgmatic.logger.Multi_stream_handler)
|
||||
)
|
||||
|
||||
|
||||
def test_logs_does_not_raise():
|
||||
module.Logs()
|
||||
@@ -0,0 +1,12 @@
|
||||
from borgmatic.actions.browse import repositories_list as module
|
||||
|
||||
|
||||
def test_repositories_list_populates_options():
|
||||
config = {'repositories': [{'path': 'test1.borg'}, {'path': 'test2.borg', 'label': 'two'}]}
|
||||
|
||||
repositories_list = module.Repositories_list(config=config)
|
||||
assert len(repositories_list.options) == 2
|
||||
assert repositories_list.options[0].prompt == 'test1.borg'
|
||||
assert repositories_list.options[0].id == 0
|
||||
assert repositories_list.options[1].prompt == 'two'
|
||||
assert repositories_list.options[1].id == 1
|
||||
@@ -0,0 +1,19 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import workers as module
|
||||
|
||||
|
||||
def test_archive_path_loaded_publish_records_complete():
|
||||
signal = module.Archive_path_loaded(owner=flexmock(), name='Bob')
|
||||
signal.publish(module.LOADING_DONE)
|
||||
|
||||
assert signal.complete
|
||||
|
||||
|
||||
def test_archive_path_loaded_publish_records_published_path():
|
||||
archive_path = module.borgmatic.actions.browse.archive.Archive_path('-', 'foo/bar.txt', '')
|
||||
signal = module.Archive_path_loaded(owner=flexmock(), name='Bob')
|
||||
signal.publish(archive_path)
|
||||
|
||||
assert signal.path_hierarchy == {'foo': {'bar.txt': archive_path}}
|
||||
assert not signal.complete
|
||||
@@ -57,6 +57,8 @@ def test_make_rename_command_includes_log_debug():
|
||||
|
||||
|
||||
def test_make_rename_command_includes_dry_run():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_rename_command(
|
||||
dry_run=True,
|
||||
repository_name='repo',
|
||||
@@ -79,6 +81,8 @@ def test_make_rename_command_includes_dry_run():
|
||||
|
||||
|
||||
def test_make_rename_command_includes_remote_path():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_rename_command(
|
||||
dry_run=False,
|
||||
repository_name='repo',
|
||||
@@ -102,6 +106,8 @@ def test_make_rename_command_includes_remote_path():
|
||||
|
||||
|
||||
def test_make_rename_command_includes_umask():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_rename_command(
|
||||
dry_run=False,
|
||||
repository_name='repo',
|
||||
@@ -125,6 +131,8 @@ def test_make_rename_command_includes_umask():
|
||||
|
||||
|
||||
def test_make_rename_command_includes_log_json():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_rename_command(
|
||||
dry_run=False,
|
||||
repository_name='repo',
|
||||
@@ -140,6 +148,8 @@ def test_make_rename_command_includes_log_json():
|
||||
|
||||
|
||||
def test_make_rename_command_includes_lock_wait():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_rename_command(
|
||||
dry_run=False,
|
||||
repository_name='repo',
|
||||
@@ -163,6 +173,8 @@ def test_make_rename_command_includes_lock_wait():
|
||||
|
||||
|
||||
def test_make_rename_command_includes_extra_borg_options():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_rename_command(
|
||||
dry_run=False,
|
||||
repository_name='repo',
|
||||
|
||||
@@ -557,6 +557,43 @@ def test_log_outputs_with_unfinished_process_re_polls():
|
||||
)
|
||||
|
||||
|
||||
def test_log_outputs_includes_error_output_when_output_spans_multiple_chunks():
|
||||
flexmock(module.logger).should_receive('log')
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(module.Exit_status.ERROR)
|
||||
flexmock(module).should_receive('command_for_process').and_return('python')
|
||||
|
||||
process = subprocess.Popen(
|
||||
[
|
||||
sys.executable,
|
||||
'-c',
|
||||
(
|
||||
'import os, sys; '
|
||||
f'os.write(sys.stdout.fileno(), b"x" * {module.READ_CHUNK_SIZE + 10}); '
|
||||
'os.write(sys.stdout.fileno(), b"\\nERROR: critical failure"); '
|
||||
'os.close(1); '
|
||||
'os._exit(2)'
|
||||
),
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
flexmock(module).should_receive('output_buffers_for_process').and_return((process.stdout,))
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError) as error:
|
||||
tuple(
|
||||
module.log_outputs(
|
||||
(process,),
|
||||
exclude_stdouts=(),
|
||||
output_log_level=logging.INFO,
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
)
|
||||
|
||||
assert error.value.output
|
||||
assert 'ERROR: critical failure' in error.value.output
|
||||
|
||||
|
||||
def test_read_lines_uses_system_locale_when_decoding_output():
|
||||
flexmock(module.locale).should_receive('getpreferredencoding').and_return('ISO-8859-1')
|
||||
process = subprocess.Popen(['echo', b'\xc4pple'], stdout=subprocess.PIPE)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import archive as module
|
||||
|
||||
|
||||
def test_get_repository_archives_does_not_raise():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module.borgmatic.borg.version).should_receive('local_borg_version').and_return('3.0')
|
||||
flexmock(module.borgmatic.borg.repo_list).should_receive('list_repository').and_return('{}')
|
||||
|
||||
assert module.get_repository_archives(config, config['repositories'][0]) == {}
|
||||
|
||||
|
||||
def test_get_archive_paths_returns_each_as_archive_path_with_metadata():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module.borgmatic.borg.version).should_receive('local_borg_version').and_return('3.0')
|
||||
flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_yield(
|
||||
{'path': 'foo.txt', 'type': '-', 'linktarget': ''},
|
||||
{'path': 'bar.txt', 'type': 'l', 'linktarget': 'foo.txt'},
|
||||
{'path': 'etc', 'type': 'd', 'linktarget': ''},
|
||||
)
|
||||
|
||||
assert tuple(module.get_archive_paths(config, config['repositories'][0], 'archive')) == (
|
||||
module.Archive_path('-', 'foo.txt', ''),
|
||||
module.Archive_path('l', 'bar.txt', 'foo.txt'),
|
||||
module.Archive_path('d', 'etc', ''),
|
||||
)
|
||||
|
||||
|
||||
def test_get_archive_file_content_with_binary_file_bails():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module.borgmatic.borg.version).should_receive('local_borg_version').and_return('3.0')
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
|
||||
flexmock(stdout=flexmock(readlines=lambda hint: [b'foo\n', b'bar\n'])),
|
||||
)
|
||||
flexmock(module.binaryornot.helpers).should_receive('is_binary_string').and_return(True)
|
||||
|
||||
assert (
|
||||
module.get_archive_file_content(config, config['repositories'][0], 'archive', 'etc/foo.txt')
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
def test_get_archive_file_content_decodes_content():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module.borgmatic.borg.version).should_receive('local_borg_version').and_return('3.0')
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
|
||||
flexmock(stdout=flexmock(readlines=lambda hint: [b'foo\n', b'bar\n'])),
|
||||
)
|
||||
flexmock(module.binaryornot.helpers).should_receive('is_binary_string').and_return(False)
|
||||
|
||||
assert (
|
||||
module.get_archive_file_content(config, config['repositories'][0], 'archive', 'etc/foo.txt')
|
||||
== 'foo\nbar\n'
|
||||
)
|
||||
|
||||
|
||||
def test_get_archive_file_content_with_large_file_truncates_content():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module.borgmatic.borg.version).should_receive('local_borg_version').and_return('3.0')
|
||||
flexmock(module).READLINES_HINT_BYTES = 3
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
|
||||
flexmock(stdout=flexmock(readlines=lambda hint: [b'foo\n', b'bar\n'])),
|
||||
)
|
||||
flexmock(module.binaryornot.helpers).should_receive('is_binary_string').and_return(False)
|
||||
|
||||
assert (
|
||||
module.get_archive_file_content(config, config['repositories'][0], 'archive', 'etc/foo.txt')
|
||||
== f'foo\nbar\n\n{module.TRUNCATION_MESSAGE}'
|
||||
)
|
||||
|
||||
|
||||
def test_get_archive_file_content_with_unicode_decode_error_does_not_raise():
|
||||
config = {'repositories': [{'path': 'test.borg'}]}
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module.borgmatic.borg.version).should_receive('local_borg_version').and_return('3.0')
|
||||
flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
|
||||
flexmock(stdout=flexmock(readlines=lambda hint: [b'foo\n', b'\xc3\n'])),
|
||||
)
|
||||
flexmock(module.binaryornot.helpers).should_receive('is_binary_string').and_return(False)
|
||||
|
||||
assert (
|
||||
module.get_archive_file_content(config, config['repositories'][0], 'archive', 'etc/foo.txt')
|
||||
is None
|
||||
)
|
||||
@@ -0,0 +1,94 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import directory_list as module
|
||||
|
||||
|
||||
def test_get_relative_archive_path_components_strips_off_current_directory():
|
||||
assert module.get_relative_archive_path_components(
|
||||
flexmock(file_path='foo/bar/baz/quux.txt'), ('foo', 'bar')
|
||||
) == ('baz', 'quux.txt')
|
||||
|
||||
|
||||
def test_get_relative_archive_path_components_with_root_current_directory_strips_off_nothing():
|
||||
assert module.get_relative_archive_path_components(
|
||||
flexmock(file_path='foo/bar/baz/quux.txt'), ()
|
||||
) == ('foo', 'bar', 'baz', 'quux.txt')
|
||||
|
||||
|
||||
def test_get_relative_archive_path_components_with_non_matching_paths_returns_none():
|
||||
assert (
|
||||
module.get_relative_archive_path_components(
|
||||
flexmock(file_path='foo/bar/baz/quux.txt'), ('etc',)
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_file_path_makes_file_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='-', file_path='foo/bar/baz.txt', link_target=''), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '📄 baz.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_directory_path_makes_directory_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='d', file_path='foo/bar/baz', link_target=''), ('baz',)
|
||||
)
|
||||
|
||||
assert option.prompt == '📁 baz'
|
||||
assert option.id == 'baz'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_contained_file_path_makes_directory_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='d', file_path='foo/bar/baz.txt', link_target=''),
|
||||
(
|
||||
'bar',
|
||||
'baz.txt',
|
||||
),
|
||||
)
|
||||
|
||||
assert option.prompt == '📁 bar'
|
||||
assert option.id == 'bar'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_link_path_makes_link_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='l', file_path='foo/bar/baz.txt', link_target='quux.txt'), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '🔗 baz.txt → quux.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_pipe_path_makes_pipe_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='p', file_path='foo/bar/baz.txt', link_target=''), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '🚰 baz.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
|
||||
|
||||
def test_make_directory_list_option_with_unknown_path_makes_unknown_option():
|
||||
flexmock(module.textual.widgets.option_list).should_receive('Option').replace_with(flexmock)
|
||||
|
||||
option = module.make_directory_list_option(
|
||||
flexmock(path_type='wtf', file_path='foo/bar/baz.txt', link_target=''), ('baz.txt',)
|
||||
)
|
||||
|
||||
assert option.prompt == '❓ baz.txt'
|
||||
assert option.id == 'baz.txt'
|
||||
@@ -0,0 +1,87 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import logs as module
|
||||
|
||||
|
||||
def test_rich_color_formatter_format_colors_log_record_based_on_level():
|
||||
formatted = module.Rich_color_formatter().format(
|
||||
module.logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=module.logging.ERROR,
|
||||
levelname='ERROR',
|
||||
msg='oh no',
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
assert formatted == '[bright_red]oh no[/bright_red]'
|
||||
|
||||
|
||||
def test_rich_color_formatter_format_includes_prefix():
|
||||
formatter = module.Rich_color_formatter()
|
||||
formatter.prefix = 'sup'
|
||||
formatted = formatter.format(
|
||||
module.logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=module.logging.ERROR,
|
||||
levelname='ERROR',
|
||||
msg='oh no',
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assert formatted == '[bright_red]sup: oh no[/bright_red]'
|
||||
|
||||
|
||||
def test_browse_log_handler_emit_from_worker_thread_calls_write_in_main_thread():
|
||||
flexmock(module.textual.worker).should_receive('get_current_worker')
|
||||
logs_widget = flexmock(write=lambda message: None, app=flexmock())
|
||||
flexmock(logs_widget.app).should_receive('call_from_thread').with_args(
|
||||
logs_widget.write, 'hi'
|
||||
).once()
|
||||
|
||||
module.Browse_log_handler(logs_widget).emit(
|
||||
module.logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=module.logging.DEBUG,
|
||||
levelname='DEBUG',
|
||||
msg='hi',
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_browse_log_handler_emit_from_main_thread_calls_write_directly():
|
||||
flexmock(module.textual.worker).should_receive('get_current_worker').and_raise(RuntimeError)
|
||||
logs_widget = flexmock(write=lambda message: None, app=flexmock())
|
||||
flexmock(logs_widget.app).should_receive('call_from_thread').never()
|
||||
flexmock(logs_widget).should_receive('write').with_args('hi').once()
|
||||
|
||||
module.Browse_log_handler(logs_widget).emit(
|
||||
module.logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=module.logging.DEBUG,
|
||||
levelname='DEBUG',
|
||||
msg='hi',
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_browse_log_handler_emit_from_main_thread_with_no_active_app_does_not_raise():
|
||||
flexmock(module.textual.worker).should_receive('get_current_worker').and_raise(RuntimeError)
|
||||
logs_widget = flexmock(write=lambda message: None, app=flexmock())
|
||||
flexmock(logs_widget.app).should_receive('call_from_thread').never()
|
||||
flexmock(logs_widget).should_receive('write').with_args('hi').and_raise(
|
||||
module.textual._context.NoActiveAppError
|
||||
)
|
||||
|
||||
module.Browse_log_handler(logs_widget).emit(
|
||||
module.logging.makeLogRecord(
|
||||
dict(
|
||||
levelno=module.logging.DEBUG,
|
||||
levelname='DEBUG',
|
||||
msg='hi',
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
from flexmock import flexmock
|
||||
|
||||
import borgmatic.actions.browse.app
|
||||
from borgmatic.actions.browse import run as module
|
||||
|
||||
|
||||
def test_run_browse_without_configs_bails():
|
||||
app = flexmock()
|
||||
app.should_receive('run').never()
|
||||
|
||||
flexmock(borgmatic.actions.browse.app).should_receive('Browse_app').and_return(app)
|
||||
|
||||
module.run_browse(
|
||||
diff_arguments=flexmock(),
|
||||
global_arguments=flexmock(),
|
||||
configs=(),
|
||||
)
|
||||
|
||||
|
||||
def test_run_browse_with_configs_does_not_raise():
|
||||
flexmock(borgmatic.actions.browse.app).should_receive('Browse_app').and_return(
|
||||
flexmock(run=lambda: None)
|
||||
)
|
||||
|
||||
module.run_browse(
|
||||
diff_arguments=flexmock(),
|
||||
global_arguments=flexmock(),
|
||||
configs=(flexmock(), flexmock()),
|
||||
)
|
||||
@@ -0,0 +1,126 @@
|
||||
import pytest
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.actions.browse import workers as module
|
||||
|
||||
|
||||
def test_add_repository_archives_publishes_for_each_archive():
|
||||
flexmock(module.borgmatic.actions.browse.archive).should_receive(
|
||||
'get_repository_archives'
|
||||
).and_return({'archives': [{'archive': 'foo'}, {'archive': 'bar'}]})
|
||||
archive_loaded = flexmock()
|
||||
archive_loaded.should_receive('publish').with_args('bar').once() # Reversed order.
|
||||
archive_loaded.should_receive('publish').with_args('foo').once()
|
||||
archive_loaded.should_receive('publish').with_args(module.LOADING_DONE).once()
|
||||
|
||||
module.add_repository_archives.__wrapped__(
|
||||
browse_app=flexmock(),
|
||||
archive_loaded=archive_loaded,
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
)
|
||||
|
||||
|
||||
def test_record_path_sets_file_path_in_filesystem_hierarchy():
|
||||
archive_path = flexmock(path_type='-', file_path='foo/bar/baz.txt')
|
||||
quux_path = flexmock()
|
||||
hierarchy = {'foo': {'bar': {'quux.txt': quux_path}, 'empty': {}}}
|
||||
|
||||
module.record_path(
|
||||
archive_path=archive_path, hierarchy=hierarchy, path_components=('foo', 'bar', 'baz.txt')
|
||||
)
|
||||
|
||||
assert hierarchy == {
|
||||
'foo': {'bar': {'quux.txt': quux_path, 'baz.txt': archive_path}, 'empty': {}}
|
||||
}
|
||||
|
||||
|
||||
def test_record_path_sets_directory_path_in_filesystem_hierarchy():
|
||||
archive_path = flexmock(path_type='d', file_path='foo/bar/baz')
|
||||
quux_path = flexmock()
|
||||
hierarchy = {'foo': {'bar': {'quux.txt': quux_path}, 'empty': {}}}
|
||||
|
||||
module.record_path(
|
||||
archive_path=archive_path, hierarchy=hierarchy, path_components=('foo', 'bar', 'baz')
|
||||
)
|
||||
|
||||
assert hierarchy == {'foo': {'bar': {'quux.txt': quux_path, 'baz': {}}, 'empty': {}}}
|
||||
|
||||
|
||||
def test_get_paths_lists_directory_contents():
|
||||
baz_path = module.borgmatic.actions.browse.archive.Archive_path('-', 'foo/bar/baz.txt', '')
|
||||
hierarchy = {'foo': {'bar': {'baz.txt': baz_path, 'other': {}}}, 'nope': {}}
|
||||
|
||||
assert tuple(module.get_paths(hierarchy, ('foo', 'bar'))) == (
|
||||
baz_path,
|
||||
module.borgmatic.actions.browse.archive.Archive_path('d', 'foo/bar/other', ''),
|
||||
)
|
||||
|
||||
|
||||
def test_get_paths_with_full_path_components_lists_directory_contents():
|
||||
baz_path = module.borgmatic.actions.browse.archive.Archive_path('-', 'etc/foo/bar/baz.txt', '')
|
||||
hierarchy = {'foo': {'bar': {'baz.txt': baz_path, 'other': {}}}, 'nope': {}}
|
||||
|
||||
assert tuple(module.get_paths(hierarchy, ('foo', 'bar'), ('etc', 'foo', 'bar'))) == (
|
||||
baz_path,
|
||||
module.borgmatic.actions.browse.archive.Archive_path('d', 'etc/foo/bar/other', ''),
|
||||
)
|
||||
|
||||
|
||||
def test_get_paths_lists_empty_directory_contents():
|
||||
baz_path = module.borgmatic.actions.browse.archive.Archive_path('-', 'etc/foo/bar/baz.txt', '')
|
||||
hierarchy = {'foo': {'bar': {'baz.txt': baz_path, 'other': {}}}, 'nope': {}}
|
||||
|
||||
assert (
|
||||
tuple(module.get_paths(hierarchy, ('foo', 'bar', 'other'), ('etc', 'foo', 'bar', 'other')))
|
||||
== ()
|
||||
)
|
||||
|
||||
|
||||
def test_get_paths_with_unknown_file_raises():
|
||||
hierarchy = {'foo': {'other': {}}}
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
tuple(module.get_paths(hierarchy, ('foo', 'bar.txt')))
|
||||
|
||||
|
||||
def test_get_paths_with_unknown_directory_raises():
|
||||
hierarchy = {'foo': {'other': {}}}
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
tuple(module.get_paths(hierarchy, ('foo', 'bar', 'baz')))
|
||||
|
||||
|
||||
def test_load_archive_paths_publishes_for_each_archive_path():
|
||||
flexmock(module.borgmatic.actions.browse.archive).should_receive('get_archive_paths').and_yield(
|
||||
'foo.txt', 'bar.txt'
|
||||
)
|
||||
path_loaded = flexmock()
|
||||
path_loaded.should_receive('publish').with_args('foo.txt').once()
|
||||
path_loaded.should_receive('publish').with_args('bar.txt').once()
|
||||
path_loaded.should_receive('publish').with_args(module.LOADING_DONE).once()
|
||||
|
||||
module.load_archive_paths.__wrapped__(
|
||||
browse_app=flexmock(),
|
||||
path_loaded=path_loaded,
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
)
|
||||
|
||||
|
||||
def test_load_file_preview_publishes_file_contents():
|
||||
flexmock(module.borgmatic.actions.browse.archive).should_receive(
|
||||
'get_archive_file_content'
|
||||
).and_return('hi')
|
||||
file_preview_loaded = flexmock()
|
||||
file_preview_loaded.should_receive('publish').with_args('hi').once()
|
||||
|
||||
module.load_file_preview.__wrapped__(
|
||||
browse_app=flexmock(),
|
||||
file_preview_loaded=file_preview_loaded,
|
||||
config=flexmock(),
|
||||
repository=flexmock(),
|
||||
archive_name='archive',
|
||||
file_path='foo/bar/baz.txt',
|
||||
)
|
||||
@@ -22,6 +22,7 @@ def test_run_arbitrary_borg_calls_borg_with_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -99,6 +100,7 @@ def test_run_arbitrary_borg_with_lock_wait_calls_borg_with_lock_wait_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -123,6 +125,7 @@ def test_run_arbitrary_borg_with_archive_calls_borg_with_archive_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -148,6 +151,7 @@ def test_run_arbitrary_borg_with_local_path_calls_borg_via_local_path():
|
||||
borg_local_path='borg1',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -174,6 +178,7 @@ def test_run_arbitrary_borg_with_exit_codes_calls_borg_using_them():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -200,6 +205,7 @@ def test_run_arbitrary_borg_with_remote_path_calls_borg_with_remote_path_flags()
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -227,6 +233,7 @@ def test_run_arbitrary_borg_with_remote_path_injection_attack_gets_escaped():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -252,6 +259,7 @@ def test_run_arbitrary_borg_passes_borg_specific_flags_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -276,6 +284,7 @@ def test_run_arbitrary_borg_omits_dash_dash_in_flags_passed_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -300,6 +309,7 @@ def test_run_arbitrary_borg_without_borg_specific_flags_does_not_raise():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
@@ -376,6 +386,7 @@ def test_run_arbitrary_borg_calls_borg_with_working_directory():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.run_arbitrary_borg(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -24,6 +24,7 @@ def insert_execute_command_mock(command, working_directory=None, borg_exit_codes
|
||||
def test_break_lock_calls_borg_with_required_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'break-lock', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -36,6 +37,7 @@ def test_break_lock_calls_borg_with_required_flags():
|
||||
def test_break_lock_calls_borg_with_local_path():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg1', 'break-lock', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -49,6 +51,7 @@ def test_break_lock_calls_borg_with_local_path():
|
||||
def test_break_lock_calls_borg_using_exit_codes():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg1', 'break-lock', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -64,6 +67,7 @@ def test_break_lock_calls_borg_with_remote_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'break-lock', '--remote-path', 'borg1', '--log-json', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -77,6 +81,7 @@ def test_break_lock_calls_borg_with_remote_path_flags():
|
||||
def test_break_lock_calls_borg_with_umask_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'break-lock', '--umask', '0770', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -89,6 +94,7 @@ def test_break_lock_calls_borg_with_umask_flags():
|
||||
def test_break_lock_calls_borg_with_lock_wait_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'break-lock', '--log-json', '--lock-wait', '5', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -103,6 +109,7 @@ def test_break_lock_calls_borg_with_extra_borg_options():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'break-lock', '--log-json', '--extra', 'value with space', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
@@ -145,6 +152,7 @@ def test_break_lock_calls_borg_with_working_directory():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'break-lock', '--log-json', 'repo'), working_directory='/working/dir'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.break_lock(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -35,6 +35,7 @@ def insert_execute_command_mock(
|
||||
def test_change_passphrase_calls_borg_with_required_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'key', 'change-passphrase', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -48,6 +49,7 @@ def test_change_passphrase_calls_borg_with_required_flags():
|
||||
def test_change_passphrase_calls_borg_with_local_path():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg1', 'key', 'change-passphrase', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -68,6 +70,7 @@ def test_change_passphrase_calls_borg_using_exit_codes():
|
||||
config=config,
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -83,6 +86,7 @@ def test_change_passphrase_calls_borg_with_remote_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'change-passphrase', '--remote-path', 'borg1', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -101,6 +105,7 @@ def test_change_passphrase_calls_borg_with_umask_flags():
|
||||
('borg', 'key', 'change-passphrase', '--umask', '0770', 'repo'),
|
||||
config=config,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -118,6 +123,7 @@ def test_change_passphrase_calls_borg_with_lock_wait_flags():
|
||||
('borg', 'key', 'change-passphrase', '--lock-wait', '5', 'repo'),
|
||||
config=config,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -135,6 +141,7 @@ def test_change_passphrase_calls_borg_with_extra_borg_options():
|
||||
('borg', 'key', 'change-passphrase', '--extra', 'value with space', 'repo'),
|
||||
config=config,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -179,6 +186,7 @@ def test_change_passphrase_with_dry_run_skips_borg_call():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.execute).should_receive('execute_command').never()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -195,6 +203,7 @@ def test_change_passphrase_calls_borg_without_passphrase():
|
||||
('borg', 'key', 'change-passphrase', 'repo'),
|
||||
config={'option': 'foo'},
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
@@ -217,6 +226,7 @@ def test_change_passphrase_calls_borg_with_working_directory():
|
||||
config=config,
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.change_passphrase(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -337,6 +337,7 @@ def test_check_archives_with_progress_passes_through_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -373,6 +374,7 @@ def test_check_archives_with_log_json_and_progress_passes_through_both_to_borg()
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -409,6 +411,7 @@ def test_check_archives_with_repair_passes_through_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -445,6 +448,7 @@ def test_check_archives_with_log_json_and_repair_passes_through_both_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -481,6 +485,7 @@ def test_check_archives_with_max_duration_flag_passes_through_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -517,6 +522,7 @@ def test_check_archives_with_max_duration_option_passes_through_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -550,6 +556,7 @@ def test_check_archives_with_max_duration_option_and_archives_check_runs_reposit
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--max-duration', '33', '--repository-only', '--log-json', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -583,6 +590,7 @@ def test_check_archives_with_max_duration_flag_and_archives_check_runs_repositor
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--max-duration', '33', '--repository-only', '--log-json', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -619,6 +627,7 @@ def test_check_archives_with_max_duration_option_and_data_check_runs_repository_
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--max-duration', '33', '--repository-only', '--log-json', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -655,6 +664,7 @@ def test_check_archives_with_max_duration_flag_and_data_check_runs_repository_ch
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--max-duration', '33', '--repository-only', '--log-json', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -691,6 +701,7 @@ def test_check_archives_with_max_duration_flag_overrides_max_duration_option():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -724,6 +735,7 @@ def test_check_archives_calls_borg_with_parameters(checks):
|
||||
flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'check', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -751,6 +763,7 @@ def test_check_archives_with_data_check_implies_archives_check_calls_borg_with_p
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'check', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -777,8 +790,8 @@ def test_check_archives_with_log_info_passes_through_to_borg():
|
||||
(),
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.INFO)
|
||||
insert_execute_command_mock(('borg', 'check', '--log-json', '--info', 'repo'))
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -805,8 +818,8 @@ def test_check_archives_with_log_debug_passes_through_to_borg():
|
||||
(),
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
insert_execute_command_mock(('borg', 'check', '--log-json', '--debug', '--show-rc', 'repo'))
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -832,6 +845,7 @@ def test_check_archives_with_local_path_calls_borg_via_local_path():
|
||||
flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg1', 'check', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -861,6 +875,7 @@ def test_check_archives_with_exit_codes_calls_borg_using_them():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--log-json', 'repo'), borg_exit_codes=borg_exit_codes
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -886,6 +901,7 @@ def test_check_archives_with_remote_path_passes_through_to_borg():
|
||||
flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'check', '--remote-path', 'borg1', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -912,6 +928,7 @@ def test_check_archives_with_umask_passes_through_to_borg():
|
||||
flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'check', '--umask', '077', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -937,6 +954,7 @@ def test_check_archives_with_lock_wait_passes_through_to_borg():
|
||||
flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'check', '--log-json', '--lock-wait', '5', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -963,6 +981,7 @@ def test_check_archives_with_retention_prefix():
|
||||
flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'check', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -992,6 +1011,7 @@ def test_check_archives_with_extra_borg_options_passes_through_to_borg():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--log-json', '--extra', '--options', 'value with space', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -1028,6 +1048,7 @@ def test_check_archives_with_match_archives_passes_through_to_borg():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=[{'code': 1, 'treat_as': 'error'}],
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
@@ -1059,6 +1080,7 @@ def test_check_archives_calls_borg_with_working_directory():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'check', '--log-json', 'repo'), working_directory='/working/dir'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.check_archives(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -33,6 +33,7 @@ COMPACT_COMMAND = ('borg', 'compact')
|
||||
def test_compact_segments_calls_borg_with_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock((*COMPACT_COMMAND, '--log-json', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -83,6 +84,7 @@ def test_compact_segments_with_dry_run_skips_borg_call_when_feature_unavailable(
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').never()
|
||||
flexmock(module).should_receive('execute_command').never()
|
||||
flexmock(module.logger).should_receive('info').with_args('Skipping compact (dry run)').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
repository_path='repo',
|
||||
@@ -102,6 +104,7 @@ def test_compact_segments_with_dry_run_executes_borg_call_when_feature_available
|
||||
flexmock(module.environment).should_receive('make_environment').once()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').once()
|
||||
flexmock(module).should_receive('execute_command').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
repository_path='repo',
|
||||
@@ -115,6 +118,7 @@ def test_compact_segments_with_dry_run_executes_borg_call_when_feature_available
|
||||
def test_compact_segments_with_local_path_calls_borg_via_local_path():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg1', *COMPACT_COMMAND[1:], '--log-json', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -134,6 +138,7 @@ def test_compact_segments_with_exit_codes_calls_borg_using_them():
|
||||
logging.INFO,
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -149,6 +154,7 @@ def test_compact_segments_with_remote_path_calls_borg_with_remote_path_flags():
|
||||
insert_execute_command_mock(
|
||||
(*COMPACT_COMMAND, '--remote-path', 'borg1', '--log-json', 'repo'), logging.INFO
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -163,6 +169,7 @@ def test_compact_segments_with_remote_path_calls_borg_with_remote_path_flags():
|
||||
def test_compact_segments_with_progress_calls_borg_with_progress_flag():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock((*COMPACT_COMMAND, '--progress', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -178,6 +185,7 @@ def test_compact_segments_with_log_json_and_progress_calls_borg_with_both_flags(
|
||||
insert_execute_command_mock(
|
||||
(*COMPACT_COMMAND, '--log-json', '--progress', 'repo'), logging.INFO
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -193,6 +201,7 @@ def test_compact_segments_with_cleanup_commits_calls_borg_with_cleanup_commits_f
|
||||
insert_execute_command_mock(
|
||||
(*COMPACT_COMMAND, '--log-json', '--cleanup-commits', 'repo'), logging.INFO
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -209,6 +218,7 @@ def test_compact_segments_with_threshold_calls_borg_with_threshold_flag():
|
||||
insert_execute_command_mock(
|
||||
(*COMPACT_COMMAND, '--log-json', '--threshold', '20', 'repo'), logging.INFO
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -225,6 +235,7 @@ def test_compact_segments_with_umask_calls_borg_with_umask_flags():
|
||||
insert_execute_command_mock(
|
||||
(*COMPACT_COMMAND, '--umask', '077', '--log-json', 'repo'), logging.INFO
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -241,6 +252,7 @@ def test_compact_segments_with_lock_wait_calls_borg_with_lock_wait_flags():
|
||||
insert_execute_command_mock(
|
||||
(*COMPACT_COMMAND, '--log-json', '--lock-wait', '5', 'repo'), logging.INFO
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -257,6 +269,7 @@ def test_compact_segments_with_extra_borg_options_calls_borg_with_extra_options(
|
||||
(*COMPACT_COMMAND, '--log-json', '--extra', '--options', 'value with space', 'repo'),
|
||||
logging.INFO,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
@@ -274,6 +287,7 @@ def test_compact_segments_calls_borg_with_working_directory():
|
||||
logging.INFO,
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.compact_segments(
|
||||
dry_run=False,
|
||||
|
||||
@@ -1265,6 +1265,7 @@ def test_create_archive_calls_borg_with_flags():
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1299,6 +1300,7 @@ def test_create_archive_calls_borg_with_environment():
|
||||
working_directory=None,
|
||||
environment=environment,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1477,6 +1479,44 @@ def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats():
|
||||
'source_directories': ['foo', 'bar'],
|
||||
'repositories': ['repo'],
|
||||
'exclude_patterns': None,
|
||||
'statistics': True,
|
||||
},
|
||||
patterns=[Pattern('foo'), Pattern('bar')],
|
||||
local_borg_version='1.2.3',
|
||||
global_arguments=flexmock(),
|
||||
borgmatic_runtime_directory='/borgmatic/run',
|
||||
)
|
||||
|
||||
|
||||
def test_create_archive_with_quick_stats_and_dry_run_calls_borg_without_quick_stats():
|
||||
# --dry-run and --quick-stats are mutually exclusive, see:
|
||||
# https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
|
||||
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
|
||||
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
|
||||
flexmock(module).should_receive('make_base_create_command').and_return(
|
||||
(('borg', 'create', '--dry-run'), REPO_ARCHIVE, flexmock()),
|
||||
)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'create', '--dry-run', '--info', *REPO_ARCHIVE),
|
||||
output_log_level=logging.INFO,
|
||||
output_file=None,
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=True,
|
||||
repository_path='repo',
|
||||
config={
|
||||
'source_directories': ['foo', 'bar'],
|
||||
'repositories': ['repo'],
|
||||
'exclude_patterns': None,
|
||||
'quick_statistics': True,
|
||||
},
|
||||
patterns=[Pattern('foo'), Pattern('bar')],
|
||||
local_borg_version='1.2.3',
|
||||
@@ -1504,6 +1544,7 @@ def test_create_archive_with_working_directory_calls_borg_with_working_directory
|
||||
working_directory='/working/dir',
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1539,6 +1580,7 @@ def test_create_archive_with_exit_codes_calls_borg_using_them():
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1573,6 +1615,7 @@ def test_create_archive_with_stats_calls_borg_with_stats_flag_and_answer_output_
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1611,6 +1654,7 @@ def test_create_archive_with_files_calls_borg_with_answer_output_log_level():
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1680,6 +1724,7 @@ def test_create_archive_with_progress_calls_borg_with_progress_flag():
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1731,6 +1776,7 @@ def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progr
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
).and_yield()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1764,6 +1810,7 @@ def test_create_archive_with_json_calls_borg_with_json_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield('[]')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
json_output = module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1798,6 +1845,7 @@ def test_create_archive_with_stats_and_json_calls_borg_without_stats_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield('[]')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
json_output = module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1806,6 +1854,42 @@ def test_create_archive_with_stats_and_json_calls_borg_without_stats_flag():
|
||||
'source_directories': ['foo*'],
|
||||
'repositories': ['repo'],
|
||||
'exclude_patterns': None,
|
||||
'statistics': True,
|
||||
},
|
||||
patterns=[Pattern('foo'), Pattern('bar')],
|
||||
local_borg_version='1.2.3',
|
||||
global_arguments=flexmock(),
|
||||
borgmatic_runtime_directory='/borgmatic/run',
|
||||
json=True,
|
||||
)
|
||||
|
||||
assert json_output == '[]'
|
||||
|
||||
|
||||
def test_create_archive_with_quick_stats_and_json_calls_borg_without_quick_stats_flag():
|
||||
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
|
||||
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
|
||||
flexmock(module).should_receive('make_base_create_command').and_return(
|
||||
(('borg', 'create'), REPO_ARCHIVE, flexmock()),
|
||||
)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
('borg', 'create', '--json', *REPO_ARCHIVE),
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield('[]')
|
||||
|
||||
json_output = module.create_archive(
|
||||
dry_run=False,
|
||||
repository_path='repo',
|
||||
config={
|
||||
'source_directories': ['foo*'],
|
||||
'repositories': ['repo'],
|
||||
'exclude_patterns': None,
|
||||
'quick_statistics': True,
|
||||
},
|
||||
patterns=[Pattern('foo'), Pattern('bar')],
|
||||
local_borg_version='1.2.3',
|
||||
@@ -1834,6 +1918,7 @@ def test_create_archive_with_comment_calls_borg_with_comment_flag():
|
||||
working_directory=None,
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
@@ -1871,6 +1956,7 @@ def test_create_archive_calls_borg_with_working_directory():
|
||||
working_directory='/working/dir',
|
||||
environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.create_archive(
|
||||
dry_run=False,
|
||||
|
||||
@@ -9,13 +9,13 @@ from ..test_verbosity import insert_logging_mock
|
||||
|
||||
|
||||
def test_make_delete_command_includes_log_info():
|
||||
insert_logging_mock(logging.INFO)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_match_archives_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -31,13 +31,13 @@ def test_make_delete_command_includes_log_info():
|
||||
|
||||
|
||||
def test_make_delete_command_includes_log_debug():
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_match_archives_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -63,6 +63,7 @@ def test_make_delete_command_includes_dry_run():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -88,6 +89,7 @@ def test_make_delete_command_includes_remote_path():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -111,6 +113,7 @@ def test_make_delete_command_includes_umask():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -136,6 +139,7 @@ def test_make_delete_command_includes_lock_wait():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -157,6 +161,7 @@ def test_make_delete_command_includes_extra_borg_options():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -182,6 +187,7 @@ def test_make_delete_command_with_list_config_calls_borg_with_list_flag():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -203,6 +209,7 @@ def test_make_delete_command_includes_force():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -224,6 +231,7 @@ def test_make_delete_command_includes_force_twice():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -247,6 +255,7 @@ def test_make_delete_command_includes_archive():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -275,6 +284,7 @@ def test_make_delete_command_includes_match_archives():
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
|
||||
('repo',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_delete_command(
|
||||
repository={'path': 'repo'},
|
||||
@@ -307,6 +317,7 @@ def test_delete_archives_with_archive_calls_borg_delete():
|
||||
)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.execute).should_receive('execute_command').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.delete_archives(
|
||||
repository={'path': 'repo'},
|
||||
@@ -327,6 +338,7 @@ def test_delete_archives_with_match_archives_calls_borg_delete():
|
||||
)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.execute).should_receive('execute_command').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.delete_archives(
|
||||
repository={'path': 'repo'},
|
||||
@@ -348,6 +360,7 @@ def test_delete_archives_with_archive_related_argument_calls_borg_delete(argumen
|
||||
)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.execute).should_receive('execute_command').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.delete_archives(
|
||||
repository={'path': 'repo'},
|
||||
@@ -367,6 +380,7 @@ def test_delete_archives_without_archive_related_argument_calls_borg_repo_delete
|
||||
flexmock(module.borgmatic.borg.environment).should_receive('make_environment').never()
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.borgmatic.execute).should_receive('execute_command').never()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.delete_archives(
|
||||
repository={'path': 'repo'},
|
||||
@@ -403,6 +417,7 @@ def test_delete_archives_calls_borg_delete_with_working_directory():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.delete_archives(
|
||||
repository={'path': 'repo'},
|
||||
|
||||
@@ -4,6 +4,8 @@ from flexmock import flexmock
|
||||
|
||||
from borgmatic.borg import diff as module
|
||||
|
||||
from ..test_verbosity import insert_logging_mock
|
||||
|
||||
LOGGING_ANSWER = flexmock()
|
||||
|
||||
|
||||
@@ -40,6 +42,7 @@ def test_diff_calls_borg_with_archives():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -94,6 +97,7 @@ def test_diff_with_local_path_calls_borg_with_it():
|
||||
borg_local_path='borg6',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -150,6 +154,7 @@ def test_diff_with_remote_path_calls_borg_with_it():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -206,6 +211,7 @@ def test_diff_with_lock_wait_calls_borg_with_it():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -262,6 +268,7 @@ def test_diff_with_log_level_info_calls_borg_with_info_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -319,6 +326,7 @@ def test_diff_with_log_level_debug_calls_borg_with_debug_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -376,6 +384,7 @@ def test_diff_with_only_patterns_calls_borg_with_configured_pattern_paths():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -434,6 +443,7 @@ def test_diff_with_exclude_config_calls_borg_with_exclude_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -489,6 +499,7 @@ def test_diff_with_numeric_ids_calls_borg_with_numeric_ids_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -549,6 +560,7 @@ def test_diff_with_numeric_ids_and_feature_not_available_calls_borg_with_numeric
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -604,6 +616,7 @@ def test_diff_with_same_chunker_params_calls_borg_with_it():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -660,6 +673,7 @@ def test_diff_with_sort_keys_calls_borg_with_formatted_sort_by_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -715,6 +729,7 @@ def test_diff_with_content_only_calls_borg_with_it():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -771,6 +786,7 @@ def test_diff_with_extra_borg_options_calls_borg_with_them():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
@@ -828,6 +844,7 @@ def test_diff_without_separate_repository_archive_feature_available_calls_borg_j
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.borgmatic.borg.diff.diff(
|
||||
repository='repo',
|
||||
|
||||
@@ -36,6 +36,7 @@ def test_export_key_calls_borg_with_required_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -50,6 +51,7 @@ def test_export_key_calls_borg_with_local_path():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg1', 'key', 'export', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -66,6 +68,7 @@ def test_export_key_calls_borg_using_exit_codes():
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
borg_exit_codes = flexmock()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', 'repo'), borg_exit_codes=borg_exit_codes)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -80,6 +83,7 @@ def test_export_key_calls_borg_with_remote_path_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--remote-path', 'borg1', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -95,6 +99,7 @@ def test_export_key_calls_borg_with_umask_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--umask', '0770', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -109,6 +114,7 @@ def test_export_key_calls_borg_with_lock_wait_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--lock-wait', '5', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -123,6 +129,7 @@ def test_export_key_calls_borg_with_extra_borg_options():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--extra', 'value with space', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -167,6 +174,7 @@ def test_export_key_calls_borg_with_paper_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--paper', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -181,6 +189,7 @@ def test_export_key_calls_borg_with_paper_flag():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--paper', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -195,6 +204,7 @@ def test_export_key_calls_borg_with_qr_html_flag():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', '--qr-html', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -211,6 +221,7 @@ def test_export_key_calls_borg_with_path_argument():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'export', '--log-json', 'repo', 'dest'), output_file=None
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -240,6 +251,7 @@ def test_export_key_with_stdout_path_calls_borg_without_path_argument():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -268,6 +280,7 @@ def test_export_key_calls_borg_with_working_directory():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'export', 'repo'), working_directory='/working/dir')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
@@ -288,6 +301,7 @@ def test_export_key_calls_borg_with_path_argument_and_working_directory():
|
||||
output_file=None,
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_key(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -39,6 +39,7 @@ def test_export_tar_archive_calls_borg_with_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'export-tar', '--log-json', 'repo::archive', 'test.tar', 'path1', 'path2'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -62,6 +63,7 @@ def test_export_tar_archive_calls_borg_with_local_path_flags():
|
||||
('borg1', 'export-tar', '--log-json', 'repo::archive', 'test.tar'),
|
||||
borg_local_path='borg1',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -87,6 +89,7 @@ def test_export_tar_archive_calls_borg_using_exit_codes():
|
||||
('borg', 'export-tar', '--log-json', 'repo::archive', 'test.tar'),
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -109,6 +112,7 @@ def test_export_tar_archive_calls_borg_with_remote_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'export-tar', '--remote-path', 'borg1', '--log-json', 'repo::archive', 'test.tar'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -132,6 +136,7 @@ def test_export_tar_archive_calls_borg_with_umask_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'export-tar', '--umask', '0770', '--log-json', 'repo::archive', 'test.tar'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -154,6 +159,7 @@ def test_export_tar_archive_calls_borg_with_lock_wait_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'export-tar', '--log-json', '--lock-wait', '5', 'repo::archive', 'test.tar'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -184,6 +190,7 @@ def test_export_tar_archive_calls_borg_with_extra_borg_options():
|
||||
'test.tar',
|
||||
),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -272,6 +279,7 @@ def test_export_tar_archive_calls_borg_with_tar_filter_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'export-tar', '--log-json', '--tar-filter', 'bzip2', 'repo::archive', 'test.tar'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -296,6 +304,7 @@ def test_export_tar_archive_calls_borg_with_list_flag():
|
||||
('borg', 'export-tar', '--log-json', '--list', 'repo::archive', 'test.tar'),
|
||||
output_log_level=logging.ANSWER,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -326,6 +335,7 @@ def test_export_tar_archive_calls_borg_with_strip_components_flag():
|
||||
'test.tar',
|
||||
),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -349,6 +359,7 @@ def test_export_tar_archive_skips_abspath_for_remote_repository_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'export-tar', '--log-json', 'server:repo::archive', 'test.tar')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -369,6 +380,7 @@ def test_export_tar_archive_calls_borg_with_stdout_destination_path():
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'export-tar', 'repo::archive', '-'), capture=False)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
@@ -392,6 +404,7 @@ def test_export_tar_archive_calls_borg_with_working_directory():
|
||||
('borg', 'export-tar', '--log-json', 'repo::archive', 'test.tar'),
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.export_tar_archive(
|
||||
dry_run=False,
|
||||
|
||||
@@ -25,6 +25,7 @@ def test_extract_last_archive_dry_run_calls_borg_with_last_archive():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -38,6 +39,7 @@ def test_extract_last_archive_dry_run_calls_borg_with_last_archive():
|
||||
def test_extract_last_archive_dry_run_without_any_archives_should_not_raise():
|
||||
flexmock(module.repo_list).should_receive('resolve_archive_name').and_raise(ValueError)
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -53,10 +55,10 @@ def test_extract_last_archive_dry_run_with_log_info_calls_borg_with_info_paramet
|
||||
insert_execute_command_mock(
|
||||
('borg', 'extract', '--dry-run', '--log-json', '--info', 'repo::archive')
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -81,10 +83,10 @@ def test_extract_last_archive_dry_run_with_log_debug_calls_borg_with_debug_param
|
||||
'repo::archive',
|
||||
),
|
||||
)
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -109,6 +111,7 @@ def test_extract_last_archive_dry_run_calls_borg_with_progress_flag():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={'progress': True},
|
||||
@@ -125,6 +128,7 @@ def test_extract_last_archive_dry_run_calls_borg_via_local_path():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -146,6 +150,7 @@ def test_extract_last_archive_dry_run_calls_borg_using_exit_codes():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={'borg_exit_codes': borg_exit_codes},
|
||||
@@ -164,6 +169,7 @@ def test_extract_last_archive_dry_run_calls_borg_with_remote_path_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -183,6 +189,7 @@ def test_extract_last_archive_dry_run_calls_borg_with_lock_wait_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={},
|
||||
@@ -209,6 +216,7 @@ def test_extract_last_archive_dry_run_calls_borg_with_extra_borg_options():
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_last_archive_dry_run(
|
||||
config={'extra_borg_options': {'extract': '--extra "value with space"'}},
|
||||
@@ -231,6 +239,7 @@ def test_extract_archive_calls_borg_with_path_flags():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -254,6 +263,7 @@ def test_extract_archive_calls_borg_with_local_path():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -282,6 +292,7 @@ def test_extract_archive_calls_borg_with_exit_codes():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -307,6 +318,7 @@ def test_extract_archive_calls_borg_with_remote_path_flags():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -338,6 +350,7 @@ def test_extract_archive_calls_borg_with_numeric_ids_parameter(feature_available
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -363,6 +376,7 @@ def test_extract_archive_calls_borg_with_umask_flags():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -388,6 +402,7 @@ def test_extract_archive_calls_borg_with_lock_wait_flags():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -413,6 +428,7 @@ def test_extract_archive_calls_borg_with_extra_borg_options():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -428,7 +444,6 @@ def test_extract_archive_calls_borg_with_extra_borg_options():
|
||||
def test_extract_archive_with_log_info_calls_borg_with_info_parameter():
|
||||
flexmock(module.os.path).should_receive('abspath').and_return('repo')
|
||||
insert_execute_command_mock(('borg', 'extract', '--log-json', '--info', 'repo::archive'))
|
||||
insert_logging_mock(logging.INFO)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
@@ -437,6 +452,7 @@ def test_extract_archive_with_log_info_calls_borg_with_info_parameter():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -454,7 +470,6 @@ def test_extract_archive_with_log_debug_calls_borg_with_debug_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'extract', '--log-json', '--debug', '--list', '--show-rc', 'repo::archive'),
|
||||
)
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
@@ -463,6 +478,7 @@ def test_extract_archive_with_log_debug_calls_borg_with_debug_flags():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -486,6 +502,7 @@ def test_extract_archive_calls_borg_with_dry_run_parameter():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=True,
|
||||
@@ -511,6 +528,7 @@ def test_extract_archive_calls_borg_with_destination_path():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -537,6 +555,7 @@ def test_extract_archive_calls_borg_with_strip_components():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -572,6 +591,7 @@ def test_extract_archive_calls_borg_with_strip_components_calculated_from_all():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -607,6 +627,7 @@ def test_extract_archive_calls_borg_with_strip_components_calculated_from_all_wi
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -631,6 +652,7 @@ def test_extract_archive_with_strip_components_all_and_no_paths_raises():
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
flexmock(module).should_receive('execute_command').never()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
module.extract_archive(
|
||||
@@ -665,6 +687,7 @@ def test_extract_archive_calls_borg_with_progress_flag():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -697,6 +720,7 @@ def test_extract_archive_with_log_json_and_progress_calls_borg_with_both_flags()
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -731,6 +755,7 @@ def test_extract_archive_calls_borg_with_extract_to_stdout_returns_process():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.extract_archive(
|
||||
@@ -769,6 +794,7 @@ def test_extract_archive_with_progress_and_extract_to_stdout_ignores_progress():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.extract_archive(
|
||||
@@ -804,6 +830,7 @@ def test_extract_archive_skips_abspath_for_remote_repository():
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).and_return('repo')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -829,6 +856,7 @@ def test_extract_archive_uses_configured_working_directory_in_repo_path_and_dest
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).with_args('repo', '/working/dir').and_return('/working/dir/repo').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
@@ -852,6 +880,7 @@ def test_extract_archive_uses_configured_working_directory_in_repo_path_when_des
|
||||
flexmock(module.borgmatic.config.validate).should_receive(
|
||||
'normalize_repository_path',
|
||||
).with_args('repo', '/working/dir').and_return('/working/dir/repo').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.extract_archive(
|
||||
dry_run=False,
|
||||
|
||||
@@ -32,6 +32,7 @@ def test_import_key_calls_borg_with_required_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'import', '--log-json', 'repo', '-'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -47,6 +48,7 @@ def test_import_key_calls_borg_with_local_path():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg1', 'key', 'import', '--log-json', 'repo', '-'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -66,6 +68,7 @@ def test_import_key_calls_borg_using_exit_codes():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--log-json', 'repo', '-'), borg_exit_codes=borg_exit_codes
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -83,6 +86,7 @@ def test_import_key_calls_borg_with_remote_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--remote-path', 'borg1', '--log-json', 'repo', '-')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -101,6 +105,7 @@ def test_import_key_calls_borg_with_umask_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--umask', '0770', '--log-json', 'repo', '-')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -118,6 +123,7 @@ def test_import_key_calls_borg_with_lock_wait_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--log-json', '--lock-wait', '5', 'repo', '-')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -135,6 +141,7 @@ def test_import_key_calls_borg_with_extra_borg_options():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--log-json', '--extra', 'value with space', 'repo', '-')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -184,6 +191,7 @@ def test_import_key_calls_borg_with_paper_flags():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'import', '--log-json', '--paper', 'repo', '-'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -201,6 +209,7 @@ def test_import_key_calls_borg_with_path_argument():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--log-json', 'repo', 'source'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -232,6 +241,7 @@ def test_import_key_with_stdin_path_calls_borg_without_path_argument():
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
insert_execute_command_mock(('borg', 'key', 'import', '--log-json', 'repo', '-'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -264,6 +274,7 @@ def test_import_key_calls_borg_with_working_directory():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'key', 'import', '--log-json', 'repo', '-'), working_directory='/working/dir'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
@@ -284,6 +295,7 @@ def test_import_key_calls_borg_with_path_argument_and_working_directory():
|
||||
('borg', 'key', 'import', '--log-json', 'repo', 'source'),
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.import_key(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -17,6 +17,7 @@ def test_make_info_command_constructs_borg_info_command():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -112,6 +113,7 @@ def test_make_info_command_with_log_debug_and_json_omits_borg_logging_flags():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -135,6 +137,7 @@ def test_make_info_command_with_json_passes_through_to_command():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -158,6 +161,7 @@ def test_make_info_command_with_archive_uses_match_archives_flags():
|
||||
).and_return(('--match-archives', 'archive'))
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -189,6 +193,7 @@ def test_make_info_command_with_local_path_passes_through_to_command():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -216,6 +221,7 @@ def test_make_info_command_with_remote_path_passes_through_to_command():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -241,6 +247,7 @@ def test_make_info_command_with_umask_passes_through_to_command():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -268,6 +275,7 @@ def test_make_info_command_with_lock_wait_passes_through_to_command():
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
config = {'lock_wait': 5}
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -292,6 +300,7 @@ def test_make_info_command_with_extra_borg_options_passes_through_to_command():
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
config = {'extra_borg_options': {'info': '--extra "value with space"'}}
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -327,6 +336,7 @@ def test_make_info_command_transforms_prefix_into_match_archives_flags():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -362,6 +372,7 @@ def test_make_info_command_prefers_prefix_over_archive_name_format():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -393,6 +404,7 @@ def test_make_info_command_transforms_archive_name_format_into_match_archives_fl
|
||||
).and_return(('--match-archives', 'sh:bar-*'))
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -425,6 +437,7 @@ def test_make_info_command_with_match_archives_option_passes_through_to_command(
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -460,6 +473,7 @@ def test_make_info_command_with_match_archives_flag_passes_through_to_command():
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -496,6 +510,7 @@ def test_make_info_command_passes_arguments_through_to_command(argument_name):
|
||||
)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
@@ -537,6 +552,7 @@ def test_make_info_command_with_date_based_matching_passes_through_to_command():
|
||||
older='1m',
|
||||
oldest='1w',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_info_command(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -78,6 +78,7 @@ def test_make_list_command_includes_json_but_not_debug():
|
||||
|
||||
|
||||
def test_make_list_command_includes_json():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
@@ -94,6 +95,7 @@ def test_make_list_command_includes_json():
|
||||
|
||||
|
||||
def test_make_list_command_includes_lock_wait():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
|
||||
('--lock-wait', '5'),
|
||||
).and_return(())
|
||||
@@ -112,6 +114,7 @@ def test_make_list_command_includes_lock_wait():
|
||||
|
||||
|
||||
def test_make_list_command_includes_format():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
|
||||
()
|
||||
).and_return(('--format', 'stuff'))
|
||||
@@ -130,6 +133,7 @@ def test_make_list_command_includes_format():
|
||||
|
||||
|
||||
def test_make_list_command_includes_extra_borg_options():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
@@ -146,6 +150,7 @@ def test_make_list_command_includes_extra_borg_options():
|
||||
|
||||
|
||||
def test_make_list_command_includes_archive():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
@@ -164,6 +169,7 @@ def test_make_list_command_includes_archive():
|
||||
|
||||
|
||||
def test_make_list_command_includes_archive_and_path():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||
@@ -182,6 +188,7 @@ def test_make_list_command_includes_archive_and_path():
|
||||
|
||||
|
||||
def test_make_list_command_includes_local_path():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
@@ -199,6 +206,7 @@ def test_make_list_command_includes_local_path():
|
||||
|
||||
|
||||
def test_make_list_command_includes_remote_path():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags').with_args(
|
||||
'remote-path',
|
||||
@@ -223,6 +231,7 @@ def test_make_list_command_includes_remote_path():
|
||||
|
||||
|
||||
def test_make_list_command_includes_umask():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').replace_with(
|
||||
lambda name, value: (f'--{name}', value) if value else (),
|
||||
)
|
||||
@@ -241,6 +250,7 @@ def test_make_list_command_includes_umask():
|
||||
|
||||
|
||||
def test_make_list_command_includes_short():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--short',))
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
@@ -271,6 +281,7 @@ def test_make_list_command_includes_short():
|
||||
),
|
||||
)
|
||||
def test_make_list_command_includes_additional_flags(argument_name):
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(
|
||||
(f"--{argument_name.replace('_', '-')}", 'value'),
|
||||
|
||||
@@ -25,6 +25,7 @@ def test_mount_archive_calls_borg_with_required_flags():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_execute_command_mock(('borg', 'mount', '--log-json', 'repo', '/mnt'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -48,6 +49,7 @@ def test_mount_archive_with_borg_features_calls_borg_with_repository_and_match_a
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--log-json', '--repo', 'repo', '--match-archives', 'archive', '/mnt'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -66,6 +68,7 @@ def test_mount_archive_without_archive_calls_borg_with_repository_flags_only():
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'mount', '--log-json', 'repo::archive', '/mnt'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -86,6 +89,7 @@ def test_mount_archive_calls_borg_with_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--log-json', 'repo::archive', '/mnt', 'path1', 'path2')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(
|
||||
mount_point='/mnt',
|
||||
@@ -109,6 +113,7 @@ def test_mount_archive_calls_borg_with_local_path():
|
||||
('repo::archive',),
|
||||
)
|
||||
insert_execute_command_mock(('borg1', 'mount', '--log-json', 'repo::archive', '/mnt'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -132,6 +137,7 @@ def test_mount_archive_calls_borg_using_exit_codes():
|
||||
('borg', 'mount', '--log-json', 'repo::archive', '/mnt'),
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -152,6 +158,7 @@ def test_mount_archive_calls_borg_with_remote_path_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--remote-path', 'borg1', '--log-json', 'repo::archive', '/mnt'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -173,6 +180,7 @@ def test_mount_archive_calls_borg_with_umask_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--umask', '0770', '--log-json', 'repo::archive', '/mnt')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -193,6 +201,7 @@ def test_mount_archive_calls_borg_with_lock_wait_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--log-json', '--lock-wait', '5', 'repo::archive', '/mnt')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -213,6 +222,7 @@ def test_mount_archive_calls_borg_with_extra_borg_options():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--log-json', '--extra', 'value with space', 'repo::archive', '/mnt')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
@@ -280,6 +290,7 @@ def test_mount_archive_calls_borg_with_foreground_parameter():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=True)
|
||||
module.mount_archive(
|
||||
@@ -300,6 +311,7 @@ def test_mount_archive_calls_borg_with_options_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--log-json', '-o', 'super_mount', 'repo::archive', '/mnt')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(
|
||||
mount_point='/mnt',
|
||||
@@ -361,6 +373,7 @@ def test_mount_archive_with_date_based_matching_calls_borg_with_date_based_flags
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(
|
||||
mount_point='/mnt',
|
||||
@@ -388,6 +401,7 @@ def test_mount_archive_calls_borg_with_working_directory():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'mount', '--log-json', 'repo', '/mnt'), working_directory='/working/dir'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
|
||||
module.mount_archive(
|
||||
|
||||
@@ -244,6 +244,7 @@ def test_prune_archives_calls_borg_with_flags():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -312,6 +313,7 @@ def test_prune_archives_with_dry_run_calls_borg_with_dry_run_flag():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, '--dry-run', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -334,6 +336,7 @@ def test_prune_archives_with_local_path_calls_borg_via_local_path():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock(('borg1', *PRUNE_COMMAND[1:], 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -362,6 +365,7 @@ def test_prune_archives_with_exit_codes_calls_borg_using_them():
|
||||
logging.INFO,
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -384,6 +388,7 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_flags():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, '--remote-path', 'borg1', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -407,6 +412,7 @@ def test_prune_archives_with_stats_config_calls_borg_with_stats_flag():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, '--stats', 'repo'), module.borgmatic.logger.ANSWER)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=None, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -429,6 +435,7 @@ def test_prune_archives_with_list_config_calls_borg_with_list_flag():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, '--list', 'repo'), module.borgmatic.logger.ANSWER)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=None)
|
||||
module.prune_archives(
|
||||
@@ -452,6 +459,7 @@ def test_prune_archives_with_umask_calls_borg_with_umask_flags():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, '--umask', '077', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -475,6 +483,7 @@ def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_flags():
|
||||
'1.2.3',
|
||||
).and_return(False)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, '--lock-wait', '5', 'repo'), logging.INFO)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -500,6 +509,7 @@ def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
|
||||
(*PRUNE_COMMAND, '--extra', '--options', 'value with space', 'repo'),
|
||||
logging.INFO,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -569,6 +579,7 @@ def test_prune_archives_with_date_based_matching_calls_borg_with_date_based_flag
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(
|
||||
statistics=False,
|
||||
@@ -602,6 +613,7 @@ def test_prune_archives_calls_borg_with_working_directory():
|
||||
logging.INFO,
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=False, list_details=False)
|
||||
module.prune_archives(
|
||||
@@ -624,6 +636,7 @@ def test_prune_archives_calls_borg_without_stats_when_feature_is_not_available()
|
||||
'2.0.0b10',
|
||||
).and_return(True)
|
||||
insert_execute_command_mock((*PRUNE_COMMAND, 'repo'), logging.ANSWER)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
prune_arguments = flexmock(statistics=True, list_details=False)
|
||||
module.prune_archives(
|
||||
|
||||
@@ -35,6 +35,7 @@ def test_recreate_calls_borg_with_required_flags():
|
||||
),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -70,6 +71,7 @@ def test_recreate_with_dry_run_calls_borg_with_dry_run_flag():
|
||||
),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', '--dry-run', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -107,6 +109,7 @@ def test_recreate_with_remote_path():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--remote-path', 'borg1', '--log-json', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -144,6 +147,7 @@ def test_recreate_with_lock_wait():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--lock-wait', '5', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -180,6 +184,7 @@ def test_recreate_with_extra_borg_options():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--extra', 'value with space', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -214,7 +219,6 @@ def test_recreate_with_log_info():
|
||||
),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', '--info', '--repo', 'repo'))
|
||||
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.recreate_archive(
|
||||
@@ -291,6 +295,7 @@ def test_recreate_with_list_config_calls_borg_with_list_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--list', '--filter', 'AME+-', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -328,6 +333,7 @@ def test_recreate_with_patterns_from_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--patterns-from', 'patterns_file', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -366,6 +372,7 @@ def test_recreate_with_exclude_flags():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--exclude', 'pattern', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -402,6 +409,7 @@ def test_recreate_with_target_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--target', 'new-archive', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -446,6 +454,7 @@ def test_recreate_with_comment_flag():
|
||||
'repo',
|
||||
),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -482,6 +491,7 @@ def test_recreate_with_timestamp_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--timestamp', '2023-10-01T12:00:00', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -518,6 +528,7 @@ def test_recreate_with_compression_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--compression', 'lz4', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -554,6 +565,7 @@ def test_recreate_with_chunker_params_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--chunker-params', '19,23,21,4095', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -590,6 +602,7 @@ def test_recreate_with_recompress_flag():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--recompress', 'always', '--repo', 'repo')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -624,6 +637,7 @@ def test_recreate_with_match_archives_star():
|
||||
),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -658,6 +672,7 @@ def test_recreate_with_match_archives_regex():
|
||||
),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -692,6 +707,7 @@ def test_recreate_with_match_archives_shell():
|
||||
),
|
||||
)
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -728,6 +744,7 @@ def test_recreate_with_match_archives_and_feature_available_calls_borg_with_matc
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--repo', 'repo', '--match-archives', 'foo-*')
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -764,6 +781,7 @@ def test_recreate_with_archives_flag_and_feature_available_calls_borg_with_match
|
||||
insert_execute_command_mock(
|
||||
('borg', 'recreate', '--log-json', '--repo', 'repo', '--match-archives', 'archive'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -794,6 +812,7 @@ def test_recreate_with_match_archives_and_feature_not_available_calls_borg_witho
|
||||
)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_archive_flags').never()
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
@@ -824,6 +843,7 @@ def test_recreate_with_archives_flags_and_feature_not_available_calls_borg_with_
|
||||
).and_return(('repo::archive',))
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').never()
|
||||
insert_execute_command_mock(('borg', 'recreate', '--log-json', 'repo::archive'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.recreate_archive(
|
||||
repository='repo',
|
||||
|
||||
@@ -50,6 +50,7 @@ def insert_repo_create_command_mock(
|
||||
def test_create_repository_calls_borg_with_flags():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -177,6 +178,7 @@ def test_create_repository_with_source_repository_calls_borg_with_other_repo_fla
|
||||
insert_repo_create_command_mock(
|
||||
(*REPO_CREATE_COMMAND, '--other-repo', 'other.borg', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -199,6 +201,7 @@ def test_create_repository_with_source_repository_calls_borg_with_other_repo_fla
|
||||
def test_create_repository_with_copy_crypt_key_calls_borg_with_copy_crypt_key_flag():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--copy-crypt-key', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -221,6 +224,7 @@ def test_create_repository_with_copy_crypt_key_calls_borg_with_copy_crypt_key_fl
|
||||
def test_create_repository_with_append_only_calls_borg_with_append_only_flag():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--append-only', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -243,6 +247,7 @@ def test_create_repository_with_append_only_calls_borg_with_append_only_flag():
|
||||
def test_create_repository_with_append_only_config_calls_borg_with_append_only_flag():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--append-only', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -267,6 +272,7 @@ def test_create_repository_with_storage_quota_calls_borg_with_storage_quota_flag
|
||||
insert_repo_create_command_mock(
|
||||
(*REPO_CREATE_COMMAND, '--storage-quota', '5G', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -289,6 +295,7 @@ def test_create_repository_with_storage_quota_calls_borg_with_storage_quota_flag
|
||||
def test_create_repository_with_make_parent_dirs_calls_borg_with_make_parent_dirs_flag():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--make-parent-dirs', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -355,6 +362,7 @@ def test_create_repository_with_log_debug_calls_borg_with_debug_flag():
|
||||
def test_create_repository_with_lock_wait_calls_borg_with_lock_wait_flag():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--lock-wait', '5', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -376,6 +384,7 @@ def test_create_repository_with_lock_wait_calls_borg_with_lock_wait_flag():
|
||||
def test_create_repository_with_local_path_calls_borg_via_local_path():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock(('borg1', *REPO_CREATE_COMMAND[1:], '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -402,6 +411,7 @@ def test_create_repository_with_exit_codes_calls_borg_using_them():
|
||||
('borg', *REPO_CREATE_COMMAND[1:], '--repo', 'repo'),
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -425,6 +435,7 @@ def test_create_repository_with_remote_path_calls_borg_with_remote_path_flag():
|
||||
insert_repo_create_command_mock(
|
||||
(*REPO_CREATE_COMMAND, '--remote-path', 'borg1', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -447,6 +458,7 @@ def test_create_repository_with_remote_path_calls_borg_with_remote_path_flag():
|
||||
def test_create_repository_with_umask_calls_borg_with_umask_flag():
|
||||
insert_repo_info_command_not_found_mock()
|
||||
insert_repo_create_command_mock((*REPO_CREATE_COMMAND, '--umask', '077', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -470,6 +482,7 @@ def test_create_repository_calls_borg_with_extra_borg_options():
|
||||
insert_repo_create_command_mock(
|
||||
(*REPO_CREATE_COMMAND, '--extra', '--options', 'value with space', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -494,6 +507,7 @@ def test_create_repository_calls_borg_with_extra_borg_options_from_deprecated_in
|
||||
insert_repo_create_command_mock(
|
||||
(*REPO_CREATE_COMMAND, '--extra', '--options', 'value with space', '--repo', 'repo'),
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
@@ -518,6 +532,7 @@ def test_create_repository_calls_borg_with_working_directory():
|
||||
(*REPO_CREATE_COMMAND, '--repo', 'repo'),
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(
|
||||
(
|
||||
|
||||
@@ -8,6 +8,7 @@ from ..test_verbosity import insert_logging_mock
|
||||
|
||||
|
||||
def test_make_repo_delete_command_with_feature_available_runs_borg_repo_delete():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
@@ -30,6 +31,7 @@ def test_make_repo_delete_command_with_feature_available_runs_borg_repo_delete()
|
||||
|
||||
|
||||
def test_make_repo_delete_command_without_feature_available_runs_borg_delete():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
@@ -98,6 +100,7 @@ def test_make_repo_delete_command_includes_log_debug():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_dry_run():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args(
|
||||
@@ -124,6 +127,7 @@ def test_make_repo_delete_command_includes_dry_run():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_remote_path():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args(
|
||||
@@ -150,6 +154,7 @@ def test_make_repo_delete_command_includes_remote_path():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_umask():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').replace_with(
|
||||
lambda name, value: (f'--{name}', value) if value else (),
|
||||
@@ -174,6 +179,7 @@ def test_make_repo_delete_command_includes_umask():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_lock_wait():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args(
|
||||
@@ -200,6 +206,7 @@ def test_make_repo_delete_command_includes_lock_wait():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_without_feature_available_includes_delete_extra_borg_options():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
@@ -222,6 +229,7 @@ def test_make_repo_delete_command_without_feature_available_includes_delete_extr
|
||||
|
||||
|
||||
def test_make_repo_delete_command_with_feature_available_includes_delete_extra_borg_options():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
@@ -244,6 +252,7 @@ def test_make_repo_delete_command_with_feature_available_includes_delete_extra_b
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_list():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args(
|
||||
@@ -270,6 +279,7 @@ def test_make_repo_delete_command_includes_list():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_force():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
@@ -292,6 +302,7 @@ def test_make_repo_delete_command_includes_force():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_includes_force_twice():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
@@ -314,6 +325,7 @@ def test_make_repo_delete_command_includes_force_twice():
|
||||
|
||||
|
||||
def test_make_repo_delete_command_with_output_file_omits_log_json():
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
|
||||
flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
|
||||
@@ -38,6 +38,7 @@ def test_display_repository_info_calls_borg_with_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -74,6 +75,7 @@ def test_display_repository_info_without_borg_features_calls_borg_with_info_sub_
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -116,6 +118,7 @@ def test_display_repository_info_with_log_info_calls_borg_with_info_flag():
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
config={},
|
||||
@@ -148,8 +151,8 @@ def test_display_repository_info_with_log_info_and_json_suppresses_most_borg_out
|
||||
borg_exit_codes=None,
|
||||
).and_yield('[]')
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags').never()
|
||||
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
json_output = module.display_repository_info(
|
||||
repository_path='repo',
|
||||
config={},
|
||||
@@ -226,8 +229,8 @@ def test_display_repository_info_with_log_debug_and_json_suppresses_most_borg_ou
|
||||
borg_exit_codes=None,
|
||||
).and_yield('[]')
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags').never()
|
||||
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
json_output = module.display_repository_info(
|
||||
repository_path='repo',
|
||||
config={},
|
||||
@@ -262,6 +265,7 @@ def test_display_repository_info_with_json_calls_borg_with_json_flag():
|
||||
borg_exit_codes=None,
|
||||
).and_yield('[]')
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags').never()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
json_output = module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -305,6 +309,7 @@ def test_display_repository_info_with_local_path_calls_borg_via_local_path():
|
||||
borg_local_path='borg1',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -348,6 +353,7 @@ def test_display_repository_info_with_exit_codes_calls_borg_using_them():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -389,6 +395,7 @@ def test_display_repository_info_with_remote_path_calls_borg_with_remote_path_fl
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -431,6 +438,7 @@ def test_display_repository_info_with_umask_calls_borg_with_umask_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -467,6 +475,7 @@ def test_display_repository_info_with_lock_wait_calls_borg_with_lock_wait_flags(
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -509,6 +518,7 @@ def test_display_repository_info_without_feature_available_calls_borg_with_info_
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -561,6 +571,7 @@ def test_display_repository_info_with_feature_available_calls_borg_with_repo_inf
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
@@ -604,6 +615,7 @@ def test_display_repository_info_calls_borg_with_working_directory():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.display_repository_info(
|
||||
repository_path='repo',
|
||||
|
||||
@@ -126,6 +126,7 @@ def test_get_latest_archive_calls_borg_with_flags():
|
||||
environment=None,
|
||||
working_directory=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -218,6 +219,7 @@ def test_get_latest_archive_with_local_path_calls_borg_via_local_path():
|
||||
borg_local_path='borg1',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -250,6 +252,7 @@ def test_get_latest_archive_with_exit_codes_calls_borg_using_them():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -283,6 +286,7 @@ def test_get_latest_archive_with_remote_path_calls_borg_with_remote_path_flags()
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -317,6 +321,7 @@ def test_get_latest_archive_with_umask_calls_borg_with_umask_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -346,6 +351,7 @@ def test_get_latest_archive_without_archives_raises():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': []}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
module.get_latest_archive(
|
||||
@@ -377,6 +383,7 @@ def test_get_latest_archive_with_lock_wait_calls_borg_with_lock_wait_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -409,6 +416,7 @@ def test_get_latest_archive_with_match_archives_calls_borg_with_match_archives_f
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -447,6 +455,7 @@ def test_get_latest_archive_calls_borg_with_list_extra_borg_options():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -485,6 +494,7 @@ def test_get_latest_archive_with_feature_available_calls_borg_with_repo_list_ext
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -518,6 +528,7 @@ def test_get_latest_archive_with_consider_checkpoints_calls_borg_with_consider_c
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -552,6 +563,7 @@ def test_get_latest_archive_with_consider_checkpoints_and_feature_available_call
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -585,6 +597,7 @@ def test_get_latest_archive_calls_borg_with_working_directory():
|
||||
environment=None,
|
||||
working_directory='/working/dir',
|
||||
).and_yield(json.dumps({'archives': [expected_archive]}))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
assert (
|
||||
module.get_latest_archive(
|
||||
@@ -758,6 +771,7 @@ def test_make_repo_list_command_includes_lock_wait():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -787,6 +801,7 @@ def test_make_repo_list_command_includes_list_extra_borg_options():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -816,6 +831,7 @@ def test_make_repo_list_command_with_feature_available_includes_repo_list_extra_
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -845,6 +861,7 @@ def test_make_repo_list_command_includes_local_path():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -877,6 +894,7 @@ def test_make_repo_list_command_includes_remote_path():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -909,6 +927,7 @@ def test_make_repo_list_command_includes_umask():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -940,6 +959,7 @@ def test_make_repo_list_command_transforms_prefix_into_match_archives():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -962,6 +982,7 @@ def test_make_repo_list_command_prefers_prefix_over_archive_name_format():
|
||||
flexmock(module.flags).should_receive('make_match_archives_flags').never()
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -986,6 +1007,7 @@ def test_make_repo_list_command_transforms_archive_name_format_into_match_archiv
|
||||
).and_return(('--match-archives', 'sh:bar-*'))
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -1017,6 +1039,7 @@ def test_make_repo_list_command_includes_format_from_command_line():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -1047,6 +1070,7 @@ def test_make_repo_list_command_includes_short():
|
||||
).and_return(())
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--short',))
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -1091,6 +1115,7 @@ def test_make_repo_list_command_includes_additional_flags(argument_name):
|
||||
(f"--{argument_name.replace('_', '-')}", 'value'),
|
||||
)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -1134,6 +1159,7 @@ def test_make_repo_list_command_with_match_archives_calls_borg_with_match_archiv
|
||||
).and_return(('--match-archives', 'foo-*'))
|
||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -1161,6 +1187,7 @@ def test_list_repository_calls_borg_command():
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').and_yield('').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags')
|
||||
|
||||
module.list_repository(
|
||||
@@ -1178,6 +1205,7 @@ def test_list_repository_with_json_calls_borg_json_command_only():
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').and_yield('{}')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags').never()
|
||||
|
||||
assert (
|
||||
@@ -1204,6 +1232,7 @@ def test_make_repo_list_command_with_date_based_matching_calls_borg_with_date_ba
|
||||
('--newer', '1d', '--newest', '1y', '--older', '1m', '--oldest', '1w'),
|
||||
)
|
||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
command = module.make_repo_list_command(
|
||||
repository_path='repo',
|
||||
@@ -1256,6 +1285,7 @@ def test_list_repository_calls_borg_with_working_directory():
|
||||
borg_local_path=object,
|
||||
borg_exit_codes=object,
|
||||
).and_yield('').once()
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags')
|
||||
|
||||
module.list_repository(
|
||||
|
||||
@@ -26,6 +26,7 @@ def test_transfer_archives_calls_borg_with_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -63,6 +64,7 @@ def test_transfer_archives_with_dry_run_calls_borg_with_dry_run_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=True,
|
||||
@@ -98,6 +100,7 @@ def test_transfer_archives_with_log_info_calls_borg_with_info_flag():
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
repository_path='repo',
|
||||
@@ -170,6 +173,7 @@ def test_transfer_archives_with_archive_calls_borg_with_match_archives_flag():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -208,6 +212,7 @@ def test_transfer_archives_with_match_archives_calls_borg_with_match_archives_fl
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -246,6 +251,7 @@ def test_transfer_archives_with_archive_name_format_calls_borg_with_match_archiv
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -280,6 +286,7 @@ def test_transfer_archives_with_local_path_calls_borg_via_local_path():
|
||||
borg_local_path='borg2',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -316,6 +323,7 @@ def test_transfer_archives_with_exit_codes_calls_borg_using_them():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -354,6 +362,7 @@ def test_transfer_archives_with_remote_path_calls_borg_with_remote_path_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -391,6 +400,7 @@ def test_transfer_archives_with_umask_calls_borg_with_umask_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -429,6 +439,7 @@ def test_transfer_archives_with_lock_wait_calls_borg_with_lock_wait_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -464,6 +475,7 @@ def test_transfer_archives_calls_borg_with_extra_borg_options():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -501,6 +513,7 @@ def test_transfer_archives_with_progress_calls_borg_with_progress_flags():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -538,6 +551,7 @@ def test_transfer_archives_with_log_json_and_progress_calls_borg_with_both_flags
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -576,6 +590,7 @@ def test_transfer_archives_passes_through_arguments_to_borg(argument_name):
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -613,6 +628,7 @@ def test_transfer_archives_with_source_repository_calls_borg_with_other_repo_fla
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -662,6 +678,7 @@ def test_transfer_archives_with_date_based_matching_calls_borg_with_date_based_f
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
@@ -701,6 +718,7 @@ def test_transfer_archives_calls_borg_with_working_directory():
|
||||
borg_local_path='borg',
|
||||
borg_exit_codes=None,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.transfer_archives(
|
||||
dry_run=False,
|
||||
|
||||
@@ -26,6 +26,7 @@ def insert_execute_command_mock(
|
||||
|
||||
def test_unmount_archive_calls_borg_with_required_parameters():
|
||||
insert_execute_command_mock(('borg', 'umount', '--log-json', '/mnt'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.unmount_archive(config={}, mount_point='/mnt')
|
||||
|
||||
@@ -49,6 +50,7 @@ def test_unmount_archive_calls_borg_with_extra_borg_options():
|
||||
('borg', 'umount', '--log-json', '--extra', 'value with space', '/mnt'),
|
||||
borg_local_path='borg',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.unmount_archive(
|
||||
config={'extra_borg_options': {'umount': '--extra "value with space"'}}, mount_point='/mnt'
|
||||
@@ -57,6 +59,7 @@ def test_unmount_archive_calls_borg_with_extra_borg_options():
|
||||
|
||||
def test_unmount_archive_calls_borg_with_local_path():
|
||||
insert_execute_command_mock(('borg1', 'umount', '--log-json', '/mnt'), borg_local_path='borg1')
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.unmount_archive(config={}, mount_point='/mnt', local_path='borg1')
|
||||
|
||||
@@ -66,6 +69,7 @@ def test_unmount_archive_calls_borg_with_exit_codes():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'umount', '--log-json', '/mnt'), borg_exit_codes=borg_exit_codes
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.unmount_archive(config={'borg_exit_codes': borg_exit_codes}, mount_point='/mnt')
|
||||
|
||||
@@ -74,5 +78,6 @@ def test_unmount_archive_calls_borg_with_working_directory():
|
||||
insert_execute_command_mock(
|
||||
('borg', 'umount', '--log-json', '/mnt'), working_directory='/working/dir'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
|
||||
module.unmount_archive(config={'working_directory': '/working/dir'}, mount_point='/mnt')
|
||||
|
||||
@@ -32,6 +32,7 @@ def insert_execute_command_and_capture_output_mock(
|
||||
|
||||
def test_local_borg_version_calls_borg_with_required_parameters():
|
||||
insert_execute_command_and_capture_output_mock(('borg', '--version', '--log-json'))
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
|
||||
assert module.local_borg_version({}) == VERSION
|
||||
@@ -59,6 +60,7 @@ def test_local_borg_version_with_local_borg_path_calls_borg_with_it():
|
||||
insert_execute_command_and_capture_output_mock(
|
||||
('borg1', '--version', '--log-json'), borg_local_path='borg1'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
|
||||
assert module.local_borg_version({}, 'borg1') == VERSION
|
||||
@@ -70,6 +72,7 @@ def test_local_borg_version_with_borg_exit_codes_calls_using_with_them():
|
||||
('borg', '--version', '--log-json'),
|
||||
borg_exit_codes=borg_exit_codes,
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
|
||||
assert module.local_borg_version({'borg_exit_codes': borg_exit_codes}) == VERSION
|
||||
@@ -79,6 +82,7 @@ def test_local_borg_version_with_invalid_version_raises():
|
||||
insert_execute_command_and_capture_output_mock(
|
||||
('borg', '--version', '--log-json'), version_output='wtf'
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
@@ -90,6 +94,7 @@ def test_local_borg_version_calls_borg_with_working_directory():
|
||||
('borg', '--version', '--log-json'),
|
||||
working_directory='/working/dir',
|
||||
)
|
||||
insert_logging_mock(logging.WARNING)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
|
||||
assert module.local_borg_version({'working_directory': '/working/dir'}) == VERSION
|
||||
|
||||
@@ -2095,6 +2095,43 @@ 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(
|
||||
|
||||
@@ -66,7 +66,9 @@ def test_initialize_monitor_without_send_logs_does_not_add_handler():
|
||||
|
||||
|
||||
def test_ping_monitor_respects_dry_run():
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive('get_handler')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda url, config: url)
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive(
|
||||
'format_buffered_logs_for_payload',
|
||||
).and_return('loggy log')
|
||||
@@ -83,7 +85,9 @@ def test_ping_monitor_respects_dry_run():
|
||||
|
||||
|
||||
def test_ping_monitor_with_no_states_does_not_notify():
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive('get_handler').never()
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda url, config: url)
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive(
|
||||
'format_buffered_logs_for_payload',
|
||||
).never()
|
||||
@@ -100,7 +104,9 @@ def test_ping_monitor_with_no_states_does_not_notify():
|
||||
|
||||
|
||||
def test_ping_monitor_notifies_fail_by_default():
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive('get_handler')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda url, config: url)
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive(
|
||||
'format_buffered_logs_for_payload',
|
||||
).and_return('')
|
||||
@@ -123,7 +129,9 @@ def test_ping_monitor_notifies_fail_by_default():
|
||||
|
||||
|
||||
def test_ping_monitor_with_logs_appends_logs_to_body():
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive('get_handler')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda url, config: url)
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive(
|
||||
'format_buffered_logs_for_payload',
|
||||
).and_return('loggy log')
|
||||
@@ -146,7 +154,9 @@ def test_ping_monitor_with_logs_appends_logs_to_body():
|
||||
|
||||
|
||||
def test_ping_monitor_with_finish_default_config_notifies():
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive('get_handler')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda url, config: url)
|
||||
flexmock(module.borgmatic.hooks.monitoring.logs).should_receive(
|
||||
'format_buffered_logs_for_payload',
|
||||
).and_return('')
|
||||
|
||||
@@ -779,6 +779,7 @@ def test_raise_for_process_errors_with_no_processes_bails():
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas={},
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -795,6 +796,7 @@ def test_raise_for_process_errors_with_running_process_bails():
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -812,6 +814,7 @@ def test_raise_for_process_errors_with_running_process_and_no_buffer_readers_wai
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers={},
|
||||
process_metadatas=process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -829,6 +832,7 @@ def test_raise_for_process_errors_with_successful_process_bails():
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -846,6 +850,7 @@ def test_raise_for_process_errors_with_warning_process_returns_warning_status():
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -860,6 +865,7 @@ def test_raise_for_process_errors_with_error_process_raises():
|
||||
process: module.Process_metadata(last_lines=['hi', 'there'], capture=False)
|
||||
}
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(module.Exit_status.ERROR)
|
||||
flexmock(module).should_receive('log_remaining_buffer_lines').and_return(())
|
||||
command = flexmock()
|
||||
flexmock(module).should_receive('command_for_process').and_return(command)
|
||||
|
||||
@@ -867,6 +873,7 @@ def test_raise_for_process_errors_with_error_process_raises():
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -890,12 +897,14 @@ def test_raise_for_process_errors_with_success_process_and_warning_process_retur
|
||||
flexmock(module).should_receive('interpret_exit_code').with_args(
|
||||
object, 1, object, object
|
||||
).and_return(module.Exit_status.WARNING)
|
||||
flexmock(module).should_receive('log_remaining_buffer_lines').and_return(())
|
||||
flexmock(module).should_receive('command_for_process').never()
|
||||
|
||||
assert (
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -917,6 +926,7 @@ def test_raise_for_process_errors_with_warning_process_and_error_process_raises(
|
||||
flexmock(module).should_receive('interpret_exit_code').with_args(
|
||||
object, 3, object, object
|
||||
).and_return(module.Exit_status.ERROR)
|
||||
flexmock(module).should_receive('log_remaining_buffer_lines').and_return(())
|
||||
command = flexmock()
|
||||
flexmock(module).should_receive('command_for_process').and_return(command)
|
||||
|
||||
@@ -924,6 +934,7 @@ def test_raise_for_process_errors_with_warning_process_and_error_process_raises(
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -947,6 +958,7 @@ def test_raise_for_process_errors_with_warning_process_and_running_process_kills
|
||||
flexmock(module).should_receive('interpret_exit_code').with_args(
|
||||
object, 1, object, object
|
||||
).and_return(module.Exit_status.WARNING)
|
||||
flexmock(module).should_receive('log_remaining_buffer_lines').and_return(())
|
||||
command = flexmock()
|
||||
flexmock(module).should_receive('command_for_process').and_return(command)
|
||||
|
||||
@@ -954,6 +966,7 @@ def test_raise_for_process_errors_with_warning_process_and_running_process_kills
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -975,6 +988,7 @@ def test_raise_for_process_errors_with_error_process_and_running_process_kills_a
|
||||
flexmock(module).should_receive('interpret_exit_code').with_args(
|
||||
object, 3, object, object
|
||||
).and_return(module.Exit_status.ERROR)
|
||||
flexmock(module).should_receive('log_remaining_buffer_lines').and_return(())
|
||||
command = flexmock()
|
||||
flexmock(module).should_receive('command_for_process').and_return(command)
|
||||
|
||||
@@ -982,6 +996,7 @@ def test_raise_for_process_errors_with_error_process_and_running_process_kills_a
|
||||
module.raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
@@ -998,6 +1013,7 @@ def test_raise_for_process_errors_with_warning_process_and_long_output_raises_wi
|
||||
process: module.Process_metadata(last_lines=['hi', 'there'], capture=False)
|
||||
}
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(module.Exit_status.ERROR)
|
||||
flexmock(module).should_receive('log_remaining_buffer_lines').and_return(())
|
||||
command = flexmock()
|
||||
flexmock(module).should_receive('command_for_process').and_return(command)
|
||||
|
||||
@@ -1005,6 +1021,7 @@ def test_raise_for_process_errors_with_warning_process_and_long_output_raises_wi
|
||||
flexmock(module, ERROR_OUTPUT_MAX_LINE_COUNT=2).raise_for_process_errors(
|
||||
buffer_readers,
|
||||
process_metadatas,
|
||||
output_log_level=None,
|
||||
borg_local_path=flexmock(),
|
||||
borg_exit_codes=flexmock(),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user