mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-08-07 00:23:20 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f79286fc91 | ||
|
|
694d376d15 | ||
|
|
ab4c08019c | ||
|
|
fd39f54df7 | ||
|
|
ca7e18bb29 | ||
|
|
6975a5b155 | ||
|
|
b627d00595 | ||
|
|
9bd8f1a6df | ||
|
|
faf682ca35 | ||
|
|
6aeb74550d | ||
|
|
89500df429 | ||
|
|
82b072d0b7 | ||
|
|
018c0296fd | ||
|
|
9c42e7e817 | ||
|
|
953277a066 | ||
|
|
e2002b5488 | ||
|
|
c9742e1d04 | ||
|
|
906da838ef | ||
|
|
d7f1c10c8c | ||
|
|
e8e4d17168 | ||
|
|
a31ce337e9 | ||
|
|
902730df46 | ||
|
|
c969c822ee | ||
|
|
c31702d092 | ||
|
|
ba8fbe7a44 | ||
|
|
2774c2e4c0 | ||
|
|
ae036aebd7 | ||
|
|
2e9f70d496 | ||
|
|
90be5b84b1 | ||
|
|
80e95f20a3 | ||
|
|
ac7c7d4036 | ||
|
|
858b0b9fbe | ||
|
|
9cc043f60e |
@@ -1,3 +1,39 @@
|
|||||||
|
1.7.5
|
||||||
|
* #311: Override PostgreSQL dump/restore commands via configuration options.
|
||||||
|
* #604: Fix traceback when a configuration section is present but lacking any options.
|
||||||
|
* #607: Clarify documentation examples for include merging and deep merging.
|
||||||
|
* #611: Fix "data" consistency check to support "check_last" and consistency "prefix" options.
|
||||||
|
* #613: Clarify documentation about multiple repositories and separate configuration files.
|
||||||
|
|
||||||
|
1.7.4
|
||||||
|
* #596: Fix special file detection erroring when broken symlinks are encountered.
|
||||||
|
* #597, #598: Fix regression in which "check" action errored on certain systems ("Cannot determine
|
||||||
|
Borg repository ID").
|
||||||
|
|
||||||
|
1.7.3
|
||||||
|
* #357: Add "break-lock" action for removing any repository and cache locks leftover from Borg
|
||||||
|
aborting.
|
||||||
|
* #360: To prevent Borg hangs, unconditionally delete stale named pipes before dumping databases.
|
||||||
|
* #587: When database hooks are enabled, auto-exclude special files from a "create" action to
|
||||||
|
prevent Borg from hanging. You can override/prevent this behavior by explicitly setting the
|
||||||
|
"read_special" option to true.
|
||||||
|
* #587: Warn when ignoring a configured "read_special" value of false, as true is needed when
|
||||||
|
database hooks are enabled.
|
||||||
|
* #589: Update sample systemd service file to allow system "idle" (e.g. a video monitor turning
|
||||||
|
off) while borgmatic is running.
|
||||||
|
* #590: Fix for potential data loss (data not getting backed up) when the "patterns_from" option
|
||||||
|
was used with "source_directories" (or the "~/.borgmatic" path existed, which got injected into
|
||||||
|
"source_directories" implicitly). The fix is for borgmatic to convert "source_directories" into
|
||||||
|
patterns whenever "patterns_from" is used, working around a Borg bug:
|
||||||
|
https://github.com/borgbackup/borg/issues/6994
|
||||||
|
* #590: In "borgmatic create --list" output, display which files get excluded from the backup due
|
||||||
|
to patterns or excludes.
|
||||||
|
* #591: Add support for Borg 2's "--match-archives" flag. This replaces "--glob-archives", which
|
||||||
|
borgmatic now treats as an alias for "--match-archives". But note that the two flags have
|
||||||
|
slightly different syntax. See the Borg 2 changelog for more information:
|
||||||
|
https://borgbackup.readthedocs.io/en/2.0.0b3/changes.html#version-2-0-0b3-2022-10-02
|
||||||
|
* Fix for "borgmatic --archive latest" not finding the latest archive when a verbosity is set.
|
||||||
|
|
||||||
1.7.2
|
1.7.2
|
||||||
* #577: Fix regression in which "borgmatic info --archive ..." showed repository info instead of
|
* #577: Fix regression in which "borgmatic info --archive ..." showed repository info instead of
|
||||||
archive info with Borg 1.
|
archive info with Borg 1.
|
||||||
@@ -10,7 +46,7 @@
|
|||||||
* #574: Fix for potential data loss (data not getting backed up) when the "patterns" option was
|
* #574: Fix for potential data loss (data not getting backed up) when the "patterns" option was
|
||||||
used with "source_directories" (or the "~/.borgmatic" path existed, which got injected into
|
used with "source_directories" (or the "~/.borgmatic" path existed, which got injected into
|
||||||
"source_directories" implicitly). The fix is for borgmatic to convert "source_directories" into
|
"source_directories" implicitly). The fix is for borgmatic to convert "source_directories" into
|
||||||
patterns whenever "patterns" is used, working around a potential Borg bug:
|
patterns whenever "patterns" is used, working around a Borg bug:
|
||||||
https://github.com/borgbackup/borg/issues/6994
|
https://github.com/borgbackup/borg/issues/6994
|
||||||
|
|
||||||
1.7.0
|
1.7.0
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from borgmatic.borg import environment, flags
|
||||||
|
from borgmatic.execute import execute_command
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def break_lock(
|
||||||
|
repository, storage_config, local_borg_version, local_path='borg', remote_path=None,
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Given a local or remote repository path, a storage configuration dict, the local Borg version,
|
||||||
|
and optional local and remote Borg paths, break any repository and cache locks leftover from Borg
|
||||||
|
aborting.
|
||||||
|
'''
|
||||||
|
umask = storage_config.get('umask', None)
|
||||||
|
lock_wait = storage_config.get('lock_wait', None)
|
||||||
|
|
||||||
|
full_command = (
|
||||||
|
(local_path, 'break-lock')
|
||||||
|
+ (('--remote-path', remote_path) if remote_path else ())
|
||||||
|
+ (('--umask', str(umask)) if umask else ())
|
||||||
|
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
||||||
|
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
|
||||||
|
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
|
||||||
|
+ flags.make_repository_flags(repository, local_borg_version)
|
||||||
|
)
|
||||||
|
|
||||||
|
borg_environment = environment.make_environment(storage_config)
|
||||||
|
execute_command(full_command, borg_local_path=local_path, extra_environment=borg_environment)
|
||||||
+25
-19
@@ -5,7 +5,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
from borgmatic.borg import environment, extract, flags, rinfo, state
|
from borgmatic.borg import environment, extract, feature, flags, rinfo, state
|
||||||
from borgmatic.execute import DO_NOT_CAPTURE, execute_command
|
from borgmatic.execute import DO_NOT_CAPTURE, execute_command
|
||||||
|
|
||||||
DEFAULT_CHECKS = (
|
DEFAULT_CHECKS = (
|
||||||
@@ -146,9 +146,10 @@ def filter_checks_on_frequency(
|
|||||||
return tuple(filtered_checks)
|
return tuple(filtered_checks)
|
||||||
|
|
||||||
|
|
||||||
def make_check_flags(checks, check_last=None, prefix=None):
|
def make_check_flags(local_borg_version, checks, check_last=None, prefix=None):
|
||||||
'''
|
'''
|
||||||
Given a parsed sequence of checks, transform it into tuple of command-line flags.
|
Given the local Borg version and a parsed sequence of checks, transform the checks into tuple of
|
||||||
|
command-line flags.
|
||||||
|
|
||||||
For example, given parsed checks of:
|
For example, given parsed checks of:
|
||||||
|
|
||||||
@@ -163,28 +164,33 @@ def make_check_flags(checks, check_last=None, prefix=None):
|
|||||||
|
|
||||||
Additionally, if a check_last value is given and "archives" is in checks, then include a
|
Additionally, if a check_last value is given and "archives" is in checks, then include a
|
||||||
"--last" flag. And if a prefix value is given and "archives" is in checks, then include a
|
"--last" flag. And if a prefix value is given and "archives" is in checks, then include a
|
||||||
"--glob-archives" flag.
|
"--match-archives" flag.
|
||||||
'''
|
'''
|
||||||
if 'archives' in checks:
|
|
||||||
last_flags = ('--last', str(check_last)) if check_last else ()
|
|
||||||
glob_archives_flags = ('--glob-archives', f'{prefix}*') if prefix else ()
|
|
||||||
else:
|
|
||||||
last_flags = ()
|
|
||||||
glob_archives_flags = ()
|
|
||||||
if check_last:
|
|
||||||
logger.info('Ignoring check_last option, as "archives" is not in consistency checks')
|
|
||||||
if prefix:
|
|
||||||
logger.info(
|
|
||||||
'Ignoring consistency prefix option, as "archives" is not in consistency checks'
|
|
||||||
)
|
|
||||||
|
|
||||||
if 'data' in checks:
|
if 'data' in checks:
|
||||||
data_flags = ('--verify-data',)
|
data_flags = ('--verify-data',)
|
||||||
checks += ('archives',)
|
checks += ('archives',)
|
||||||
else:
|
else:
|
||||||
data_flags = ()
|
data_flags = ()
|
||||||
|
|
||||||
common_flags = last_flags + glob_archives_flags + data_flags
|
if 'archives' in checks:
|
||||||
|
last_flags = ('--last', str(check_last)) if check_last else ()
|
||||||
|
if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version):
|
||||||
|
match_archives_flags = ('--match-archives', f'sh:{prefix}*') if prefix else ()
|
||||||
|
else:
|
||||||
|
match_archives_flags = ('--glob-archives', f'{prefix}*') if prefix else ()
|
||||||
|
else:
|
||||||
|
last_flags = ()
|
||||||
|
match_archives_flags = ()
|
||||||
|
if check_last:
|
||||||
|
logger.warning(
|
||||||
|
'Ignoring check_last option, as "archives" or "data" are not in consistency checks'
|
||||||
|
)
|
||||||
|
if prefix:
|
||||||
|
logger.warning(
|
||||||
|
'Ignoring consistency prefix option, as "archives" or "data" are not in consistency checks'
|
||||||
|
)
|
||||||
|
|
||||||
|
common_flags = last_flags + match_archives_flags + data_flags
|
||||||
|
|
||||||
if {'repository', 'archives'}.issubset(set(checks)):
|
if {'repository', 'archives'}.issubset(set(checks)):
|
||||||
return common_flags
|
return common_flags
|
||||||
@@ -298,7 +304,7 @@ def check_archives(
|
|||||||
full_command = (
|
full_command = (
|
||||||
(local_path, 'check')
|
(local_path, 'check')
|
||||||
+ (('--repair',) if repair else ())
|
+ (('--repair',) if repair else ())
|
||||||
+ make_check_flags(checks, check_last, prefix)
|
+ make_check_flags(local_borg_version, checks, check_last, prefix)
|
||||||
+ (('--remote-path', remote_path) if remote_path else ())
|
+ (('--remote-path', remote_path) if remote_path else ())
|
||||||
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
||||||
+ verbosity_flags
|
+ verbosity_flags
|
||||||
|
|||||||
+138
-28
@@ -3,10 +3,16 @@ import itertools
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import stat
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from borgmatic.borg import environment, feature, flags, state
|
from borgmatic.borg import environment, feature, flags, state
|
||||||
from borgmatic.execute import DO_NOT_CAPTURE, execute_command, execute_command_with_processes
|
from borgmatic.execute import (
|
||||||
|
DO_NOT_CAPTURE,
|
||||||
|
execute_command,
|
||||||
|
execute_command_and_capture_output,
|
||||||
|
execute_command_with_processes,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -104,18 +110,23 @@ def deduplicate_directories(directory_devices, additional_directory_devices):
|
|||||||
return tuple(sorted(deduplicated))
|
return tuple(sorted(deduplicated))
|
||||||
|
|
||||||
|
|
||||||
def write_pattern_file(patterns=None, sources=None):
|
def write_pattern_file(patterns=None, sources=None, pattern_file=None):
|
||||||
'''
|
'''
|
||||||
Given a sequence of patterns and an optional sequence of source directories, write them to a
|
Given a sequence of patterns and an optional sequence of source directories, write them to a
|
||||||
named temporary file (with the source directories as additional roots) and return the file.
|
named temporary file (with the source directories as additional roots) and return the file.
|
||||||
|
If an optional open pattern file is given, overwrite it instead of making a new temporary file.
|
||||||
Return None if no patterns are provided.
|
Return None if no patterns are provided.
|
||||||
'''
|
'''
|
||||||
if not patterns:
|
if not patterns and not sources:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
pattern_file = tempfile.NamedTemporaryFile('w')
|
if pattern_file is None:
|
||||||
|
pattern_file = tempfile.NamedTemporaryFile('w')
|
||||||
|
else:
|
||||||
|
pattern_file.seek(0)
|
||||||
|
|
||||||
pattern_file.write(
|
pattern_file.write(
|
||||||
'\n'.join(tuple(patterns) + tuple(f'R {source}' for source in (sources or [])))
|
'\n'.join(tuple(patterns or ()) + tuple(f'R {source}' for source in (sources or [])))
|
||||||
)
|
)
|
||||||
pattern_file.flush()
|
pattern_file.flush()
|
||||||
|
|
||||||
@@ -187,7 +198,7 @@ def make_exclude_flags(location_config, exclude_filename=None):
|
|||||||
DEFAULT_ARCHIVE_NAME_FORMAT = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
|
DEFAULT_ARCHIVE_NAME_FORMAT = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
|
||||||
|
|
||||||
|
|
||||||
def borgmatic_source_directories(borgmatic_source_directory):
|
def collect_borgmatic_source_directories(borgmatic_source_directory):
|
||||||
'''
|
'''
|
||||||
Return a list of borgmatic-specific source directories used for state like database backups.
|
Return a list of borgmatic-specific source directories used for state like database backups.
|
||||||
'''
|
'''
|
||||||
@@ -218,6 +229,61 @@ def pattern_root_directories(patterns=None):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def special_file(path):
|
||||||
|
'''
|
||||||
|
Return whether the given path is a special file (character device, block device, or named pipe
|
||||||
|
/ FIFO).
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
mode = os.stat(path).st_mode
|
||||||
|
except (FileNotFoundError, OSError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return stat.S_ISCHR(mode) or stat.S_ISBLK(mode) or stat.S_ISFIFO(mode)
|
||||||
|
|
||||||
|
|
||||||
|
def any_parent_directories(path, candidate_parents):
|
||||||
|
'''
|
||||||
|
Return whether any of the given candidate parent directories are an actual parent of the given
|
||||||
|
path. This includes grandparents, etc.
|
||||||
|
'''
|
||||||
|
for parent in candidate_parents:
|
||||||
|
if pathlib.PurePosixPath(parent) in pathlib.PurePath(path).parents:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def collect_special_file_paths(
|
||||||
|
create_command, local_path, working_directory, borg_environment, skip_directories
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Given a Borg create command as a tuple, a local Borg path, a working directory, and a dict of
|
||||||
|
environment variables to pass to Borg, and a sequence of parent directories to skip, collect the
|
||||||
|
paths for any special files (character devices, block devices, and named pipes / FIFOs) that
|
||||||
|
Borg would encounter during a create. These are all paths that could cause Borg to hang if its
|
||||||
|
--read-special flag is used.
|
||||||
|
'''
|
||||||
|
paths_output = execute_command_and_capture_output(
|
||||||
|
create_command + ('--dry-run', '--list'),
|
||||||
|
capture_stderr=True,
|
||||||
|
working_directory=working_directory,
|
||||||
|
extra_environment=borg_environment,
|
||||||
|
)
|
||||||
|
|
||||||
|
paths = tuple(
|
||||||
|
path_line.split(' ', 1)[1]
|
||||||
|
for path_line in paths_output.split('\n')
|
||||||
|
if path_line and path_line.startswith('- ')
|
||||||
|
)
|
||||||
|
|
||||||
|
return tuple(
|
||||||
|
path
|
||||||
|
for path in paths
|
||||||
|
if special_file(path) and not any_parent_directories(path, skip_directories)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_archive(
|
def create_archive(
|
||||||
dry_run,
|
dry_run,
|
||||||
repository,
|
repository,
|
||||||
@@ -239,11 +305,13 @@ def create_archive(
|
|||||||
If a sequence of stream processes is given (instances of subprocess.Popen), then execute the
|
If a sequence of stream processes is given (instances of subprocess.Popen), then execute the
|
||||||
create command while also triggering the given processes to produce output.
|
create command while also triggering the given processes to produce output.
|
||||||
'''
|
'''
|
||||||
|
borgmatic_source_directories = expand_directories(
|
||||||
|
collect_borgmatic_source_directories(location_config.get('borgmatic_source_directory'))
|
||||||
|
)
|
||||||
sources = deduplicate_directories(
|
sources = deduplicate_directories(
|
||||||
map_directories_to_devices(
|
map_directories_to_devices(
|
||||||
expand_directories(
|
expand_directories(
|
||||||
location_config.get('source_directories', [])
|
tuple(location_config.get('source_directories', ())) + borgmatic_source_directories
|
||||||
+ borgmatic_source_directories(location_config.get('borgmatic_source_directory'))
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
additional_directory_devices=map_directories_to_devices(
|
additional_directory_devices=map_directories_to_devices(
|
||||||
@@ -251,11 +319,18 @@ def create_archive(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ensure_files_readable(location_config.get('patterns_from'), location_config.get('exclude_from'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
working_directory = os.path.expanduser(location_config.get('working_directory'))
|
working_directory = os.path.expanduser(location_config.get('working_directory'))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
working_directory = None
|
working_directory = None
|
||||||
pattern_file = write_pattern_file(location_config.get('patterns'), sources)
|
|
||||||
|
pattern_file = (
|
||||||
|
write_pattern_file(location_config.get('patterns'), sources)
|
||||||
|
if location_config.get('patterns') or location_config.get('patterns_from')
|
||||||
|
else None
|
||||||
|
)
|
||||||
exclude_file = write_pattern_file(
|
exclude_file = write_pattern_file(
|
||||||
expand_home_directories(location_config.get('exclude_patterns'))
|
expand_home_directories(location_config.get('exclude_patterns'))
|
||||||
)
|
)
|
||||||
@@ -293,9 +368,12 @@ def create_archive(
|
|||||||
('--remote-ratelimit', str(upload_rate_limit)) if upload_rate_limit else ()
|
('--remote-ratelimit', str(upload_rate_limit)) if upload_rate_limit else ()
|
||||||
)
|
)
|
||||||
|
|
||||||
ensure_files_readable(location_config.get('patterns_from'), location_config.get('exclude_from'))
|
if stream_processes and location_config.get('read_special') is False:
|
||||||
|
logger.warning(
|
||||||
|
f'{repository}: Ignoring configured "read_special" value of false, as true is needed for database hooks.'
|
||||||
|
)
|
||||||
|
|
||||||
full_command = (
|
create_command = (
|
||||||
tuple(local_path.split(' '))
|
tuple(local_path.split(' '))
|
||||||
+ ('create',)
|
+ ('create',)
|
||||||
+ make_pattern_flags(location_config, pattern_file.name if pattern_file else None)
|
+ make_pattern_flags(location_config, pattern_file.name if pattern_file else None)
|
||||||
@@ -313,19 +391,14 @@ def create_archive(
|
|||||||
+ atime_flags
|
+ atime_flags
|
||||||
+ (('--noctime',) if location_config.get('ctime') is False else ())
|
+ (('--noctime',) if location_config.get('ctime') is False else ())
|
||||||
+ (('--nobirthtime',) if location_config.get('birthtime') is False else ())
|
+ (('--nobirthtime',) if location_config.get('birthtime') is False else ())
|
||||||
+ (('--read-special',) if (location_config.get('read_special') or stream_processes) else ())
|
+ (('--read-special',) if location_config.get('read_special') or stream_processes else ())
|
||||||
+ noflags_flags
|
+ noflags_flags
|
||||||
+ (('--files-cache', files_cache) if files_cache else ())
|
+ (('--files-cache', files_cache) if files_cache else ())
|
||||||
+ (('--remote-path', remote_path) if remote_path else ())
|
+ (('--remote-path', remote_path) if remote_path else ())
|
||||||
+ (('--umask', str(umask)) if umask else ())
|
+ (('--umask', str(umask)) if umask else ())
|
||||||
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
||||||
+ (('--list', '--filter', 'AME-') if list_files and not json and not progress else ())
|
+ (('--list', '--filter', 'AMEx-') if list_files and not json and not progress else ())
|
||||||
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO and not json else ())
|
|
||||||
+ (('--stats',) if stats and not json and not dry_run else ())
|
|
||||||
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) and not json else ())
|
|
||||||
+ (('--dry-run',) if dry_run else ())
|
+ (('--dry-run',) if dry_run else ())
|
||||||
+ (('--progress',) if progress else ())
|
|
||||||
+ (('--json',) if json else ())
|
|
||||||
+ (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
|
+ (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
|
||||||
+ flags.make_repository_archive_flags(repository, archive_name_format, local_borg_version)
|
+ flags.make_repository_archive_flags(repository, archive_name_format, local_borg_version)
|
||||||
+ (sources if not pattern_file else ())
|
+ (sources if not pattern_file else ())
|
||||||
@@ -344,9 +417,42 @@ def create_archive(
|
|||||||
|
|
||||||
borg_environment = environment.make_environment(storage_config)
|
borg_environment = environment.make_environment(storage_config)
|
||||||
|
|
||||||
|
# If database hooks are enabled (as indicated by streaming processes), exclude files that might
|
||||||
|
# cause Borg to hang. But skip this if the user has explicitly set the "read_special" to True.
|
||||||
|
if stream_processes and not location_config.get('read_special'):
|
||||||
|
logger.debug(f'{repository}: Collecting special file paths')
|
||||||
|
special_file_paths = collect_special_file_paths(
|
||||||
|
create_command,
|
||||||
|
local_path,
|
||||||
|
working_directory,
|
||||||
|
borg_environment,
|
||||||
|
skip_directories=borgmatic_source_directories,
|
||||||
|
)
|
||||||
|
logger.warning(
|
||||||
|
f'{repository}: Excluding special files to prevent Borg from hanging: {", ".join(special_file_paths)}'
|
||||||
|
)
|
||||||
|
|
||||||
|
exclude_file = write_pattern_file(
|
||||||
|
expand_home_directories(
|
||||||
|
tuple(location_config.get('exclude_patterns') or ()) + special_file_paths
|
||||||
|
),
|
||||||
|
pattern_file=exclude_file,
|
||||||
|
)
|
||||||
|
|
||||||
|
if exclude_file:
|
||||||
|
create_command += make_exclude_flags(location_config, exclude_file.name)
|
||||||
|
|
||||||
|
create_command += (
|
||||||
|
(('--info',) if logger.getEffectiveLevel() == logging.INFO and not json else ())
|
||||||
|
+ (('--stats',) if stats and not json and not dry_run else ())
|
||||||
|
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) and not json else ())
|
||||||
|
+ (('--progress',) if progress else ())
|
||||||
|
+ (('--json',) if json else ())
|
||||||
|
)
|
||||||
|
|
||||||
if stream_processes:
|
if stream_processes:
|
||||||
return execute_command_with_processes(
|
return execute_command_with_processes(
|
||||||
full_command,
|
create_command,
|
||||||
stream_processes,
|
stream_processes,
|
||||||
output_log_level,
|
output_log_level,
|
||||||
output_file,
|
output_file,
|
||||||
@@ -354,12 +460,16 @@ def create_archive(
|
|||||||
working_directory=working_directory,
|
working_directory=working_directory,
|
||||||
extra_environment=borg_environment,
|
extra_environment=borg_environment,
|
||||||
)
|
)
|
||||||
|
elif output_log_level is None:
|
||||||
return execute_command(
|
return execute_command_and_capture_output(
|
||||||
full_command,
|
create_command, working_directory=working_directory, extra_environment=borg_environment,
|
||||||
output_log_level,
|
)
|
||||||
output_file,
|
else:
|
||||||
borg_local_path=local_path,
|
execute_command(
|
||||||
working_directory=working_directory,
|
create_command,
|
||||||
extra_environment=borg_environment,
|
output_log_level,
|
||||||
)
|
output_file,
|
||||||
|
borg_local_path=local_path,
|
||||||
|
working_directory=working_directory,
|
||||||
|
extra_environment=borg_environment,
|
||||||
|
)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class Feature(Enum):
|
|||||||
RCREATE = 7
|
RCREATE = 7
|
||||||
RLIST = 8
|
RLIST = 8
|
||||||
RINFO = 9
|
RINFO = 9
|
||||||
|
MATCH_ARCHIVES = 10
|
||||||
|
|
||||||
|
|
||||||
FEATURE_TO_MINIMUM_BORG_VERSION = {
|
FEATURE_TO_MINIMUM_BORG_VERSION = {
|
||||||
@@ -25,6 +26,7 @@ FEATURE_TO_MINIMUM_BORG_VERSION = {
|
|||||||
Feature.RCREATE: parse_version('2.0.0a2'), # borg rcreate
|
Feature.RCREATE: parse_version('2.0.0a2'), # borg rcreate
|
||||||
Feature.RLIST: parse_version('2.0.0a2'), # borg rlist
|
Feature.RLIST: parse_version('2.0.0a2'), # borg rlist
|
||||||
Feature.RINFO: parse_version('2.0.0a2'), # borg rinfo
|
Feature.RINFO: parse_version('2.0.0a2'), # borg rinfo
|
||||||
|
Feature.MATCH_ARCHIVES: parse_version('2.0.0b3'), # borg --match-archives
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+23
-10
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.borg import environment, flags
|
from borgmatic.borg import environment, feature, flags
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command, execute_command_and_capture_output
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -36,7 +36,11 @@ def display_archives_info(
|
|||||||
+ flags.make_flags('remote-path', remote_path)
|
+ flags.make_flags('remote-path', remote_path)
|
||||||
+ flags.make_flags('lock-wait', lock_wait)
|
+ flags.make_flags('lock-wait', lock_wait)
|
||||||
+ (
|
+ (
|
||||||
flags.make_flags('glob-archives', f'{info_arguments.prefix}*')
|
(
|
||||||
|
flags.make_flags('match-archives', f'sh:{info_arguments.prefix}*')
|
||||||
|
if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version)
|
||||||
|
else flags.make_flags('glob-archives', f'{info_arguments.prefix}*')
|
||||||
|
)
|
||||||
if info_arguments.prefix
|
if info_arguments.prefix
|
||||||
else ()
|
else ()
|
||||||
)
|
)
|
||||||
@@ -44,12 +48,21 @@ def display_archives_info(
|
|||||||
info_arguments, excludes=('repository', 'archive', 'prefix')
|
info_arguments, excludes=('repository', 'archive', 'prefix')
|
||||||
)
|
)
|
||||||
+ flags.make_repository_flags(repository, local_borg_version)
|
+ flags.make_repository_flags(repository, local_borg_version)
|
||||||
+ flags.make_flags('glob-archives', info_arguments.archive)
|
+ (
|
||||||
|
flags.make_flags('match-archives', info_arguments.archive)
|
||||||
|
if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version)
|
||||||
|
else flags.make_flags('glob-archives', info_arguments.archive)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return execute_command(
|
if info_arguments.json:
|
||||||
full_command,
|
return execute_command_and_capture_output(
|
||||||
output_log_level=None if info_arguments.json else logging.WARNING,
|
full_command, extra_environment=environment.make_environment(storage_config),
|
||||||
borg_local_path=local_path,
|
)
|
||||||
extra_environment=environment.make_environment(storage_config),
|
else:
|
||||||
)
|
execute_command(
|
||||||
|
full_command,
|
||||||
|
output_log_level=logging.WARNING,
|
||||||
|
borg_local_path=local_path,
|
||||||
|
extra_environment=environment.make_environment(storage_config),
|
||||||
|
)
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import logging
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from borgmatic.borg import environment, feature, flags, rlist
|
from borgmatic.borg import environment, feature, flags, rlist
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command, execute_command_and_capture_output
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
ARCHIVE_FILTER_FLAGS_MOVED_TO_RLIST = ('prefix', 'glob_archives', 'sort_by', 'first', 'last')
|
ARCHIVE_FILTER_FLAGS_MOVED_TO_RLIST = ('prefix', 'match_archives', 'sort_by', 'first', 'last')
|
||||||
MAKE_FLAGS_EXCLUDES = (
|
MAKE_FLAGS_EXCLUDES = (
|
||||||
'repository',
|
'repository',
|
||||||
'archive',
|
'archive',
|
||||||
@@ -111,7 +111,7 @@ def list_archive(
|
|||||||
format=list_arguments.format,
|
format=list_arguments.format,
|
||||||
json=list_arguments.json,
|
json=list_arguments.json,
|
||||||
prefix=list_arguments.prefix,
|
prefix=list_arguments.prefix,
|
||||||
glob_archives=list_arguments.glob_archives,
|
match_archives=list_arguments.match_archives,
|
||||||
sort_by=list_arguments.sort_by,
|
sort_by=list_arguments.sort_by,
|
||||||
first=list_arguments.first,
|
first=list_arguments.first,
|
||||||
last=list_arguments.last,
|
last=list_arguments.last,
|
||||||
@@ -143,7 +143,7 @@ def list_archive(
|
|||||||
format=None,
|
format=None,
|
||||||
json=None,
|
json=None,
|
||||||
prefix=list_arguments.prefix,
|
prefix=list_arguments.prefix,
|
||||||
glob_archives=list_arguments.glob_archives,
|
match_archives=list_arguments.match_archives,
|
||||||
sort_by=list_arguments.sort_by,
|
sort_by=list_arguments.sort_by,
|
||||||
first=list_arguments.first,
|
first=list_arguments.first,
|
||||||
last=list_arguments.last,
|
last=list_arguments.last,
|
||||||
@@ -151,7 +151,7 @@ def list_archive(
|
|||||||
|
|
||||||
# Ask Borg to list archives. Capture its output for use below.
|
# Ask Borg to list archives. Capture its output for use below.
|
||||||
archive_lines = tuple(
|
archive_lines = tuple(
|
||||||
execute_command(
|
execute_command_and_capture_output(
|
||||||
rlist.make_rlist_command(
|
rlist.make_rlist_command(
|
||||||
repository,
|
repository,
|
||||||
storage_config,
|
storage_config,
|
||||||
@@ -160,8 +160,6 @@ def list_archive(
|
|||||||
local_path,
|
local_path,
|
||||||
remote_path,
|
remote_path,
|
||||||
),
|
),
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path=local_path,
|
|
||||||
extra_environment=borg_environment,
|
extra_environment=borg_environment,
|
||||||
)
|
)
|
||||||
.strip('\n')
|
.strip('\n')
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ def mount_archive(
|
|||||||
+ (
|
+ (
|
||||||
(
|
(
|
||||||
flags.make_repository_flags(repository, local_borg_version)
|
flags.make_repository_flags(repository, local_borg_version)
|
||||||
+ ('--glob-archives', archive)
|
+ (
|
||||||
|
('--match-archives', archive)
|
||||||
|
if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version)
|
||||||
|
else ('--glob-archives', archive)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if feature.available(feature.Feature.SEPARATE_REPOSITORY_ARCHIVE, local_borg_version)
|
if feature.available(feature.Feature.SEPARATE_REPOSITORY_ARCHIVE, local_borg_version)
|
||||||
else (
|
else (
|
||||||
|
|||||||
+12
-4
@@ -1,12 +1,12 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.borg import environment, flags
|
from borgmatic.borg import environment, feature, flags
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def make_prune_flags(retention_config):
|
def make_prune_flags(retention_config, local_borg_version):
|
||||||
'''
|
'''
|
||||||
Given a retention config dict mapping from option name to value, tranform it into an iterable of
|
Given a retention config dict mapping from option name to value, tranform it into an iterable of
|
||||||
command-line name-value flag pairs.
|
command-line name-value flag pairs.
|
||||||
@@ -24,8 +24,12 @@ def make_prune_flags(retention_config):
|
|||||||
'''
|
'''
|
||||||
config = retention_config.copy()
|
config = retention_config.copy()
|
||||||
prefix = config.pop('prefix', '{hostname}-')
|
prefix = config.pop('prefix', '{hostname}-')
|
||||||
|
|
||||||
if prefix:
|
if prefix:
|
||||||
config['glob_archives'] = f'{prefix}*'
|
if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version):
|
||||||
|
config['match_archives'] = f'sh:{prefix}*'
|
||||||
|
else:
|
||||||
|
config['glob_archives'] = f'{prefix}*'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
('--' + option_name.replace('_', '-'), str(value)) for option_name, value in config.items()
|
('--' + option_name.replace('_', '-'), str(value)) for option_name, value in config.items()
|
||||||
@@ -54,7 +58,11 @@ def prune_archives(
|
|||||||
|
|
||||||
full_command = (
|
full_command = (
|
||||||
(local_path, 'prune')
|
(local_path, 'prune')
|
||||||
+ tuple(element for pair in make_prune_flags(retention_config) for element in pair)
|
+ tuple(
|
||||||
|
element
|
||||||
|
for pair in make_prune_flags(retention_config, local_borg_version)
|
||||||
|
for element in pair
|
||||||
|
)
|
||||||
+ (('--remote-path', remote_path) if remote_path else ())
|
+ (('--remote-path', remote_path) if remote_path else ())
|
||||||
+ (('--umask', str(umask)) if umask else ())
|
+ (('--umask', str(umask)) if umask else ())
|
||||||
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
|
||||||
|
|||||||
+14
-7
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.borg import environment, feature, flags
|
from borgmatic.borg import environment, feature, flags
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command, execute_command_and_capture_output
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -44,9 +44,16 @@ def display_repository_info(
|
|||||||
+ flags.make_repository_flags(repository, local_borg_version)
|
+ flags.make_repository_flags(repository, local_borg_version)
|
||||||
)
|
)
|
||||||
|
|
||||||
return execute_command(
|
extra_environment = environment.make_environment(storage_config)
|
||||||
full_command,
|
|
||||||
output_log_level=None if rinfo_arguments.json else logging.WARNING,
|
if rinfo_arguments.json:
|
||||||
borg_local_path=local_path,
|
return execute_command_and_capture_output(
|
||||||
extra_environment=environment.make_environment(storage_config),
|
full_command, extra_environment=extra_environment,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
execute_command(
|
||||||
|
full_command,
|
||||||
|
output_log_level=logging.WARNING,
|
||||||
|
borg_local_path=local_path,
|
||||||
|
extra_environment=extra_environment,
|
||||||
|
)
|
||||||
|
|||||||
+16
-17
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.borg import environment, feature, flags
|
from borgmatic.borg import environment, feature, flags
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command, execute_command_and_capture_output
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -26,8 +26,6 @@ def resolve_archive_name(
|
|||||||
local_path,
|
local_path,
|
||||||
'rlist' if feature.available(feature.Feature.RLIST, local_borg_version) else 'list',
|
'rlist' if feature.available(feature.Feature.RLIST, local_borg_version) else 'list',
|
||||||
)
|
)
|
||||||
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
|
|
||||||
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
|
|
||||||
+ flags.make_flags('remote-path', remote_path)
|
+ flags.make_flags('remote-path', remote_path)
|
||||||
+ flags.make_flags('lock-wait', lock_wait)
|
+ flags.make_flags('lock-wait', lock_wait)
|
||||||
+ flags.make_flags('last', 1)
|
+ flags.make_flags('last', 1)
|
||||||
@@ -35,11 +33,8 @@ def resolve_archive_name(
|
|||||||
+ flags.make_repository_flags(repository, local_borg_version)
|
+ flags.make_repository_flags(repository, local_borg_version)
|
||||||
)
|
)
|
||||||
|
|
||||||
output = execute_command(
|
output = execute_command_and_capture_output(
|
||||||
full_command,
|
full_command, extra_environment=environment.make_environment(storage_config),
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path=local_path,
|
|
||||||
extra_environment=environment.make_environment(storage_config),
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
latest_archive = output.strip().splitlines()[-1]
|
latest_archive = output.strip().splitlines()[-1]
|
||||||
@@ -87,7 +82,11 @@ def make_rlist_command(
|
|||||||
+ flags.make_flags('remote-path', remote_path)
|
+ flags.make_flags('remote-path', remote_path)
|
||||||
+ flags.make_flags('lock-wait', lock_wait)
|
+ flags.make_flags('lock-wait', lock_wait)
|
||||||
+ (
|
+ (
|
||||||
flags.make_flags('glob-archives', f'{rlist_arguments.prefix}*')
|
(
|
||||||
|
flags.make_flags('match-archives', f'sh:{rlist_arguments.prefix}*')
|
||||||
|
if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version)
|
||||||
|
else flags.make_flags('glob-archives', f'{rlist_arguments.prefix}*')
|
||||||
|
)
|
||||||
if rlist_arguments.prefix
|
if rlist_arguments.prefix
|
||||||
else ()
|
else ()
|
||||||
)
|
)
|
||||||
@@ -115,12 +114,12 @@ def list_repository(
|
|||||||
repository, storage_config, local_borg_version, rlist_arguments, local_path, remote_path
|
repository, storage_config, local_borg_version, rlist_arguments, local_path, remote_path
|
||||||
)
|
)
|
||||||
|
|
||||||
output = execute_command(
|
|
||||||
main_command,
|
|
||||||
output_log_level=None if rlist_arguments.json else logging.WARNING,
|
|
||||||
borg_local_path=local_path,
|
|
||||||
extra_environment=borg_environment,
|
|
||||||
)
|
|
||||||
|
|
||||||
if rlist_arguments.json:
|
if rlist_arguments.json:
|
||||||
return output
|
return execute_command_and_capture_output(main_command, extra_environment=borg_environment,)
|
||||||
|
else:
|
||||||
|
execute_command(
|
||||||
|
main_command,
|
||||||
|
output_log_level=logging.WARNING,
|
||||||
|
borg_local_path=local_path,
|
||||||
|
extra_environment=borg_environment,
|
||||||
|
)
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ def transfer_archives(
|
|||||||
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
|
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
|
||||||
+ flags.make_flags('remote-path', remote_path)
|
+ flags.make_flags('remote-path', remote_path)
|
||||||
+ flags.make_flags('lock-wait', storage_config.get('lock_wait', None))
|
+ flags.make_flags('lock-wait', storage_config.get('lock_wait', None))
|
||||||
+ flags.make_flags(
|
+ (
|
||||||
'glob-archives', transfer_arguments.glob_archives or transfer_arguments.archive
|
flags.make_flags(
|
||||||
|
'match-archives', transfer_arguments.match_archives or transfer_arguments.archive
|
||||||
|
)
|
||||||
)
|
)
|
||||||
+ flags.make_flags_from_arguments(
|
+ flags.make_flags_from_arguments(
|
||||||
transfer_arguments,
|
transfer_arguments,
|
||||||
excludes=('repository', 'source_repository', 'archive', 'glob_archives'),
|
excludes=('repository', 'source_repository', 'archive', 'match_archives'),
|
||||||
)
|
)
|
||||||
+ flags.make_repository_flags(repository, local_borg_version)
|
+ flags.make_repository_flags(repository, local_borg_version)
|
||||||
+ flags.make_flags('other-repo', transfer_arguments.source_repository)
|
+ flags.make_flags('other-repo', transfer_arguments.source_repository)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.borg import environment
|
from borgmatic.borg import environment
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import execute_command_and_capture_output
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -18,11 +18,8 @@ def local_borg_version(storage_config, local_path='borg'):
|
|||||||
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
|
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
|
||||||
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
|
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
|
||||||
)
|
)
|
||||||
output = execute_command(
|
output = execute_command_and_capture_output(
|
||||||
full_command,
|
full_command, extra_environment=environment.make_environment(storage_config),
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path=local_path,
|
|
||||||
extra_environment=environment.make_environment(storage_config),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ SUBPARSER_ALIASES = {
|
|||||||
'rinfo': [],
|
'rinfo': [],
|
||||||
'info': ['-i'],
|
'info': ['-i'],
|
||||||
'transfer': [],
|
'transfer': [],
|
||||||
|
'break-lock': [],
|
||||||
'borg': [],
|
'borg': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,9 +294,10 @@ def make_parsers():
|
|||||||
)
|
)
|
||||||
transfer_group.add_argument(
|
transfer_group.add_argument(
|
||||||
'-a',
|
'-a',
|
||||||
|
'--match-archives',
|
||||||
'--glob-archives',
|
'--glob-archives',
|
||||||
metavar='GLOB',
|
metavar='PATTERN',
|
||||||
help='Only transfer archives with names matching this glob',
|
help='Only transfer archives with names matching this pattern',
|
||||||
)
|
)
|
||||||
transfer_group.add_argument(
|
transfer_group.add_argument(
|
||||||
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
||||||
@@ -627,7 +629,11 @@ def make_parsers():
|
|||||||
'-P', '--prefix', help='Only list archive names starting with this prefix'
|
'-P', '--prefix', help='Only list archive names starting with this prefix'
|
||||||
)
|
)
|
||||||
rlist_group.add_argument(
|
rlist_group.add_argument(
|
||||||
'-a', '--glob-archives', metavar='GLOB', help='Only list archive names matching this glob'
|
'-a',
|
||||||
|
'--match-archives',
|
||||||
|
'--glob-archives',
|
||||||
|
metavar='PATTERN',
|
||||||
|
help='Only list archive names matching this pattern',
|
||||||
)
|
)
|
||||||
rlist_group.add_argument(
|
rlist_group.add_argument(
|
||||||
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
||||||
@@ -678,7 +684,11 @@ def make_parsers():
|
|||||||
'-P', '--prefix', help='Only list archive names starting with this prefix'
|
'-P', '--prefix', help='Only list archive names starting with this prefix'
|
||||||
)
|
)
|
||||||
list_group.add_argument(
|
list_group.add_argument(
|
||||||
'-a', '--glob-archives', metavar='GLOB', help='Only list archive names matching this glob'
|
'-a',
|
||||||
|
'--match-archives',
|
||||||
|
'--glob-archives',
|
||||||
|
metavar='PATTERN',
|
||||||
|
help='Only list archive names matching this pattern',
|
||||||
)
|
)
|
||||||
list_group.add_argument(
|
list_group.add_argument(
|
||||||
'--successful',
|
'--successful',
|
||||||
@@ -747,9 +757,10 @@ def make_parsers():
|
|||||||
)
|
)
|
||||||
info_group.add_argument(
|
info_group.add_argument(
|
||||||
'-a',
|
'-a',
|
||||||
|
'--match-archives',
|
||||||
'--glob-archives',
|
'--glob-archives',
|
||||||
metavar='GLOB',
|
metavar='PATTERN',
|
||||||
help='Only show info for archive names matching this glob',
|
help='Only show info for archive names matching this pattern',
|
||||||
)
|
)
|
||||||
info_group.add_argument(
|
info_group.add_argument(
|
||||||
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
'--sort-by', metavar='KEYS', help='Comma-separated list of sorting keys'
|
||||||
@@ -764,6 +775,22 @@ def make_parsers():
|
|||||||
)
|
)
|
||||||
info_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
info_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||||
|
|
||||||
|
break_lock_parser = subparsers.add_parser(
|
||||||
|
'break-lock',
|
||||||
|
aliases=SUBPARSER_ALIASES['break-lock'],
|
||||||
|
help='Break the repository and cache locks left behind by Borg aborting',
|
||||||
|
description='Break Borg repository and cache locks left behind by Borg aborting',
|
||||||
|
add_help=False,
|
||||||
|
)
|
||||||
|
break_lock_group = break_lock_parser.add_argument_group('break-lock arguments')
|
||||||
|
break_lock_group.add_argument(
|
||||||
|
'--repository',
|
||||||
|
help='Path of repository to break the lock for, defaults to the configured repository if there is only one',
|
||||||
|
)
|
||||||
|
break_lock_group.add_argument(
|
||||||
|
'-h', '--help', action='help', help='Show this help message and exit'
|
||||||
|
)
|
||||||
|
|
||||||
borg_parser = subparsers.add_parser(
|
borg_parser = subparsers.add_parser(
|
||||||
'borg',
|
'borg',
|
||||||
aliases=SUBPARSER_ALIASES['borg'],
|
aliases=SUBPARSER_ALIASES['borg'],
|
||||||
@@ -816,7 +843,7 @@ def parse_arguments(*unparsed_arguments):
|
|||||||
if (
|
if (
|
||||||
'transfer' in arguments
|
'transfer' in arguments
|
||||||
and arguments['transfer'].archive
|
and arguments['transfer'].archive
|
||||||
and arguments['transfer'].glob_archives
|
and arguments['transfer'].match_archives
|
||||||
):
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'With the transfer action, only one of --archive and --glob-archives flags can be used.'
|
'With the transfer action, only one of --archive and --glob-archives flags can be used.'
|
||||||
@@ -824,11 +851,11 @@ def parse_arguments(*unparsed_arguments):
|
|||||||
|
|
||||||
if 'info' in arguments and (
|
if 'info' in arguments and (
|
||||||
(arguments['info'].archive and arguments['info'].prefix)
|
(arguments['info'].archive and arguments['info'].prefix)
|
||||||
or (arguments['info'].archive and arguments['info'].glob_archives)
|
or (arguments['info'].archive and arguments['info'].match_archives)
|
||||||
or (arguments['info'].prefix and arguments['info'].glob_archives)
|
or (arguments['info'].prefix and arguments['info'].match_archives)
|
||||||
):
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'With the info action, only one of --archive, --prefix, or --glob-archives flags can be used.'
|
'With the info action, only one of --archive, --prefix, or --match-archives flags can be used.'
|
||||||
)
|
)
|
||||||
|
|
||||||
return arguments
|
return arguments
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import pkg_resources
|
|||||||
|
|
||||||
import borgmatic.commands.completion
|
import borgmatic.commands.completion
|
||||||
from borgmatic.borg import borg as borg_borg
|
from borgmatic.borg import borg as borg_borg
|
||||||
|
from borgmatic.borg import break_lock as borg_break_lock
|
||||||
from borgmatic.borg import check as borg_check
|
from borgmatic.borg import check as borg_check
|
||||||
from borgmatic.borg import compact as borg_compact
|
from borgmatic.borg import compact as borg_compact
|
||||||
from borgmatic.borg import create as borg_create
|
from borgmatic.borg import create as borg_create
|
||||||
@@ -359,7 +360,7 @@ def run_actions(
|
|||||||
**hook_context,
|
**hook_context,
|
||||||
)
|
)
|
||||||
logger.info('{}: Creating archive{}'.format(repository, dry_run_label))
|
logger.info('{}: Creating archive{}'.format(repository, dry_run_label))
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks_even_if_unconfigured(
|
||||||
'remove_database_dumps',
|
'remove_database_dumps',
|
||||||
hooks,
|
hooks,
|
||||||
repository,
|
repository,
|
||||||
@@ -394,7 +395,7 @@ def run_actions(
|
|||||||
if json_output: # pragma: nocover
|
if json_output: # pragma: nocover
|
||||||
yield json.loads(json_output)
|
yield json.loads(json_output)
|
||||||
|
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks_even_if_unconfigured(
|
||||||
'remove_database_dumps',
|
'remove_database_dumps',
|
||||||
hooks,
|
hooks,
|
||||||
config_filename,
|
config_filename,
|
||||||
@@ -555,7 +556,7 @@ def run_actions(
|
|||||||
repository, arguments['restore'].archive
|
repository, arguments['restore'].archive
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks_even_if_unconfigured(
|
||||||
'remove_database_dumps',
|
'remove_database_dumps',
|
||||||
hooks,
|
hooks,
|
||||||
repository,
|
repository,
|
||||||
@@ -625,7 +626,7 @@ def run_actions(
|
|||||||
extract_process,
|
extract_process,
|
||||||
)
|
)
|
||||||
|
|
||||||
dispatch.call_hooks(
|
dispatch.call_hooks_even_if_unconfigured(
|
||||||
'remove_database_dumps',
|
'remove_database_dumps',
|
||||||
hooks,
|
hooks,
|
||||||
repository,
|
repository,
|
||||||
@@ -731,6 +732,18 @@ def run_actions(
|
|||||||
)
|
)
|
||||||
if json_output: # pragma: nocover
|
if json_output: # pragma: nocover
|
||||||
yield json.loads(json_output)
|
yield json.loads(json_output)
|
||||||
|
if 'break-lock' in arguments:
|
||||||
|
if arguments['break-lock'].repository is None or validate.repositories_match(
|
||||||
|
repository, arguments['break-lock'].repository
|
||||||
|
):
|
||||||
|
logger.warning(f'{repository}: Breaking repository and cache locks')
|
||||||
|
borg_break_lock.break_lock(
|
||||||
|
repository,
|
||||||
|
storage,
|
||||||
|
local_borg_version,
|
||||||
|
local_path=local_path,
|
||||||
|
remote_path=remote_path,
|
||||||
|
)
|
||||||
if 'borg' in arguments:
|
if 'borg' in arguments:
|
||||||
if arguments['borg'].repository is None or validate.repositories_match(
|
if arguments['borg'].repository is None or validate.repositories_match(
|
||||||
repository, arguments['borg'].repository
|
repository, arguments['borg'].repository
|
||||||
|
|||||||
@@ -8,49 +8,53 @@ def normalize(config_filename, config):
|
|||||||
message warnings produced based on the normalization performed.
|
message warnings produced based on the normalization performed.
|
||||||
'''
|
'''
|
||||||
logs = []
|
logs = []
|
||||||
|
location = config.get('location') or {}
|
||||||
|
storage = config.get('storage') or {}
|
||||||
|
consistency = config.get('consistency') or {}
|
||||||
|
hooks = config.get('hooks') or {}
|
||||||
|
|
||||||
# Upgrade exclude_if_present from a string to a list.
|
# Upgrade exclude_if_present from a string to a list.
|
||||||
exclude_if_present = config.get('location', {}).get('exclude_if_present')
|
exclude_if_present = location.get('exclude_if_present')
|
||||||
if isinstance(exclude_if_present, str):
|
if isinstance(exclude_if_present, str):
|
||||||
config['location']['exclude_if_present'] = [exclude_if_present]
|
config['location']['exclude_if_present'] = [exclude_if_present]
|
||||||
|
|
||||||
# Upgrade various monitoring hooks from a string to a dict.
|
# Upgrade various monitoring hooks from a string to a dict.
|
||||||
healthchecks = config.get('hooks', {}).get('healthchecks')
|
healthchecks = hooks.get('healthchecks')
|
||||||
if isinstance(healthchecks, str):
|
if isinstance(healthchecks, str):
|
||||||
config['hooks']['healthchecks'] = {'ping_url': healthchecks}
|
config['hooks']['healthchecks'] = {'ping_url': healthchecks}
|
||||||
|
|
||||||
cronitor = config.get('hooks', {}).get('cronitor')
|
cronitor = hooks.get('cronitor')
|
||||||
if isinstance(cronitor, str):
|
if isinstance(cronitor, str):
|
||||||
config['hooks']['cronitor'] = {'ping_url': cronitor}
|
config['hooks']['cronitor'] = {'ping_url': cronitor}
|
||||||
|
|
||||||
pagerduty = config.get('hooks', {}).get('pagerduty')
|
pagerduty = hooks.get('pagerduty')
|
||||||
if isinstance(pagerduty, str):
|
if isinstance(pagerduty, str):
|
||||||
config['hooks']['pagerduty'] = {'integration_key': pagerduty}
|
config['hooks']['pagerduty'] = {'integration_key': pagerduty}
|
||||||
|
|
||||||
cronhub = config.get('hooks', {}).get('cronhub')
|
cronhub = hooks.get('cronhub')
|
||||||
if isinstance(cronhub, str):
|
if isinstance(cronhub, str):
|
||||||
config['hooks']['cronhub'] = {'ping_url': cronhub}
|
config['hooks']['cronhub'] = {'ping_url': cronhub}
|
||||||
|
|
||||||
# Upgrade consistency checks from a list of strings to a list of dicts.
|
# Upgrade consistency checks from a list of strings to a list of dicts.
|
||||||
checks = config.get('consistency', {}).get('checks')
|
checks = consistency.get('checks')
|
||||||
if isinstance(checks, list) and len(checks) and isinstance(checks[0], str):
|
if isinstance(checks, list) and len(checks) and isinstance(checks[0], str):
|
||||||
config['consistency']['checks'] = [{'name': check_type} for check_type in checks]
|
config['consistency']['checks'] = [{'name': check_type} for check_type in checks]
|
||||||
|
|
||||||
# Rename various configuration options.
|
# Rename various configuration options.
|
||||||
numeric_owner = config.get('location', {}).pop('numeric_owner', None)
|
numeric_owner = location.pop('numeric_owner', None)
|
||||||
if numeric_owner is not None:
|
if numeric_owner is not None:
|
||||||
config['location']['numeric_ids'] = numeric_owner
|
config['location']['numeric_ids'] = numeric_owner
|
||||||
|
|
||||||
bsd_flags = config.get('location', {}).pop('bsd_flags', None)
|
bsd_flags = location.pop('bsd_flags', None)
|
||||||
if bsd_flags is not None:
|
if bsd_flags is not None:
|
||||||
config['location']['flags'] = bsd_flags
|
config['location']['flags'] = bsd_flags
|
||||||
|
|
||||||
remote_rate_limit = config.get('storage', {}).pop('remote_rate_limit', None)
|
remote_rate_limit = storage.pop('remote_rate_limit', None)
|
||||||
if remote_rate_limit is not None:
|
if remote_rate_limit is not None:
|
||||||
config['storage']['upload_rate_limit'] = remote_rate_limit
|
config['storage']['upload_rate_limit'] = remote_rate_limit
|
||||||
|
|
||||||
# Upgrade remote repositories to ssh:// syntax, required in Borg 2.
|
# Upgrade remote repositories to ssh:// syntax, required in Borg 2.
|
||||||
repositories = config.get('location', {}).get('repositories')
|
repositories = location.get('repositories')
|
||||||
if repositories:
|
if repositories:
|
||||||
config['location']['repositories'] = []
|
config['location']['repositories'] = []
|
||||||
for repository in repositories:
|
for repository in repositories:
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ def parse_overrides(raw_overrides):
|
|||||||
|
|
||||||
def apply_overrides(config, raw_overrides):
|
def apply_overrides(config, raw_overrides):
|
||||||
'''
|
'''
|
||||||
Given a sequence of configuration file override strings in the form of "section.option=value"
|
Given a configuration dict and a sequence of configuration file override strings in the form of
|
||||||
and a configuration dict, parse each override and set it the configuration dict.
|
"section.option=value", parse each override and set it the configuration dict.
|
||||||
'''
|
'''
|
||||||
overrides = parse_overrides(raw_overrides)
|
overrides = parse_overrides(raw_overrides)
|
||||||
|
|
||||||
|
|||||||
@@ -764,6 +764,32 @@ properties:
|
|||||||
description: |
|
description: |
|
||||||
Path to a certificate revocation list.
|
Path to a certificate revocation list.
|
||||||
example: "/root/.postgresql/root.crl"
|
example: "/root/.postgresql/root.crl"
|
||||||
|
pg_dump_command:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Command to use instead of "pg_dump" or
|
||||||
|
"pg_dumpall". This can be used to run a specific
|
||||||
|
pg_dump version (e.g., one inside a running
|
||||||
|
docker container). Defaults to "pg_dump" for
|
||||||
|
single database dump or "pg_dumpall" to dump
|
||||||
|
all databases.
|
||||||
|
example: docker exec my_pg_container pg_dump
|
||||||
|
pg_restore_command:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Command to use instead of "pg_restore". This
|
||||||
|
can be used to run a specific pg_restore
|
||||||
|
version (e.g., one inside a running docker
|
||||||
|
container). Defaults to "pg_restore".
|
||||||
|
example: docker exec my_pg_container pg_restore
|
||||||
|
psql_command:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Command to use instead of "psql". This can be
|
||||||
|
used to run a specific psql version (e.g.,
|
||||||
|
one inside a running docker container).
|
||||||
|
Defaults to "psql".
|
||||||
|
example: docker exec my_pg_container psql
|
||||||
options:
|
options:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
+36
-16
@@ -147,7 +147,7 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def log_command(full_command, input_file, output_file):
|
def log_command(full_command, input_file=None, output_file=None):
|
||||||
'''
|
'''
|
||||||
Log the given command (a sequence of command/argument strings), along with its input/output file
|
Log the given command (a sequence of command/argument strings), along with its input/output file
|
||||||
paths.
|
paths.
|
||||||
@@ -178,15 +178,14 @@ def execute_command(
|
|||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
Execute the given command (a sequence of command/argument strings) and log its output at the
|
Execute the given command (a sequence of command/argument strings) and log its output at the
|
||||||
given log level. If output log level is None, instead capture and return the output. (Implies
|
given log level. If an open output file object is given, then write stdout to the file and only
|
||||||
run_to_completion.) If an open output file object is given, then write stdout to the file and
|
log stderr. If an open input file object is given, then read stdin from the file. If shell is
|
||||||
only log stderr (but only if an output log level is set). If an open input file object is given,
|
True, execute the command within a shell. If an extra environment dict is given, then use it to
|
||||||
then read stdin from the file. If shell is True, execute the command within a shell. If an extra
|
augment the current environment, and pass the result into the command. If a working directory is
|
||||||
environment dict is given, then use it to augment the current environment, and pass the result
|
given, use that as the present working directory when running the command. If a Borg local path
|
||||||
into the command. If a working directory is given, use that as the present working directory
|
is given, and the command matches it (regardless of arguments), treat exit code 1 as a warning
|
||||||
when running the command. If a Borg local path is given, and the command matches it (regardless
|
instead of an error. If run to completion is False, then return the process for the command
|
||||||
of arguments), treat exit code 1 as a warning instead of an error. If run to completion is
|
without executing it to completion.
|
||||||
False, then return the process for the command without executing it to completion.
|
|
||||||
|
|
||||||
Raise subprocesses.CalledProcessError if an error occurs while running the command.
|
Raise subprocesses.CalledProcessError if an error occurs while running the command.
|
||||||
'''
|
'''
|
||||||
@@ -195,12 +194,6 @@ def execute_command(
|
|||||||
do_not_capture = bool(output_file is DO_NOT_CAPTURE)
|
do_not_capture = bool(output_file is DO_NOT_CAPTURE)
|
||||||
command = ' '.join(full_command) if shell else full_command
|
command = ' '.join(full_command) if shell else full_command
|
||||||
|
|
||||||
if output_log_level is None:
|
|
||||||
output = subprocess.check_output(
|
|
||||||
command, shell=shell, env=environment, cwd=working_directory
|
|
||||||
)
|
|
||||||
return output.decode() if output is not None else None
|
|
||||||
|
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
command,
|
command,
|
||||||
stdin=input_file,
|
stdin=input_file,
|
||||||
@@ -218,6 +211,33 @@ def execute_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def execute_command_and_capture_output(
|
||||||
|
full_command, capture_stderr=False, shell=False, extra_environment=None, working_directory=None,
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Execute the given command (a sequence of command/argument strings), capturing and returning its
|
||||||
|
output (stdout). If capture stderr is True, then capture and return stderr in addition to
|
||||||
|
stdout. If shell is True, execute the command within a shell. If an extra environment dict is
|
||||||
|
given, then use it to augment the current environment, and pass the result into the command. If
|
||||||
|
a working directory is given, use that as the present working directory when running the command.
|
||||||
|
|
||||||
|
Raise subprocesses.CalledProcessError if an error occurs while running the command.
|
||||||
|
'''
|
||||||
|
log_command(full_command)
|
||||||
|
environment = {**os.environ, **extra_environment} if extra_environment else None
|
||||||
|
command = ' '.join(full_command) if shell else full_command
|
||||||
|
|
||||||
|
output = subprocess.check_output(
|
||||||
|
command,
|
||||||
|
stderr=subprocess.STDOUT if capture_stderr else None,
|
||||||
|
shell=shell,
|
||||||
|
env=environment,
|
||||||
|
cwd=working_directory,
|
||||||
|
)
|
||||||
|
|
||||||
|
return output.decode() if output is not None else None
|
||||||
|
|
||||||
|
|
||||||
def execute_command_with_processes(
|
def execute_command_with_processes(
|
||||||
full_command,
|
full_command,
|
||||||
processes,
|
processes,
|
||||||
|
|||||||
@@ -29,19 +29,14 @@ def call_hook(function_name, hooks, log_prefix, hook_name, *args, **kwargs):
|
|||||||
'''
|
'''
|
||||||
Given the hooks configuration dict and a prefix to use in log entries, call the requested
|
Given the hooks configuration dict and a prefix to use in log entries, call the requested
|
||||||
function of the Python module corresponding to the given hook name. Supply that call with the
|
function of the Python module corresponding to the given hook name. Supply that call with the
|
||||||
configuration for this hook, the log prefix, and any given args and kwargs. Return any return
|
configuration for this hook (if any), the log prefix, and any given args and kwargs. Return any
|
||||||
value.
|
return value.
|
||||||
|
|
||||||
If the hook name is not present in the hooks configuration, then bail without calling anything.
|
|
||||||
|
|
||||||
Raise ValueError if the hook name is unknown.
|
Raise ValueError if the hook name is unknown.
|
||||||
Raise AttributeError if the function name is not found in the module.
|
Raise AttributeError if the function name is not found in the module.
|
||||||
Raise anything else that the called function raises.
|
Raise anything else that the called function raises.
|
||||||
'''
|
'''
|
||||||
config = hooks.get(hook_name)
|
config = hooks.get(hook_name, {})
|
||||||
if not config:
|
|
||||||
logger.debug('{}: No {} hook configured.'.format(log_prefix, hook_name))
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
module = HOOK_NAME_TO_MODULE[hook_name]
|
module = HOOK_NAME_TO_MODULE[hook_name]
|
||||||
@@ -59,7 +54,7 @@ def call_hooks(function_name, hooks, log_prefix, hook_names, *args, **kwargs):
|
|||||||
configuration for that hook, the log prefix, and any given args and kwargs. Collect any return
|
configuration for that hook, the log prefix, and any given args and kwargs. Collect any return
|
||||||
values into a dict from hook name to return value.
|
values into a dict from hook name to return value.
|
||||||
|
|
||||||
If the hook name is not present in the hooks configuration, then don't call the function for it,
|
If the hook name is not present in the hooks configuration, then don't call the function for it
|
||||||
and omit it from the return values.
|
and omit it from the return values.
|
||||||
|
|
||||||
Raise ValueError if the hook name is unknown.
|
Raise ValueError if the hook name is unknown.
|
||||||
@@ -71,3 +66,19 @@ def call_hooks(function_name, hooks, log_prefix, hook_names, *args, **kwargs):
|
|||||||
for hook_name in hook_names
|
for hook_name in hook_names
|
||||||
if hooks.get(hook_name)
|
if hooks.get(hook_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def call_hooks_even_if_unconfigured(function_name, hooks, log_prefix, hook_names, *args, **kwargs):
|
||||||
|
'''
|
||||||
|
Given the hooks configuration dict and a prefix to use in log entries, call the requested
|
||||||
|
function of the Python module corresponding to each given hook name. Supply each call with the
|
||||||
|
configuration for that hook, the log prefix, and any given args and kwargs. Collect any return
|
||||||
|
values into a dict from hook name to return value.
|
||||||
|
|
||||||
|
Raise AttributeError if the function name is not found in the module.
|
||||||
|
Raise anything else that a called function raises. An error stops calls to subsequent functions.
|
||||||
|
'''
|
||||||
|
return {
|
||||||
|
hook_name: call_hook(function_name, hooks, log_prefix, hook_name, *args, **kwargs)
|
||||||
|
for hook_name in hook_names
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def remove_database_dumps(dump_path, database_type_name, log_prefix, dry_run):
|
|||||||
'''
|
'''
|
||||||
dry_run_label = ' (dry run; not actually removing anything)' if dry_run else ''
|
dry_run_label = ' (dry run; not actually removing anything)' if dry_run else ''
|
||||||
|
|
||||||
logger.info(
|
logger.debug(
|
||||||
'{}: Removing {} database dumps{}'.format(log_prefix, database_type_name, dry_run_label)
|
'{}: Removing {} database dumps{}'.format(log_prefix, database_type_name, dry_run_label)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from borgmatic.execute import execute_command, execute_command_with_processes
|
from borgmatic.execute import (
|
||||||
|
execute_command,
|
||||||
|
execute_command_and_capture_output,
|
||||||
|
execute_command_with_processes,
|
||||||
|
)
|
||||||
from borgmatic.hooks import dump
|
from borgmatic.hooks import dump
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -42,8 +46,8 @@ def database_names_to_dump(database, extra_environment, log_prefix, dry_run_labe
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
'{}: Querying for "all" MySQL databases to dump{}'.format(log_prefix, dry_run_label)
|
'{}: Querying for "all" MySQL databases to dump{}'.format(log_prefix, dry_run_label)
|
||||||
)
|
)
|
||||||
show_output = execute_command(
|
show_output = execute_command_and_capture_output(
|
||||||
show_command, output_log_level=None, extra_environment=extra_environment
|
show_command, extra_environment=extra_environment
|
||||||
)
|
)
|
||||||
|
|
||||||
return tuple(
|
return tuple(
|
||||||
|
|||||||
@@ -56,13 +56,10 @@ def dump_databases(databases, log_prefix, location_config, dry_run):
|
|||||||
)
|
)
|
||||||
all_databases = bool(name == 'all')
|
all_databases = bool(name == 'all')
|
||||||
dump_format = database.get('format', 'custom')
|
dump_format = database.get('format', 'custom')
|
||||||
|
default_dump_command = 'pg_dumpall' if all_databases else 'pg_dump'
|
||||||
|
dump_command = database.get('pg_dump_command') or default_dump_command
|
||||||
command = (
|
command = (
|
||||||
(
|
(dump_command, '--no-password', '--clean', '--if-exists',)
|
||||||
'pg_dumpall' if all_databases else 'pg_dump',
|
|
||||||
'--no-password',
|
|
||||||
'--clean',
|
|
||||||
'--if-exists',
|
|
||||||
)
|
|
||||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||||
+ (('--username', database['username']) if 'username' in database else ())
|
+ (('--username', database['username']) if 'username' in database else ())
|
||||||
@@ -140,16 +137,18 @@ def restore_database_dump(database_config, log_prefix, location_config, dry_run,
|
|||||||
dump_filename = dump.make_database_dump_filename(
|
dump_filename = dump.make_database_dump_filename(
|
||||||
make_dump_path(location_config), database['name'], database.get('hostname')
|
make_dump_path(location_config), database['name'], database.get('hostname')
|
||||||
)
|
)
|
||||||
|
psql_command = database.get('psql_command') or 'psql'
|
||||||
analyze_command = (
|
analyze_command = (
|
||||||
('psql', '--no-password', '--quiet')
|
(psql_command, '--no-password', '--quiet')
|
||||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||||
+ (('--username', database['username']) if 'username' in database else ())
|
+ (('--username', database['username']) if 'username' in database else ())
|
||||||
+ (('--dbname', database['name']) if not all_databases else ())
|
+ (('--dbname', database['name']) if not all_databases else ())
|
||||||
+ ('--command', 'ANALYZE')
|
+ ('--command', 'ANALYZE')
|
||||||
)
|
)
|
||||||
|
pg_restore_command = database.get('pg_restore_command') or 'pg_restore'
|
||||||
restore_command = (
|
restore_command = (
|
||||||
('psql' if all_databases else 'pg_restore', '--no-password')
|
(psql_command if all_databases else pg_restore_command, '--no-password')
|
||||||
+ (
|
+ (
|
||||||
('--if-exists', '--exit-on-error', '--clean', '--dbname', database['name'])
|
('--if-exists', '--exit-on-error', '--clean', '--dbname', database['name'])
|
||||||
if not all_databases
|
if not all_databases
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ COPY . /app
|
|||||||
RUN apk add --no-cache py3-pip py3-ruamel.yaml py3-ruamel.yaml.clib
|
RUN apk add --no-cache py3-pip py3-ruamel.yaml py3-ruamel.yaml.clib
|
||||||
RUN pip install --no-cache /app && generate-borgmatic-config && chmod +r /etc/borgmatic/config.yaml
|
RUN pip install --no-cache /app && generate-borgmatic-config && chmod +r /etc/borgmatic/config.yaml
|
||||||
RUN borgmatic --help > /command-line.txt \
|
RUN borgmatic --help > /command-line.txt \
|
||||||
&& for action in rcreate transfer prune compact create check extract export-tar mount umount restore rlist list rinfo info borg; do \
|
&& for action in rcreate transfer prune compact create check extract export-tar mount umount restore rlist list rinfo info break-lock borg; do \
|
||||||
echo -e "\n--------------------------------------------------------------------------------\n" >> /command-line.txt \
|
echo -e "\n--------------------------------------------------------------------------------\n" >> /command-line.txt \
|
||||||
&& borgmatic "$action" --help >> /command-line.txt; done
|
&& borgmatic "$action" --help >> /command-line.txt; done
|
||||||
|
|
||||||
|
|||||||
@@ -215,8 +215,13 @@ databases that share the exact same name on different hosts.
|
|||||||
setting to support dump and restore streaming, you'll need to ensure that any
|
setting to support dump and restore streaming, you'll need to ensure that any
|
||||||
special files are excluded from backups (named pipes, block devices,
|
special files are excluded from backups (named pipes, block devices,
|
||||||
character devices, and sockets) to prevent hanging. Try a command like
|
character devices, and sockets) to prevent hanging. Try a command like
|
||||||
`find /your/source/path -type c,b,p,s` to find such files. Common directories
|
`find /your/source/path -type b -or -type c -or -type p -or -type s` to find
|
||||||
to exclude are `/dev` and `/run`, but that may not be exhaustive.
|
such files. Common directories to exclude are `/dev` and `/run`, but that may
|
||||||
|
not be exhaustive. <span class="minilink minilink-addedin">New in version
|
||||||
|
1.7.3</span> When database hooks are enabled, borgmatic automatically excludes
|
||||||
|
special files that may cause Borg to hang, so you no longer need to manually
|
||||||
|
exclude them. (This includes symlinks with special files as a destination.) You
|
||||||
|
can override/prevent this behavior by explicitly setting `read_special` to true.
|
||||||
|
|
||||||
|
|
||||||
### Manual restoration
|
### Manual restoration
|
||||||
@@ -272,3 +277,7 @@ Alternatively, if excluding special files is too onerous, you can create two
|
|||||||
separate borgmatic configuration files—one for your source files and a
|
separate borgmatic configuration files—one for your source files and a
|
||||||
separate one for backing up databases. That way, the database `read_special`
|
separate one for backing up databases. That way, the database `read_special`
|
||||||
option will not be active when backing up special files.
|
option will not be active when backing up special files.
|
||||||
|
|
||||||
|
<span class="minilink minilink-addedin">New in version 1.7.3</span> See
|
||||||
|
Limitations above about borgmatic's automatic exclusion of special files to
|
||||||
|
prevent Borg hangs.
|
||||||
|
|||||||
@@ -44,9 +44,11 @@ consistency checks with `check` on a much less frequent basis (e.g. with
|
|||||||
|
|
||||||
### Consistency check configuration
|
### Consistency check configuration
|
||||||
|
|
||||||
Another option is to customize your consistency checks. The default
|
Another option is to customize your consistency checks. By default, if you
|
||||||
consistency checks run both full-repository checks and per-archive checks
|
omit consistency checks from configuration, borgmatic runs full-repository
|
||||||
within each repository no more than once a month.
|
checks (`repository`) and per-archive checks (`archives`) within each
|
||||||
|
repository, no more than once a month. This is equivalent to what `borg check`
|
||||||
|
does if run without options.
|
||||||
|
|
||||||
But if you find that archive checks are too slow, for example, you can
|
But if you find that archive checks are too slow, for example, you can
|
||||||
configure borgmatic to run repository checks only. Configure this in the
|
configure borgmatic to run repository checks only. Configure this in the
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ be a [Borg
|
|||||||
pattern](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-patterns).
|
pattern](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-patterns).
|
||||||
|
|
||||||
To limit the archives searched, use the standard `list` parameters for
|
To limit the archives searched, use the standard `list` parameters for
|
||||||
filtering archives such as `--last`, `--archive`, `--glob-archives`, etc. For
|
filtering archives such as `--last`, `--archive`, `--match-archives`, etc. For
|
||||||
example, to search only the last five archives:
|
example, to search only the last five archives:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -42,3 +42,13 @@ potentially across providers.
|
|||||||
See [Borg repository URLs
|
See [Borg repository URLs
|
||||||
documentation](https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls)
|
documentation](https://borgbackup.readthedocs.io/en/stable/usage/general.html#repository-urls)
|
||||||
for more information on how to specify local and remote repository paths.
|
for more information on how to specify local and remote repository paths.
|
||||||
|
|
||||||
|
### Different options per repository
|
||||||
|
|
||||||
|
What if you want borgmatic to backup to multiple repositories—while also
|
||||||
|
setting different options for each one? In that case, you'll need to use
|
||||||
|
[a separate borgmatic configuration file for each
|
||||||
|
repository](https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/)
|
||||||
|
instead of the multiple repositories in one configuration file as described
|
||||||
|
above. That's because all of the repositories in a particular configuration
|
||||||
|
file get the same options applied.
|
||||||
|
|||||||
@@ -106,11 +106,60 @@ But if you do want to merge in a YAML key *and* its values, keep reading!
|
|||||||
|
|
||||||
## Include merging
|
## Include merging
|
||||||
|
|
||||||
If you need to get even fancier and pull in common configuration options while
|
If you need to get even fancier and merge in common configuration options, you
|
||||||
potentially overriding individual options, you can perform a YAML merge of
|
can perform a YAML merge of included configuration using the YAML `<<` key.
|
||||||
included configuration using the YAML `<<` key. For instance, here's an
|
For instance, here's an example of a main configuration file that pulls in
|
||||||
example of a main configuration file that pulls in two retention options via
|
retention and consistency options via a single include:
|
||||||
an include and then overrides one of them locally:
|
|
||||||
|
```yaml
|
||||||
|
<<: !include /etc/borgmatic/common.yaml
|
||||||
|
|
||||||
|
location:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
This is what `common.yaml` might look like:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
retention:
|
||||||
|
keep_hourly: 24
|
||||||
|
keep_daily: 7
|
||||||
|
|
||||||
|
consistency:
|
||||||
|
checks:
|
||||||
|
- name: repository
|
||||||
|
```
|
||||||
|
|
||||||
|
Once this include gets merged in, the resulting configuration would have all
|
||||||
|
of the `location` options from the original configuration file *and* the
|
||||||
|
`retention` and `consistency` options from the include.
|
||||||
|
|
||||||
|
Prior to borgmatic version 1.6.0, when there's a section collision between the
|
||||||
|
local file and the merged include, the local file's section takes precedence.
|
||||||
|
So if the `retention` section appears in both the local file and the include
|
||||||
|
file, the included `retention` is ignored in favor of the local `retention`.
|
||||||
|
But see below about deep merge in version 1.6.0+.
|
||||||
|
|
||||||
|
Note that this `<<` include merging syntax is only for merging in mappings
|
||||||
|
(configuration options and their values). But if you'd like to include a
|
||||||
|
single value directly, please see the section above about standard includes.
|
||||||
|
|
||||||
|
Additionally, there is a limitation preventing multiple `<<` include merges
|
||||||
|
per section. So for instance, that means you can do one `<<` merge at the
|
||||||
|
global level, another `<<` within each configuration section, etc. (This is a
|
||||||
|
YAML limitation.)
|
||||||
|
|
||||||
|
|
||||||
|
### Deep merge
|
||||||
|
|
||||||
|
<span class="minilink minilink-addedin">New in version 1.6.0</span> borgmatic
|
||||||
|
performs a deep merge of merged include files, meaning that values are merged
|
||||||
|
at all levels in the two configuration files. This allows you to include
|
||||||
|
common configuration—up to full borgmatic configuration files—while overriding
|
||||||
|
only the parts you want to customize.
|
||||||
|
|
||||||
|
For instance, here's an example of a main configuration file that pulls in two
|
||||||
|
retention options via an include and then overrides one of them locally:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
<<: !include /etc/borgmatic/common.yaml
|
<<: !include /etc/borgmatic/common.yaml
|
||||||
@@ -136,24 +185,8 @@ Once this include gets merged in, the resulting configuration would have a
|
|||||||
When there's an option collision between the local file and the merged
|
When there's an option collision between the local file and the merged
|
||||||
include, the local file's option takes precedence.
|
include, the local file's option takes precedence.
|
||||||
|
|
||||||
Note that this `<<` include merging syntax is only for merging in mappings
|
<span class="minilink minilink-addedin">New in version 1.6.1</span> Colliding
|
||||||
(configuration options and their values). But if you'd like to include a
|
list values are appended together.
|
||||||
single value directly, please see the section above about standard includes.
|
|
||||||
|
|
||||||
Additionally, there is a limitation preventing multiple `<<` include merges
|
|
||||||
per section. So for instance, that means you can do one `<<` merge at the
|
|
||||||
global level, another `<<` within each configuration section, etc. (This is a
|
|
||||||
YAML limitation.)
|
|
||||||
|
|
||||||
|
|
||||||
### Deep merge
|
|
||||||
|
|
||||||
<span class="minilink minilink-addedin">New in version 1.6.0</span> borgmatic
|
|
||||||
performs a deep merge of merged include files, meaning that values are merged
|
|
||||||
at all levels in the two configuration files. Colliding list values are
|
|
||||||
appended together. This allows you to include common configuration—up to full
|
|
||||||
borgmatic configuration files—while overriding only the parts you want to
|
|
||||||
customize.
|
|
||||||
|
|
||||||
|
|
||||||
## Configuration overrides
|
## Configuration overrides
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ based on your borgmatic configuration files or command-line arguments:
|
|||||||
|
|
||||||
### borg action
|
### borg action
|
||||||
|
|
||||||
The way you run Borg with borgmatic is via the `borg` action. Here's a simple
|
<span class="minilink minilink-addedin">New in version 1.5.15</span> The way
|
||||||
example:
|
you run Borg with borgmatic is via the `borg` action. Here's a simple example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
borgmatic borg break-lock
|
borgmatic borg break-lock
|
||||||
@@ -87,6 +87,9 @@ borgmatic's `borg` action is not without limitations:
|
|||||||
borgmatic action. In this case, only the Borg command is run.
|
borgmatic action. In this case, only the Borg command is run.
|
||||||
* Unlike normal borgmatic actions that support JSON, the `borg` action will
|
* Unlike normal borgmatic actions that support JSON, the `borg` action will
|
||||||
not disable certain borgmatic logs to avoid interfering with JSON output.
|
not disable certain borgmatic logs to avoid interfering with JSON output.
|
||||||
|
* Unlike other borgmatic actions, the `borg` action captures (and logs) all
|
||||||
|
output, so interactive prompts or flags like `--progress` will not work as
|
||||||
|
expected.
|
||||||
|
|
||||||
In general, this `borgmatic borg` feature should be considered an escape
|
In general, this `borgmatic borg` feature should be considered an escape
|
||||||
valve—a feature of second resort. In the long run, it's preferable to wrap
|
valve—a feature of second resort. In the long run, it's preferable to wrap
|
||||||
|
|||||||
+10
-5
@@ -160,17 +160,22 @@ Then, run the `rcreate` action (formerly `init`) to create that new Borg 2
|
|||||||
repository:
|
repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
borgmatic rcreate --verbosity 1 --encryption repokey-aes-ocb \
|
borgmatic rcreate --verbosity 1 --encryption repokey-blake2-aes-ocb \
|
||||||
--source-repository original.borg --repository upgraded.borg
|
--source-repository original.borg --repository upgraded.borg
|
||||||
```
|
```
|
||||||
|
|
||||||
(Note that `repokey-chacha20-poly1305` may be faster than `repokey-aes-ocb` on
|
|
||||||
certain platforms like ARM64.)
|
|
||||||
|
|
||||||
This creates an empty repository and doesn't actually transfer any data yet.
|
This creates an empty repository and doesn't actually transfer any data yet.
|
||||||
The `--source-repository` flag is necessary to reuse key material from your
|
The `--source-repository` flag is necessary to reuse key material from your
|
||||||
Borg 1 repository so that the subsequent data transfer can work.
|
Borg 1 repository so that the subsequent data transfer can work.
|
||||||
|
|
||||||
|
The `--encryption` value above selects the same chunk ID algorithm (`blake2`)
|
||||||
|
used in Borg 1, thereby making deduplication work across transferred archives
|
||||||
|
and new archives. Note that `repokey-blake2-chacha20-poly1305` may be faster
|
||||||
|
than `repokey-blake2-aes-ocb` on certain platforms like ARM64. Read about
|
||||||
|
[Borg encryption
|
||||||
|
modes](https://borgbackup.readthedocs.io/en/2.0.0b3/usage/rcreate.html#encryption-mode-tldr)
|
||||||
|
for the menu of available encryption modes.
|
||||||
|
|
||||||
To transfer data from your original Borg 1 repository to your newly created
|
To transfer data from your original Borg 1 repository to your newly created
|
||||||
Borg 2 repository:
|
Borg 2 repository:
|
||||||
|
|
||||||
@@ -191,7 +196,7 @@ confirmation of success—or tells you if something hasn't been transferred yet.
|
|||||||
Note that by omitting the `--upgrader` flag, you can also do archive transfers
|
Note that by omitting the `--upgrader` flag, you can also do archive transfers
|
||||||
between Borg 2 repositories without upgrading, even down to individual
|
between Borg 2 repositories without upgrading, even down to individual
|
||||||
archives. For more on that functionality, see the [Borg transfer
|
archives. For more on that functionality, see the [Borg transfer
|
||||||
documentation](https://borgbackup.readthedocs.io/en/2.0.0b1/usage/transfer.html).
|
documentation](https://borgbackup.readthedocs.io/en/2.0.0b3/usage/transfer.html).
|
||||||
|
|
||||||
That's it! Now you can use your new Borg 2 repository as normal with
|
That's it! Now you can use your new Borg 2 repository as normal with
|
||||||
borgmatic. If you've got multiple repositories, repeat the above process for
|
borgmatic. If you've got multiple repositories, repeat the above process for
|
||||||
|
|||||||
@@ -61,4 +61,4 @@ LogRateLimitIntervalSec=0
|
|||||||
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
|
# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
|
||||||
# dbus-user-session to be installed.
|
# dbus-user-session to be installed.
|
||||||
ExecStartPre=sleep 1m
|
ExecStartPre=sleep 1m
|
||||||
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /root/.local/bin/borgmatic --verbosity -1 --syslog-verbosity 1
|
ExecStart=systemd-inhibit --who="borgmatic" --what="sleep:shutdown" --why="Prevent interrupting scheduled backup" /root/.local/bin/borgmatic --verbosity -1 --syslog-verbosity 1
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ for sub_command in prune create check list info; do
|
|||||||
| grep -v '^--first' \
|
| grep -v '^--first' \
|
||||||
| grep -v '^--format' \
|
| grep -v '^--format' \
|
||||||
| grep -v '^--glob-archives' \
|
| grep -v '^--glob-archives' \
|
||||||
|
| grep -v '^--match-archives' \
|
||||||
| grep -v '^--last' \
|
| grep -v '^--last' \
|
||||||
| grep -v '^--format' \
|
| grep -v '^--format' \
|
||||||
| grep -v '^--patterns-from' \
|
| grep -v '^--patterns-from' \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
VERSION = '1.7.2'
|
VERSION = '1.7.5'
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ py==1.10.0
|
|||||||
pycodestyle==2.8.0
|
pycodestyle==2.8.0
|
||||||
pyflakes==2.4.0
|
pyflakes==2.4.0
|
||||||
jsonschema==3.2.0
|
jsonschema==3.2.0
|
||||||
pytest==6.2.5
|
pytest==7.2.0
|
||||||
pytest-cov==3.0.0
|
pytest-cov==4.0.0
|
||||||
regex; python_version >= '3.8'
|
regex; python_version >= '3.8'
|
||||||
requests==2.25.0
|
requests==2.25.0
|
||||||
ruamel.yaml>0.15.0,<0.18.0
|
ruamel.yaml>0.15.0,<0.18.0
|
||||||
|
|||||||
@@ -9,20 +9,24 @@ import pytest
|
|||||||
|
|
||||||
|
|
||||||
def write_configuration(
|
def write_configuration(
|
||||||
config_path, repository_path, borgmatic_source_directory, postgresql_dump_format='custom'
|
source_directory,
|
||||||
|
config_path,
|
||||||
|
repository_path,
|
||||||
|
borgmatic_source_directory,
|
||||||
|
postgresql_dump_format='custom',
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
Write out borgmatic configuration into a file at the config path. Set the options so as to work
|
Write out borgmatic configuration into a file at the config path. Set the options so as to work
|
||||||
for testing. This includes injecting the given repository path, borgmatic source directory for
|
for testing. This includes injecting the given repository path, borgmatic source directory for
|
||||||
storing database dumps, dump format (for PostgreSQL), and encryption passphrase.
|
storing database dumps, dump format (for PostgreSQL), and encryption passphrase.
|
||||||
'''
|
'''
|
||||||
config = '''
|
config = f'''
|
||||||
location:
|
location:
|
||||||
source_directories:
|
source_directories:
|
||||||
- {}
|
- {source_directory}
|
||||||
repositories:
|
repositories:
|
||||||
- {}
|
- {repository_path}
|
||||||
borgmatic_source_directory: {}
|
borgmatic_source_directory: {borgmatic_source_directory}
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
encryption_passphrase: "test"
|
encryption_passphrase: "test"
|
||||||
@@ -33,7 +37,7 @@ hooks:
|
|||||||
hostname: postgresql
|
hostname: postgresql
|
||||||
username: postgres
|
username: postgres
|
||||||
password: test
|
password: test
|
||||||
format: {}
|
format: {postgresql_dump_format}
|
||||||
- name: all
|
- name: all
|
||||||
hostname: postgresql
|
hostname: postgresql
|
||||||
username: postgres
|
username: postgres
|
||||||
@@ -57,9 +61,7 @@ hooks:
|
|||||||
hostname: mongodb
|
hostname: mongodb
|
||||||
username: root
|
username: root
|
||||||
password: test
|
password: test
|
||||||
'''.format(
|
'''
|
||||||
config_path, repository_path, borgmatic_source_directory, postgresql_dump_format
|
|
||||||
)
|
|
||||||
|
|
||||||
with open(config_path, 'w') as config_file:
|
with open(config_path, 'w') as config_file:
|
||||||
config_file.write(config)
|
config_file.write(config)
|
||||||
@@ -71,11 +73,16 @@ def test_database_dump_and_restore():
|
|||||||
repository_path = os.path.join(temporary_directory, 'test.borg')
|
repository_path = os.path.join(temporary_directory, 'test.borg')
|
||||||
borgmatic_source_directory = os.path.join(temporary_directory, '.borgmatic')
|
borgmatic_source_directory = os.path.join(temporary_directory, '.borgmatic')
|
||||||
|
|
||||||
|
# Write out a special file to ensure that it gets properly excluded and Borg doesn't hang on it.
|
||||||
|
os.mkfifo(os.path.join(temporary_directory, 'special_file'))
|
||||||
|
|
||||||
original_working_directory = os.getcwd()
|
original_working_directory = os.getcwd()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
config_path = os.path.join(temporary_directory, 'test.yaml')
|
config_path = os.path.join(temporary_directory, 'test.yaml')
|
||||||
write_configuration(config_path, repository_path, borgmatic_source_directory)
|
write_configuration(
|
||||||
|
temporary_directory, config_path, repository_path, borgmatic_source_directory
|
||||||
|
)
|
||||||
|
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
|
['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
|
||||||
@@ -114,6 +121,7 @@ def test_database_dump_and_restore_with_directory_format():
|
|||||||
try:
|
try:
|
||||||
config_path = os.path.join(temporary_directory, 'test.yaml')
|
config_path = os.path.join(temporary_directory, 'test.yaml')
|
||||||
write_configuration(
|
write_configuration(
|
||||||
|
temporary_directory,
|
||||||
config_path,
|
config_path,
|
||||||
repository_path,
|
repository_path,
|
||||||
borgmatic_source_directory,
|
borgmatic_source_directory,
|
||||||
@@ -146,7 +154,9 @@ def test_database_dump_with_error_causes_borgmatic_to_exit():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
config_path = os.path.join(temporary_directory, 'test.yaml')
|
config_path = os.path.join(temporary_directory, 'test.yaml')
|
||||||
write_configuration(config_path, repository_path, borgmatic_source_directory)
|
write_configuration(
|
||||||
|
temporary_directory, config_path, repository_path, borgmatic_source_directory
|
||||||
|
)
|
||||||
|
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
|
['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ def test_parse_arguments_disallows_json_with_both_rinfo_and_info():
|
|||||||
module.parse_arguments('rinfo', 'info', '--json')
|
module.parse_arguments('rinfo', 'info', '--json')
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_disallows_transfer_with_both_archive_and_glob_archives():
|
def test_parse_arguments_disallows_transfer_with_both_archive_and_match_archives():
|
||||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@@ -460,16 +460,16 @@ def test_parse_arguments_disallows_transfer_with_both_archive_and_glob_archives(
|
|||||||
'source.borg',
|
'source.borg',
|
||||||
'--archive',
|
'--archive',
|
||||||
'foo',
|
'foo',
|
||||||
'--glob-archives',
|
'--match-archives',
|
||||||
'*bar',
|
'sh:*bar',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_disallows_info_with_both_archive_and_glob_archives():
|
def test_parse_arguments_disallows_info_with_both_archive_and_match_archives():
|
||||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
module.parse_arguments('info', '--archive', 'foo', '--glob-archives', '*bar')
|
module.parse_arguments('info', '--archive', 'foo', '--match-archives', 'sh:*bar')
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_disallows_info_with_both_archive_and_prefix():
|
def test_parse_arguments_disallows_info_with_both_archive_and_prefix():
|
||||||
@@ -479,11 +479,11 @@ def test_parse_arguments_disallows_info_with_both_archive_and_prefix():
|
|||||||
module.parse_arguments('info', '--archive', 'foo', '--prefix', 'bar')
|
module.parse_arguments('info', '--archive', 'foo', '--prefix', 'bar')
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_disallows_info_with_both_prefix_and_glob_archives():
|
def test_parse_arguments_disallows_info_with_both_prefix_and_match_archives():
|
||||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
module.parse_arguments('info', '--prefix', 'foo', '--glob-archives', '*bar')
|
module.parse_arguments('info', '--prefix', 'foo', '--match-archives', 'sh:*bar')
|
||||||
|
|
||||||
|
|
||||||
def test_parse_arguments_check_only_extract_does_not_raise_extract_subparser_error():
|
def test_parse_arguments_check_only_extract_does_not_raise_extract_subparser_error():
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from flexmock import flexmock
|
||||||
|
|
||||||
|
from borgmatic.borg import break_lock as module
|
||||||
|
|
||||||
|
from ..test_verbosity import insert_logging_mock
|
||||||
|
|
||||||
|
|
||||||
|
def insert_execute_command_mock(command):
|
||||||
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
|
command, borg_local_path='borg', extra_environment=None,
|
||||||
|
).once()
|
||||||
|
|
||||||
|
|
||||||
|
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', 'repo'))
|
||||||
|
|
||||||
|
module.break_lock(
|
||||||
|
repository='repo', storage_config={}, local_borg_version='1.2.3',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_break_lock_calls_borg_with_remote_path_flags():
|
||||||
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
|
insert_execute_command_mock(('borg', 'break-lock', '--remote-path', 'borg1', 'repo'))
|
||||||
|
|
||||||
|
module.break_lock(
|
||||||
|
repository='repo', storage_config={}, local_borg_version='1.2.3', remote_path='borg1',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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', 'repo'))
|
||||||
|
|
||||||
|
module.break_lock(
|
||||||
|
repository='repo', storage_config={'umask': '0770'}, local_borg_version='1.2.3',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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', '--lock-wait', '5', 'repo'))
|
||||||
|
|
||||||
|
module.break_lock(
|
||||||
|
repository='repo', storage_config={'lock_wait': '5'}, local_borg_version='1.2.3',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_break_lock_with_log_info_calls_borg_with_info_parameter():
|
||||||
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
|
insert_execute_command_mock(('borg', 'break-lock', '--info', 'repo'))
|
||||||
|
insert_logging_mock(logging.INFO)
|
||||||
|
|
||||||
|
module.break_lock(
|
||||||
|
repository='repo', storage_config={}, local_borg_version='1.2.3',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_break_lock_with_log_debug_calls_borg_with_debug_flags():
|
||||||
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
|
insert_execute_command_mock(('borg', 'break-lock', '--debug', '--show-rc', 'repo'))
|
||||||
|
insert_logging_mock(logging.DEBUG)
|
||||||
|
|
||||||
|
module.break_lock(
|
||||||
|
repository='repo', storage_config={}, local_borg_version='1.2.3',
|
||||||
|
)
|
||||||
@@ -188,95 +188,153 @@ def test_filter_checks_on_frequency_restains_check_with_unelapsed_frequency_and_
|
|||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_repository_check_returns_flag():
|
def test_make_check_flags_with_repository_check_returns_flag():
|
||||||
flags = module.make_check_flags(('repository',))
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('repository',))
|
||||||
|
|
||||||
assert flags == ('--repository-only',)
|
assert flags == ('--repository-only',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_archives_check_returns_flag():
|
def test_make_check_flags_with_archives_check_returns_flag():
|
||||||
flags = module.make_check_flags(('archives',))
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('archives',))
|
||||||
|
|
||||||
assert flags == ('--archives-only',)
|
assert flags == ('--archives-only',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_data_check_returns_flag_and_implies_archives():
|
def test_make_check_flags_with_data_check_returns_flag_and_implies_archives():
|
||||||
flags = module.make_check_flags(('data',))
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('data',))
|
||||||
|
|
||||||
assert flags == ('--archives-only', '--verify-data',)
|
assert flags == ('--archives-only', '--verify-data',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_extract_omits_extract_flag():
|
def test_make_check_flags_with_extract_omits_extract_flag():
|
||||||
flags = module.make_check_flags(('extract',))
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('extract',))
|
||||||
|
|
||||||
assert flags == ()
|
assert flags == ()
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_repository_and_data_checks_does_not_return_repository_only():
|
def test_make_check_flags_with_repository_and_data_checks_does_not_return_repository_only():
|
||||||
flags = module.make_check_flags(('repository', 'data',))
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('repository', 'data',))
|
||||||
|
|
||||||
assert flags == ('--verify-data',)
|
assert flags == ('--verify-data',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_default_checks_and_default_prefix_returns_default_flags():
|
def test_make_check_flags_with_default_checks_and_default_prefix_returns_default_flags():
|
||||||
flags = module.make_check_flags(('repository', 'archives'), prefix=module.DEFAULT_PREFIX)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
assert flags == ('--glob-archives', f'{module.DEFAULT_PREFIX}*')
|
flags = module.make_check_flags(
|
||||||
|
'1.2.3', ('repository', 'archives'), prefix=module.DEFAULT_PREFIX
|
||||||
|
)
|
||||||
|
|
||||||
|
assert flags == ('--match-archives', f'sh:{module.DEFAULT_PREFIX}*')
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_all_checks_and_default_prefix_returns_default_flags():
|
def test_make_check_flags_with_all_checks_and_default_prefix_returns_default_flags():
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
flags = module.make_check_flags(
|
flags = module.make_check_flags(
|
||||||
('repository', 'archives', 'extract'), prefix=module.DEFAULT_PREFIX
|
'1.2.3', ('repository', 'archives', 'extract'), prefix=module.DEFAULT_PREFIX
|
||||||
|
)
|
||||||
|
|
||||||
|
assert flags == ('--match-archives', f'sh:{module.DEFAULT_PREFIX}*')
|
||||||
|
|
||||||
|
|
||||||
|
def test_make_check_flags_with_all_checks_and_default_prefix_without_borg_features_returns_glob_archives_flags():
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(False)
|
||||||
|
|
||||||
|
flags = module.make_check_flags(
|
||||||
|
'1.2.3', ('repository', 'archives', 'extract'), prefix=module.DEFAULT_PREFIX
|
||||||
)
|
)
|
||||||
|
|
||||||
assert flags == ('--glob-archives', f'{module.DEFAULT_PREFIX}*')
|
assert flags == ('--glob-archives', f'{module.DEFAULT_PREFIX}*')
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_archives_check_and_last_includes_last_flag():
|
def test_make_check_flags_with_archives_check_and_last_includes_last_flag():
|
||||||
flags = module.make_check_flags(('archives',), check_last=3)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('archives',), check_last=3)
|
||||||
|
|
||||||
assert flags == ('--archives-only', '--last', '3')
|
assert flags == ('--archives-only', '--last', '3')
|
||||||
|
|
||||||
|
|
||||||
|
def test_make_check_flags_with_data_check_and_last_includes_last_flag():
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('data',), check_last=3)
|
||||||
|
|
||||||
|
assert flags == ('--archives-only', '--last', '3', '--verify-data')
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_repository_check_and_last_omits_last_flag():
|
def test_make_check_flags_with_repository_check_and_last_omits_last_flag():
|
||||||
flags = module.make_check_flags(('repository',), check_last=3)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('repository',), check_last=3)
|
||||||
|
|
||||||
assert flags == ('--repository-only',)
|
assert flags == ('--repository-only',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_default_checks_and_last_includes_last_flag():
|
def test_make_check_flags_with_default_checks_and_last_includes_last_flag():
|
||||||
flags = module.make_check_flags(('repository', 'archives'), check_last=3)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('repository', 'archives'), check_last=3)
|
||||||
|
|
||||||
assert flags == ('--last', '3')
|
assert flags == ('--last', '3')
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_archives_check_and_prefix_includes_glob_archives_flag():
|
def test_make_check_flags_with_archives_check_and_prefix_includes_match_archives_flag():
|
||||||
flags = module.make_check_flags(('archives',), prefix='foo-')
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
assert flags == ('--archives-only', '--glob-archives', 'foo-*')
|
flags = module.make_check_flags('1.2.3', ('archives',), prefix='foo-')
|
||||||
|
|
||||||
|
assert flags == ('--archives-only', '--match-archives', 'sh:foo-*')
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_archives_check_and_empty_prefix_omits_glob_archives_flag():
|
def test_make_check_flags_with_data_check_and_prefix_includes_match_archives_flag():
|
||||||
flags = module.make_check_flags(('archives',), prefix='')
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('data',), prefix='foo-')
|
||||||
|
|
||||||
|
assert flags == ('--archives-only', '--match-archives', 'sh:foo-*', '--verify-data')
|
||||||
|
|
||||||
|
|
||||||
|
def test_make_check_flags_with_archives_check_and_empty_prefix_omits_match_archives_flag():
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('archives',), prefix='')
|
||||||
|
|
||||||
assert flags == ('--archives-only',)
|
assert flags == ('--archives-only',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_archives_check_and_none_prefix_omits_glob_archives_flag():
|
def test_make_check_flags_with_archives_check_and_none_prefix_omits_match_archives_flag():
|
||||||
flags = module.make_check_flags(('archives',), prefix=None)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('archives',), prefix=None)
|
||||||
|
|
||||||
assert flags == ('--archives-only',)
|
assert flags == ('--archives-only',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_repository_check_and_prefix_omits_glob_archives_flag():
|
def test_make_check_flags_with_repository_check_and_prefix_omits_match_archives_flag():
|
||||||
flags = module.make_check_flags(('repository',), prefix='foo-')
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
|
flags = module.make_check_flags('1.2.3', ('repository',), prefix='foo-')
|
||||||
|
|
||||||
assert flags == ('--repository-only',)
|
assert flags == ('--repository-only',)
|
||||||
|
|
||||||
|
|
||||||
def test_make_check_flags_with_default_checks_and_prefix_includes_glob_archives_flag():
|
def test_make_check_flags_with_default_checks_and_prefix_includes_match_archives_flag():
|
||||||
flags = module.make_check_flags(('repository', 'archives'), prefix='foo-')
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
assert flags == ('--glob-archives', 'foo-*')
|
flags = module.make_check_flags('1.2.3', ('repository', 'archives'), prefix='foo-')
|
||||||
|
|
||||||
|
assert flags == ('--match-archives', 'sh:foo-*')
|
||||||
|
|
||||||
|
|
||||||
def test_read_check_time_does_not_raise():
|
def test_read_check_time_does_not_raise():
|
||||||
@@ -369,7 +427,7 @@ def test_check_archives_calls_borg_with_parameters(checks):
|
|||||||
'{"repository": {"id": "repo"}}'
|
'{"repository": {"id": "repo"}}'
|
||||||
)
|
)
|
||||||
flexmock(module).should_receive('make_check_flags').with_args(
|
flexmock(module).should_receive('make_check_flags').with_args(
|
||||||
checks, check_last, module.DEFAULT_PREFIX
|
'1.2.3', checks, check_last, module.DEFAULT_PREFIX
|
||||||
).and_return(())
|
).and_return(())
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(('borg', 'check', 'repo'))
|
insert_execute_command_mock(('borg', 'check', 'repo'))
|
||||||
@@ -523,7 +581,7 @@ def test_check_archives_with_local_path_calls_borg_via_local_path():
|
|||||||
'{"repository": {"id": "repo"}}'
|
'{"repository": {"id": "repo"}}'
|
||||||
)
|
)
|
||||||
flexmock(module).should_receive('make_check_flags').with_args(
|
flexmock(module).should_receive('make_check_flags').with_args(
|
||||||
checks, check_last, module.DEFAULT_PREFIX
|
'1.2.3', checks, check_last, module.DEFAULT_PREFIX
|
||||||
).and_return(())
|
).and_return(())
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(('borg1', 'check', 'repo'))
|
insert_execute_command_mock(('borg1', 'check', 'repo'))
|
||||||
@@ -550,7 +608,7 @@ def test_check_archives_with_remote_path_calls_borg_with_remote_path_parameters(
|
|||||||
'{"repository": {"id": "repo"}}'
|
'{"repository": {"id": "repo"}}'
|
||||||
)
|
)
|
||||||
flexmock(module).should_receive('make_check_flags').with_args(
|
flexmock(module).should_receive('make_check_flags').with_args(
|
||||||
checks, check_last, module.DEFAULT_PREFIX
|
'1.2.3', checks, check_last, module.DEFAULT_PREFIX
|
||||||
).and_return(())
|
).and_return(())
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(('borg', 'check', '--remote-path', 'borg1', 'repo'))
|
insert_execute_command_mock(('borg', 'check', '--remote-path', 'borg1', 'repo'))
|
||||||
@@ -577,7 +635,7 @@ def test_check_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
|||||||
'{"repository": {"id": "repo"}}'
|
'{"repository": {"id": "repo"}}'
|
||||||
)
|
)
|
||||||
flexmock(module).should_receive('make_check_flags').with_args(
|
flexmock(module).should_receive('make_check_flags').with_args(
|
||||||
checks, check_last, module.DEFAULT_PREFIX
|
'1.2.3', checks, check_last, module.DEFAULT_PREFIX
|
||||||
).and_return(())
|
).and_return(())
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(('borg', 'check', '--lock-wait', '5', 'repo'))
|
insert_execute_command_mock(('borg', 'check', '--lock-wait', '5', 'repo'))
|
||||||
@@ -604,7 +662,7 @@ def test_check_archives_with_retention_prefix():
|
|||||||
'{"repository": {"id": "repo"}}'
|
'{"repository": {"id": "repo"}}'
|
||||||
)
|
)
|
||||||
flexmock(module).should_receive('make_check_flags').with_args(
|
flexmock(module).should_receive('make_check_flags').with_args(
|
||||||
checks, check_last, prefix
|
'1.2.3', checks, check_last, prefix
|
||||||
).and_return(())
|
).and_return(())
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(('borg', 'check', 'repo'))
|
insert_execute_command_mock(('borg', 'check', 'repo'))
|
||||||
|
|||||||
+404
-83
@@ -130,10 +130,27 @@ def test_write_pattern_file_with_sources_writes_sources_as_roots():
|
|||||||
module.write_pattern_file(['R /foo', '+ /foo/bar'], sources=['/baz', '/quux'])
|
module.write_pattern_file(['R /foo', '+ /foo/bar'], sources=['/baz', '/quux'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_pattern_file_without_patterns_but_with_sources_writes_sources_as_roots():
|
||||||
|
temporary_file = flexmock(name='filename', flush=lambda: None)
|
||||||
|
temporary_file.should_receive('write').with_args('R /baz\nR /quux')
|
||||||
|
flexmock(module.tempfile).should_receive('NamedTemporaryFile').and_return(temporary_file)
|
||||||
|
|
||||||
|
module.write_pattern_file([], sources=['/baz', '/quux'])
|
||||||
|
|
||||||
|
|
||||||
def test_write_pattern_file_with_empty_exclude_patterns_does_not_raise():
|
def test_write_pattern_file_with_empty_exclude_patterns_does_not_raise():
|
||||||
module.write_pattern_file([])
|
module.write_pattern_file([])
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_pattern_file_overwrites_existing_file():
|
||||||
|
pattern_file = flexmock(name='filename', flush=lambda: None)
|
||||||
|
pattern_file.should_receive('seek').with_args(0).once()
|
||||||
|
pattern_file.should_receive('write').with_args('R /foo\n+ /foo/bar')
|
||||||
|
flexmock(module.tempfile).should_receive('NamedTemporaryFile').never()
|
||||||
|
|
||||||
|
module.write_pattern_file(['R /foo', '+ /foo/bar'], pattern_file=pattern_file)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'filename_lists,opened_filenames',
|
'filename_lists,opened_filenames',
|
||||||
(
|
(
|
||||||
@@ -267,25 +284,25 @@ def test_make_exclude_flags_is_empty_when_config_has_no_excludes():
|
|||||||
assert exclude_flags == ()
|
assert exclude_flags == ()
|
||||||
|
|
||||||
|
|
||||||
def test_borgmatic_source_directories_set_when_directory_exists():
|
def test_collect_borgmatic_source_directories_set_when_directory_exists():
|
||||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||||
flexmock(module.os.path).should_receive('expanduser')
|
flexmock(module.os.path).should_receive('expanduser')
|
||||||
|
|
||||||
assert module.borgmatic_source_directories('/tmp') == ['/tmp']
|
assert module.collect_borgmatic_source_directories('/tmp') == ['/tmp']
|
||||||
|
|
||||||
|
|
||||||
def test_borgmatic_source_directories_empty_when_directory_does_not_exist():
|
def test_collect_borgmatic_source_directories_empty_when_directory_does_not_exist():
|
||||||
flexmock(module.os.path).should_receive('exists').and_return(False)
|
flexmock(module.os.path).should_receive('exists').and_return(False)
|
||||||
flexmock(module.os.path).should_receive('expanduser')
|
flexmock(module.os.path).should_receive('expanduser')
|
||||||
|
|
||||||
assert module.borgmatic_source_directories('/tmp') == []
|
assert module.collect_borgmatic_source_directories('/tmp') == []
|
||||||
|
|
||||||
|
|
||||||
def test_borgmatic_source_directories_defaults_when_directory_not_given():
|
def test_collect_borgmatic_source_directories_defaults_when_directory_not_given():
|
||||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||||
flexmock(module.os.path).should_receive('expanduser')
|
flexmock(module.os.path).should_receive('expanduser')
|
||||||
|
|
||||||
assert module.borgmatic_source_directories(None) == [
|
assert module.collect_borgmatic_source_directories(None) == [
|
||||||
module.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
|
module.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -300,12 +317,103 @@ def test_pattern_root_directories_parses_roots_and_ignores_others():
|
|||||||
) == ['/root', '/baz']
|
) == ['/root', '/baz']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'character_device,block_device,fifo,expected_result',
|
||||||
|
(
|
||||||
|
(False, False, False, False),
|
||||||
|
(True, False, False, True),
|
||||||
|
(False, True, False, True),
|
||||||
|
(True, True, False, True),
|
||||||
|
(False, False, True, True),
|
||||||
|
(False, True, True, True),
|
||||||
|
(True, False, True, True),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_special_file_looks_at_file_type(character_device, block_device, fifo, expected_result):
|
||||||
|
flexmock(module.os).should_receive('stat').and_return(flexmock(st_mode=flexmock()))
|
||||||
|
flexmock(module.stat).should_receive('S_ISCHR').and_return(character_device)
|
||||||
|
flexmock(module.stat).should_receive('S_ISBLK').and_return(block_device)
|
||||||
|
flexmock(module.stat).should_receive('S_ISFIFO').and_return(fifo)
|
||||||
|
|
||||||
|
assert module.special_file('/dev/special') == expected_result
|
||||||
|
|
||||||
|
|
||||||
|
def test_special_file_treats_broken_symlink_as_non_special():
|
||||||
|
flexmock(module.os).should_receive('stat').and_raise(FileNotFoundError)
|
||||||
|
|
||||||
|
assert module.special_file('/broken/symlink') is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_any_parent_directories_treats_parents_as_match():
|
||||||
|
module.any_parent_directories('/foo/bar.txt', ('/foo', '/etc'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_any_parent_directories_treats_grandparents_as_match():
|
||||||
|
module.any_parent_directories('/foo/bar/baz.txt', ('/foo', '/etc'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_any_parent_directories_treats_unrelated_paths_as_non_match():
|
||||||
|
module.any_parent_directories('/foo/bar.txt', ('/usr', '/etc'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_special_file_paths_parses_special_files_from_borg_dry_run_file_list():
|
||||||
|
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
|
||||||
|
'Processing files ...\n- /foo\n- /bar\n- /baz'
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('special_file').and_return(True)
|
||||||
|
flexmock(module).should_receive('any_parent_directories').and_return(False)
|
||||||
|
|
||||||
|
assert module.collect_special_file_paths(
|
||||||
|
('borg', 'create'),
|
||||||
|
local_path=None,
|
||||||
|
working_directory=None,
|
||||||
|
borg_environment=None,
|
||||||
|
skip_directories=flexmock(),
|
||||||
|
) == ('/foo', '/bar', '/baz')
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_special_file_paths_excludes_requested_directories():
|
||||||
|
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
|
||||||
|
'- /foo\n- /bar\n- /baz'
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('special_file').and_return(True)
|
||||||
|
flexmock(module).should_receive('any_parent_directories').and_return(False).and_return(
|
||||||
|
True
|
||||||
|
).and_return(False)
|
||||||
|
|
||||||
|
assert module.collect_special_file_paths(
|
||||||
|
('borg', 'create'),
|
||||||
|
local_path=None,
|
||||||
|
working_directory=None,
|
||||||
|
borg_environment=None,
|
||||||
|
skip_directories=flexmock(),
|
||||||
|
) == ('/foo', '/baz')
|
||||||
|
|
||||||
|
|
||||||
|
def test_collect_special_file_paths_excludes_non_special_files():
|
||||||
|
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
|
||||||
|
'- /foo\n- /bar\n- /baz'
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('special_file').and_return(True).and_return(False).and_return(
|
||||||
|
True
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('any_parent_directories').and_return(False)
|
||||||
|
|
||||||
|
assert module.collect_special_file_paths(
|
||||||
|
('borg', 'create'),
|
||||||
|
local_path=None,
|
||||||
|
working_directory=None,
|
||||||
|
borg_environment=None,
|
||||||
|
skip_directories=flexmock(),
|
||||||
|
) == ('/foo', '/baz')
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
|
DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
|
||||||
REPO_ARCHIVE_WITH_PATHS = (f'repo::{DEFAULT_ARCHIVE_NAME}', 'foo', 'bar')
|
REPO_ARCHIVE_WITH_PATHS = (f'repo::{DEFAULT_ARCHIVE_NAME}', 'foo', 'bar')
|
||||||
|
|
||||||
|
|
||||||
def test_create_archive_calls_borg_with_parameters():
|
def test_create_archive_calls_borg_with_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -344,7 +452,7 @@ def test_create_archive_calls_borg_with_parameters():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_calls_borg_with_environment():
|
def test_create_archive_calls_borg_with_environment():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -385,7 +493,7 @@ def test_create_archive_calls_borg_with_environment():
|
|||||||
|
|
||||||
def test_create_archive_with_patterns_calls_borg_with_patterns_including_converted_source_directories():
|
def test_create_archive_with_patterns_calls_borg_with_patterns_including_converted_source_directories():
|
||||||
pattern_flags = ('--patterns-from', 'patterns')
|
pattern_flags = ('--patterns-from', 'patterns')
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -427,7 +535,7 @@ def test_create_archive_with_patterns_calls_borg_with_patterns_including_convert
|
|||||||
|
|
||||||
def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
|
def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
|
||||||
exclude_flags = ('--exclude-from', 'excludes')
|
exclude_flags = ('--exclude-from', 'excludes')
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -468,7 +576,7 @@ def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_log_info_calls_borg_with_info_parameter():
|
def test_create_archive_with_log_info_calls_borg_with_info_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -485,7 +593,7 @@ def test_create_archive_with_log_info_calls_borg_with_info_parameter():
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--info') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--info',),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -508,7 +616,7 @@ def test_create_archive_with_log_info_calls_borg_with_info_parameter():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
|
def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -524,11 +632,8 @@ def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--json',),
|
||||||
output_log_level=None,
|
|
||||||
output_file=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
working_directory=None,
|
working_directory=None,
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
)
|
)
|
||||||
@@ -549,7 +654,7 @@ def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
|
def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -566,7 +671,7 @@ def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--debug', '--show-rc') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--debug', '--show-rc'),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -589,7 +694,7 @@ def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
|
def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -605,11 +710,8 @@ def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--json',),
|
||||||
output_log_level=None,
|
|
||||||
output_file=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
working_directory=None,
|
working_directory=None,
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
)
|
)
|
||||||
@@ -630,7 +732,7 @@ def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
|
def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -671,7 +773,7 @@ def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
|
|||||||
def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats_parameter():
|
def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats_parameter():
|
||||||
# --dry-run and --stats are mutually exclusive, see:
|
# --dry-run and --stats are mutually exclusive, see:
|
||||||
# https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
|
# https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -688,7 +790,7 @@ def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats_paramete
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--info', '--dry-run') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create', '--dry-run') + REPO_ARCHIVE_WITH_PATHS + ('--info',),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -712,7 +814,7 @@ def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats_paramete
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_interval_parameters():
|
def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_interval_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -751,7 +853,7 @@ def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_inte
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_chunker_params_calls_borg_with_chunker_params_parameters():
|
def test_create_archive_with_chunker_params_calls_borg_with_chunker_params_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -790,7 +892,7 @@ def test_create_archive_with_chunker_params_calls_borg_with_chunker_params_param
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_compression_calls_borg_with_compression_parameters():
|
def test_create_archive_with_compression_calls_borg_with_compression_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -834,7 +936,7 @@ def test_create_archive_with_compression_calls_borg_with_compression_parameters(
|
|||||||
def test_create_archive_with_upload_rate_limit_calls_borg_with_upload_ratelimit_parameters(
|
def test_create_archive_with_upload_rate_limit_calls_borg_with_upload_ratelimit_parameters(
|
||||||
feature_available, option_flag
|
feature_available, option_flag
|
||||||
):
|
):
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -873,7 +975,7 @@ def test_create_archive_with_upload_rate_limit_calls_borg_with_upload_ratelimit_
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_working_directory_calls_borg_with_working_directory():
|
def test_create_archive_with_working_directory_calls_borg_with_working_directory():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -915,7 +1017,7 @@ def test_create_archive_with_working_directory_calls_borg_with_working_directory
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_parameter():
|
def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -960,7 +1062,7 @@ def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_par
|
|||||||
def test_create_archive_with_numeric_ids_calls_borg_with_numeric_ids_parameter(
|
def test_create_archive_with_numeric_ids_calls_borg_with_numeric_ids_parameter(
|
||||||
feature_available, option_flag
|
feature_available, option_flag
|
||||||
):
|
):
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1000,7 +1102,7 @@ def test_create_archive_with_numeric_ids_calls_borg_with_numeric_ids_parameter(
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_read_special_calls_borg_with_read_special_parameter():
|
def test_create_archive_with_read_special_calls_borg_with_read_special_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1016,8 +1118,18 @@ def test_create_archive_with_read_special_calls_borg_with_read_special_parameter
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('collect_special_file_paths').and_return(())
|
||||||
|
create_command = ('borg', 'create', '--read-special') + REPO_ARCHIVE_WITH_PATHS
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--read-special') + REPO_ARCHIVE_WITH_PATHS,
|
create_command + ('--dry-run', '--list'),
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
|
create_command,
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1047,7 +1159,7 @@ def test_create_archive_with_basic_option_calls_borg_with_corresponding_paramete
|
|||||||
option_name, option_value
|
option_name, option_value
|
||||||
):
|
):
|
||||||
option_flag = '--no' + option_name.replace('', '') if option_value is False else None
|
option_flag = '--no' + option_name.replace('', '') if option_value is False else None
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1098,7 +1210,7 @@ def test_create_archive_with_basic_option_calls_borg_with_corresponding_paramete
|
|||||||
def test_create_archive_with_atime_option_calls_borg_with_corresponding_parameter(
|
def test_create_archive_with_atime_option_calls_borg_with_corresponding_parameter(
|
||||||
option_value, feature_available, option_flag
|
option_value, feature_available, option_flag
|
||||||
):
|
):
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1149,7 +1261,7 @@ def test_create_archive_with_atime_option_calls_borg_with_corresponding_paramete
|
|||||||
def test_create_archive_with_flags_option_calls_borg_with_corresponding_parameter(
|
def test_create_archive_with_flags_option_calls_borg_with_corresponding_parameter(
|
||||||
option_value, feature_available, option_flag
|
option_value, feature_available, option_flag
|
||||||
):
|
):
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1189,7 +1301,7 @@ def test_create_archive_with_flags_option_calls_borg_with_corresponding_paramete
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters():
|
def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1229,7 +1341,7 @@ def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters(
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_local_path_calls_borg_via_local_path():
|
def test_create_archive_with_local_path_calls_borg_via_local_path():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1269,7 +1381,7 @@ def test_create_archive_with_local_path_calls_borg_via_local_path():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters():
|
def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1309,7 +1421,7 @@ def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters(
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_umask_calls_borg_with_umask_parameters():
|
def test_create_archive_with_umask_calls_borg_with_umask_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1348,7 +1460,7 @@ def test_create_archive_with_umask_calls_borg_with_umask_parameters():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1387,7 +1499,7 @@ def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_stats_calls_borg_with_stats_parameter_and_warning_output_log_level():
|
def test_create_archive_with_stats_calls_borg_with_stats_parameter_and_warning_output_log_level():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1404,7 +1516,7 @@ def test_create_archive_with_stats_calls_borg_with_stats_parameter_and_warning_o
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--stats') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--stats',),
|
||||||
output_log_level=logging.WARNING,
|
output_log_level=logging.WARNING,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1427,7 +1539,7 @@ def test_create_archive_with_stats_calls_borg_with_stats_parameter_and_warning_o
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_stats_and_log_info_calls_borg_with_stats_parameter_and_info_output_log_level():
|
def test_create_archive_with_stats_and_log_info_calls_borg_with_stats_parameter_and_info_output_log_level():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1444,7 +1556,7 @@ def test_create_archive_with_stats_and_log_info_calls_borg_with_stats_parameter_
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--info', '--stats') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--info', '--stats'),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1468,7 +1580,7 @@ def test_create_archive_with_stats_and_log_info_calls_borg_with_stats_parameter_
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_files_calls_borg_with_list_parameter_and_warning_output_log_level():
|
def test_create_archive_with_files_calls_borg_with_list_parameter_and_warning_output_log_level():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1485,7 +1597,7 @@ def test_create_archive_with_files_calls_borg_with_list_parameter_and_warning_ou
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--list', '--filter', 'AME-') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create', '--list', '--filter', 'AMEx-') + REPO_ARCHIVE_WITH_PATHS,
|
||||||
output_log_level=logging.WARNING,
|
output_log_level=logging.WARNING,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1508,7 +1620,7 @@ def test_create_archive_with_files_calls_borg_with_list_parameter_and_warning_ou
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_files_and_log_info_calls_borg_with_list_parameter_and_info_output_log_level():
|
def test_create_archive_with_files_and_log_info_calls_borg_with_list_parameter_and_info_output_log_level():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1525,7 +1637,7 @@ def test_create_archive_with_files_and_log_info_calls_borg_with_list_parameter_a
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--list', '--filter', 'AME-', '--info') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create', '--list', '--filter', 'AMEx-') + REPO_ARCHIVE_WITH_PATHS + ('--info',),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1549,7 +1661,7 @@ def test_create_archive_with_files_and_log_info_calls_borg_with_list_parameter_a
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_parameter_and_no_list():
|
def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_parameter_and_no_list():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1566,7 +1678,7 @@ def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_para
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--info', '--progress') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--info', '--progress',),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=module.DO_NOT_CAPTURE,
|
output_file=module.DO_NOT_CAPTURE,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1590,7 +1702,7 @@ def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_para
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_progress_calls_borg_with_progress_parameter():
|
def test_create_archive_with_progress_calls_borg_with_progress_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1607,7 +1719,7 @@ def test_create_archive_with_progress_calls_borg_with_progress_parameter():
|
|||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'create', '--progress') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--progress',),
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=module.DO_NOT_CAPTURE,
|
output_file=module.DO_NOT_CAPTURE,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
@@ -1631,7 +1743,7 @@ def test_create_archive_with_progress_calls_borg_with_progress_parameter():
|
|||||||
|
|
||||||
def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progress_parameter():
|
def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progress_parameter():
|
||||||
processes = flexmock()
|
processes = flexmock()
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1647,9 +1759,23 @@ def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progr
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('collect_special_file_paths').and_return(())
|
||||||
|
create_command = (
|
||||||
|
('borg', 'create', '--one-file-system', '--read-special')
|
||||||
|
+ REPO_ARCHIVE_WITH_PATHS
|
||||||
|
+ ('--progress',)
|
||||||
|
)
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
('borg', 'create', '--one-file-system', '--read-special', '--progress')
|
create_command + ('--dry-run', '--list'),
|
||||||
+ REPO_ARCHIVE_WITH_PATHS,
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=module.DO_NOT_CAPTURE,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command,
|
||||||
processes=processes,
|
processes=processes,
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=module.DO_NOT_CAPTURE,
|
output_file=module.DO_NOT_CAPTURE,
|
||||||
@@ -1673,8 +1799,193 @@ def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progr
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_archive_with_stream_processes_ignores_read_special_false_and_logs_warnings():
|
||||||
|
processes = flexmock()
|
||||||
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
|
flexmock(module).should_receive('pattern_root_directories').and_return([])
|
||||||
|
flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
|
||||||
|
flexmock(module).should_receive('expand_home_directories').and_return(())
|
||||||
|
flexmock(module).should_receive('write_pattern_file').and_return(None)
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
flexmock(module).should_receive('ensure_files_readable')
|
||||||
|
flexmock(module.logger).should_receive('warning').twice()
|
||||||
|
flexmock(module).should_receive('make_pattern_flags').and_return(())
|
||||||
|
flexmock(module).should_receive('make_exclude_flags').and_return(())
|
||||||
|
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||||
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
|
)
|
||||||
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('collect_special_file_paths').and_return(())
|
||||||
|
create_command = (
|
||||||
|
'borg',
|
||||||
|
'create',
|
||||||
|
'--one-file-system',
|
||||||
|
'--read-special',
|
||||||
|
) + REPO_ARCHIVE_WITH_PATHS
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command + ('--dry-run', '--list'),
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command,
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
module.create_archive(
|
||||||
|
dry_run=False,
|
||||||
|
repository='repo',
|
||||||
|
location_config={
|
||||||
|
'source_directories': ['foo', 'bar'],
|
||||||
|
'repositories': ['repo'],
|
||||||
|
'exclude_patterns': None,
|
||||||
|
'read_special': False,
|
||||||
|
},
|
||||||
|
storage_config={},
|
||||||
|
local_borg_version='1.2.3',
|
||||||
|
stream_processes=processes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_archive_with_stream_processes_adds_special_files_to_excludes():
|
||||||
|
processes = flexmock()
|
||||||
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
|
flexmock(module).should_receive('pattern_root_directories').and_return([])
|
||||||
|
flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
|
||||||
|
flexmock(module).should_receive('expand_home_directories').and_return(()).and_return(
|
||||||
|
('special',)
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('write_pattern_file').and_return(None).and_return(
|
||||||
|
flexmock(name='/excludes')
|
||||||
|
)
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
flexmock(module).should_receive('ensure_files_readable')
|
||||||
|
flexmock(module).should_receive('make_pattern_flags').and_return(())
|
||||||
|
flexmock(module).should_receive('make_exclude_flags').and_return(()).and_return(
|
||||||
|
'--exclude-from', '/excludes'
|
||||||
|
)
|
||||||
|
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||||
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
|
)
|
||||||
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('collect_special_file_paths').and_return(('special',))
|
||||||
|
create_command = (
|
||||||
|
'borg',
|
||||||
|
'create',
|
||||||
|
'--one-file-system',
|
||||||
|
'--read-special',
|
||||||
|
) + REPO_ARCHIVE_WITH_PATHS
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command + ('--dry-run', '--list'),
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command + ('--exclude-from', '/excludes'),
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
module.create_archive(
|
||||||
|
dry_run=False,
|
||||||
|
repository='repo',
|
||||||
|
location_config={
|
||||||
|
'source_directories': ['foo', 'bar'],
|
||||||
|
'repositories': ['repo'],
|
||||||
|
'exclude_patterns': None,
|
||||||
|
},
|
||||||
|
storage_config={},
|
||||||
|
local_borg_version='1.2.3',
|
||||||
|
stream_processes=processes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_archive_with_stream_processes_and_read_special_does_not_add_special_files_to_excludes():
|
||||||
|
processes = flexmock()
|
||||||
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
|
flexmock(module).should_receive('pattern_root_directories').and_return([])
|
||||||
|
flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
|
||||||
|
flexmock(module).should_receive('expand_home_directories').and_return(()).and_return(
|
||||||
|
('special',)
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('write_pattern_file').and_return(None)
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
flexmock(module).should_receive('ensure_files_readable')
|
||||||
|
flexmock(module).should_receive('make_pattern_flags').and_return(())
|
||||||
|
flexmock(module).should_receive('make_exclude_flags').and_return(())
|
||||||
|
flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
|
||||||
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
|
)
|
||||||
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('collect_special_file_paths').and_return(('special',))
|
||||||
|
create_command = (
|
||||||
|
'borg',
|
||||||
|
'create',
|
||||||
|
'--one-file-system',
|
||||||
|
'--read-special',
|
||||||
|
) + REPO_ARCHIVE_WITH_PATHS
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command + ('--dry-run', '--list'),
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command,
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
module.create_archive(
|
||||||
|
dry_run=False,
|
||||||
|
repository='repo',
|
||||||
|
location_config={
|
||||||
|
'source_directories': ['foo', 'bar'],
|
||||||
|
'repositories': ['repo'],
|
||||||
|
'exclude_patterns': None,
|
||||||
|
'read_special': True,
|
||||||
|
},
|
||||||
|
storage_config={},
|
||||||
|
local_borg_version='1.2.3',
|
||||||
|
stream_processes=processes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_json_calls_borg_with_json_parameter():
|
def test_create_archive_with_json_calls_borg_with_json_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1690,11 +2001,8 @@ def test_create_archive_with_json_calls_borg_with_json_parameter():
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--json',),
|
||||||
output_log_level=None,
|
|
||||||
output_file=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
working_directory=None,
|
working_directory=None,
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
@@ -1716,7 +2024,7 @@ def test_create_archive_with_json_calls_borg_with_json_parameter():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter():
|
def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1732,11 +2040,8 @@ def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter()
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
|
('borg', 'create') + REPO_ARCHIVE_WITH_PATHS + ('--json',),
|
||||||
output_log_level=None,
|
|
||||||
output_file=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
working_directory=None,
|
working_directory=None,
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
@@ -1759,7 +2064,7 @@ def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter()
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_source_directories_glob_expands():
|
def test_create_archive_with_source_directories_glob_expands():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'food'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'food'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1799,7 +2104,7 @@ def test_create_archive_with_source_directories_glob_expands():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_non_matching_source_directories_glob_passes_through():
|
def test_create_archive_with_non_matching_source_directories_glob_passes_through():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo*',))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo*',))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1839,7 +2144,7 @@ def test_create_archive_with_non_matching_source_directories_glob_passes_through
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_glob_calls_borg_with_expanded_directories():
|
def test_create_archive_with_glob_calls_borg_with_expanded_directories():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'food'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'food'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1878,7 +2183,7 @@ def test_create_archive_with_glob_calls_borg_with_expanded_directories():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
|
def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1918,7 +2223,7 @@ def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
|
|||||||
|
|
||||||
def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
|
def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
|
||||||
repository_archive_pattern = 'repo::Documents_{hostname}-{now}'
|
repository_archive_pattern = 'repo::Documents_{hostname}-{now}'
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1958,7 +2263,7 @@ def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
|
|||||||
|
|
||||||
def test_create_archive_with_repository_accepts_borg_placeholders():
|
def test_create_archive_with_repository_accepts_borg_placeholders():
|
||||||
repository_archive_pattern = '{fqdn}::Documents_{hostname}-{now}'
|
repository_archive_pattern = '{fqdn}::Documents_{hostname}-{now}'
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -1997,7 +2302,7 @@ def test_create_archive_with_repository_accepts_borg_placeholders():
|
|||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_extra_borg_options_calls_borg_with_extra_options():
|
def test_create_archive_with_extra_borg_options_calls_borg_with_extra_options():
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -2035,9 +2340,9 @@ def test_create_archive_with_extra_borg_options_calls_borg_with_extra_options():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_create_archive_with_stream_processes_calls_borg_with_processes():
|
def test_create_archive_with_stream_processes_calls_borg_with_processes_and_read_special():
|
||||||
processes = flexmock()
|
processes = flexmock()
|
||||||
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
|
flexmock(module).should_receive('collect_borgmatic_source_directories').and_return([])
|
||||||
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
||||||
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
||||||
flexmock(module).should_receive('expand_directories').and_return(())
|
flexmock(module).should_receive('expand_directories').and_return(())
|
||||||
@@ -2053,8 +2358,24 @@ def test_create_archive_with_stream_processes_calls_borg_with_processes():
|
|||||||
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
(f'repo::{DEFAULT_ARCHIVE_NAME}',)
|
||||||
)
|
)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
flexmock(module).should_receive('collect_special_file_paths').and_return(())
|
||||||
|
create_command = (
|
||||||
|
'borg',
|
||||||
|
'create',
|
||||||
|
'--one-file-system',
|
||||||
|
'--read-special',
|
||||||
|
) + REPO_ARCHIVE_WITH_PATHS
|
||||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
('borg', 'create', '--one-file-system', '--read-special') + REPO_ARCHIVE_WITH_PATHS,
|
create_command + ('--dry-run', 'list'),
|
||||||
|
processes=processes,
|
||||||
|
output_log_level=logging.INFO,
|
||||||
|
output_file=None,
|
||||||
|
borg_local_path='borg',
|
||||||
|
working_directory=None,
|
||||||
|
extra_environment=None,
|
||||||
|
)
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
create_command,
|
||||||
processes=processes,
|
processes=processes,
|
||||||
output_log_level=logging.INFO,
|
output_log_level=logging.INFO,
|
||||||
output_file=None,
|
output_file=None,
|
||||||
|
|||||||
@@ -15,13 +15,6 @@ def insert_execute_command_mock(command, working_directory=None):
|
|||||||
).once()
|
).once()
|
||||||
|
|
||||||
|
|
||||||
def insert_execute_command_output_mock(command, result):
|
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
|
||||||
command, output_log_level=None, borg_local_path=command[0], extra_environment=None,
|
|
||||||
).and_return(result).once()
|
|
||||||
|
|
||||||
|
|
||||||
def test_extract_last_archive_dry_run_calls_borg_with_last_archive():
|
def test_extract_last_archive_dry_run_calls_borg_with_last_archive():
|
||||||
flexmock(module.rlist).should_receive('resolve_archive_name').and_return('archive')
|
flexmock(module.rlist).should_receive('resolve_archive_name').and_return('archive')
|
||||||
insert_execute_command_mock(('borg', 'extract', '--dry-run', 'repo::archive'))
|
insert_execute_command_mock(('borg', 'extract', '--dry-run', 'repo::archive'))
|
||||||
|
|||||||
@@ -53,11 +53,8 @@ def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_outpu
|
|||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'info', '--json', '--repo', 'repo'),
|
('borg', 'info', '--json', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
|
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
@@ -97,11 +94,8 @@ def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_outp
|
|||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'info', '--json', '--repo', 'repo'),
|
('borg', 'info', '--json', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
|
|
||||||
insert_logging_mock(logging.DEBUG)
|
insert_logging_mock(logging.DEBUG)
|
||||||
@@ -120,11 +114,8 @@ def test_display_archives_info_with_json_calls_borg_with_json_parameter():
|
|||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--json',))
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'info', '--json', '--repo', 'repo'),
|
('borg', 'info', '--json', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
|
|
||||||
json_output = module.display_archives_info(
|
json_output = module.display_archives_info(
|
||||||
@@ -137,16 +128,16 @@ def test_display_archives_info_with_json_calls_borg_with_json_parameter():
|
|||||||
assert json_output == '[]'
|
assert json_output == '[]'
|
||||||
|
|
||||||
|
|
||||||
def test_display_archives_info_with_archive_calls_borg_with_glob_archives_parameter():
|
def test_display_archives_info_with_archive_calls_borg_with_match_archives_parameter():
|
||||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||||
flexmock(module.flags).should_receive('make_flags').with_args(
|
flexmock(module.flags).should_receive('make_flags').with_args(
|
||||||
'glob-archives', 'archive'
|
'match-archives', 'archive'
|
||||||
).and_return(('--glob-archives', 'archive'))
|
).and_return(('--match-archives', 'archive'))
|
||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').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'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'info', '--repo', 'repo', '--glob-archives', 'archive'),
|
('borg', 'info', '--repo', 'repo', '--match-archives', 'archive'),
|
||||||
output_log_level=logging.WARNING,
|
output_log_level=logging.WARNING,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
@@ -229,16 +220,16 @@ def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_paramete
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_display_archives_info_with_prefix_calls_borg_with_glob_archives_parameters():
|
def test_display_archives_info_with_prefix_calls_borg_with_match_archives_parameters():
|
||||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||||
flexmock(module.flags).should_receive('make_flags').with_args(
|
flexmock(module.flags).should_receive('make_flags').with_args(
|
||||||
'glob-archives', 'foo*'
|
'match-archives', 'sh:foo*'
|
||||||
).and_return(('--glob-archives', 'foo*'))
|
).and_return(('--match-archives', 'sh:foo*'))
|
||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').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'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'info', '--glob-archives', 'foo*', '--repo', 'repo'),
|
('borg', 'info', '--match-archives', 'sh:foo*', '--repo', 'repo'),
|
||||||
output_log_level=logging.WARNING,
|
output_log_level=logging.WARNING,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
@@ -252,7 +243,7 @@ def test_display_archives_info_with_prefix_calls_borg_with_glob_archives_paramet
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('argument_name', ('glob_archives', 'sort_by', 'first', 'last'))
|
@pytest.mark.parametrize('argument_name', ('match_archives', 'sort_by', 'first', 'last'))
|
||||||
def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
|
def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
|
||||||
flag_name = f"--{argument_name.replace('_', ' ')}"
|
flag_name = f"--{argument_name.replace('_', ' ')}"
|
||||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ def test_make_list_command_includes_short():
|
|||||||
'argument_name',
|
'argument_name',
|
||||||
(
|
(
|
||||||
'prefix',
|
'prefix',
|
||||||
'glob_archives',
|
'match_archives',
|
||||||
'sort_by',
|
'sort_by',
|
||||||
'first',
|
'first',
|
||||||
'last',
|
'last',
|
||||||
@@ -260,7 +260,7 @@ def test_list_archive_calls_borg_with_parameters():
|
|||||||
json=False,
|
json=False,
|
||||||
find_paths=None,
|
find_paths=None,
|
||||||
prefix=None,
|
prefix=None,
|
||||||
glob_archives=None,
|
match_archives=None,
|
||||||
sort_by=None,
|
sort_by=None,
|
||||||
first=None,
|
first=None,
|
||||||
last=None,
|
last=None,
|
||||||
@@ -313,7 +313,7 @@ def test_list_archive_calls_borg_with_local_path():
|
|||||||
json=False,
|
json=False,
|
||||||
find_paths=None,
|
find_paths=None,
|
||||||
prefix=None,
|
prefix=None,
|
||||||
glob_archives=None,
|
match_archives=None,
|
||||||
sort_by=None,
|
sort_by=None,
|
||||||
first=None,
|
first=None,
|
||||||
last=None,
|
last=None,
|
||||||
@@ -353,7 +353,7 @@ def test_list_archive_calls_borg_multiple_times_with_find_paths():
|
|||||||
json=False,
|
json=False,
|
||||||
find_paths=['foo.txt'],
|
find_paths=['foo.txt'],
|
||||||
prefix=None,
|
prefix=None,
|
||||||
glob_archives=None,
|
match_archives=None,
|
||||||
sort_by=None,
|
sort_by=None,
|
||||||
first=None,
|
first=None,
|
||||||
last=None,
|
last=None,
|
||||||
@@ -361,11 +361,8 @@ def test_list_archive_calls_borg_multiple_times_with_find_paths():
|
|||||||
|
|
||||||
flexmock(module.feature).should_receive('available').and_return(False)
|
flexmock(module.feature).should_receive('available').and_return(False)
|
||||||
flexmock(module.rlist).should_receive('make_rlist_command').and_return(('borg', 'list', 'repo'))
|
flexmock(module.rlist).should_receive('make_rlist_command').and_return(('borg', 'list', 'repo'))
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list', 'repo'),
|
('borg', 'list', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('archive1\narchive2').once()
|
).and_return('archive1\narchive2').once()
|
||||||
flexmock(module).should_receive('make_list_command').and_return(
|
flexmock(module).should_receive('make_list_command').and_return(
|
||||||
('borg', 'list', 'repo::archive1')
|
('borg', 'list', 'repo::archive1')
|
||||||
@@ -400,7 +397,7 @@ def test_list_archive_calls_borg_with_archive():
|
|||||||
json=False,
|
json=False,
|
||||||
find_paths=None,
|
find_paths=None,
|
||||||
prefix=None,
|
prefix=None,
|
||||||
glob_archives=None,
|
match_archives=None,
|
||||||
sort_by=None,
|
sort_by=None,
|
||||||
first=None,
|
first=None,
|
||||||
last=None,
|
last=None,
|
||||||
@@ -439,7 +436,7 @@ def test_list_archive_without_archive_delegates_to_list_repository():
|
|||||||
format=None,
|
format=None,
|
||||||
json=None,
|
json=None,
|
||||||
prefix=None,
|
prefix=None,
|
||||||
glob_archives=None,
|
match_archives=None,
|
||||||
sort_by=None,
|
sort_by=None,
|
||||||
first=None,
|
first=None,
|
||||||
last=None,
|
last=None,
|
||||||
@@ -466,7 +463,7 @@ def test_list_archive_with_borg_features_without_archive_delegates_to_list_repos
|
|||||||
format=None,
|
format=None,
|
||||||
json=None,
|
json=None,
|
||||||
prefix=None,
|
prefix=None,
|
||||||
glob_archives=None,
|
match_archives=None,
|
||||||
sort_by=None,
|
sort_by=None,
|
||||||
first=None,
|
first=None,
|
||||||
last=None,
|
last=None,
|
||||||
@@ -487,12 +484,12 @@ def test_list_archive_with_borg_features_without_archive_delegates_to_list_repos
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'archive_filter_flag', ('prefix', 'glob_archives', 'sort_by', 'first', 'last',),
|
'archive_filter_flag', ('prefix', 'match_archives', 'sort_by', 'first', 'last',),
|
||||||
)
|
)
|
||||||
def test_list_archive_with_archive_ignores_archive_filter_flag(archive_filter_flag,):
|
def test_list_archive_with_archive_ignores_archive_filter_flag(archive_filter_flag,):
|
||||||
default_filter_flags = {
|
default_filter_flags = {
|
||||||
'prefix': None,
|
'prefix': None,
|
||||||
'glob_archives': None,
|
'match_archives': None,
|
||||||
'sort_by': None,
|
'sort_by': None,
|
||||||
'first': None,
|
'first': None,
|
||||||
'last': None,
|
'last': None,
|
||||||
@@ -532,14 +529,14 @@ def test_list_archive_with_archive_ignores_archive_filter_flag(archive_filter_fl
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'archive_filter_flag', ('prefix', 'glob_archives', 'sort_by', 'first', 'last',),
|
'archive_filter_flag', ('prefix', 'match_archives', 'sort_by', 'first', 'last',),
|
||||||
)
|
)
|
||||||
def test_list_archive_with_find_paths_allows_archive_filter_flag_but_only_passes_it_to_rlist(
|
def test_list_archive_with_find_paths_allows_archive_filter_flag_but_only_passes_it_to_rlist(
|
||||||
archive_filter_flag,
|
archive_filter_flag,
|
||||||
):
|
):
|
||||||
default_filter_flags = {
|
default_filter_flags = {
|
||||||
'prefix': None,
|
'prefix': None,
|
||||||
'glob_archives': None,
|
'match_archives': None,
|
||||||
'sort_by': None,
|
'sort_by': None,
|
||||||
'first': None,
|
'first': None,
|
||||||
'last': None,
|
'last': None,
|
||||||
@@ -559,11 +556,8 @@ def test_list_archive_with_find_paths_allows_archive_filter_flag_but_only_passes
|
|||||||
remote_path=None,
|
remote_path=None,
|
||||||
).and_return(('borg', 'rlist', '--repo', 'repo'))
|
).and_return(('borg', 'rlist', '--repo', 'repo'))
|
||||||
|
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'rlist', '--repo', 'repo'),
|
('borg', 'rlist', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('archive1\narchive2').once()
|
).and_return('archive1\narchive2').once()
|
||||||
|
|
||||||
flexmock(module).should_receive('make_list_command').with_args(
|
flexmock(module).should_receive('make_list_command').with_args(
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ def test_mount_archive_calls_borg_with_required_flags():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_mount_archive_with_borg_features_calls_borg_with_repository_and_glob_archives_flags():
|
def test_mount_archive_with_borg_features_calls_borg_with_repository_and_match_archives_flags():
|
||||||
flexmock(module.feature).should_receive('available').and_return(True)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
||||||
insert_execute_command_mock(
|
insert_execute_command_mock(
|
||||||
('borg', 'mount', '--repo', 'repo', '--glob-archives', 'archive', '/mnt')
|
('borg', 'mount', '--repo', 'repo', '--match-archives', 'archive', '/mnt')
|
||||||
)
|
)
|
||||||
|
|
||||||
module.mount_archive(
|
module.mount_archive(
|
||||||
|
|||||||
@@ -23,16 +23,29 @@ BASE_PRUNE_FLAGS = (('--keep-daily', '1'), ('--keep-weekly', '2'), ('--keep-mont
|
|||||||
|
|
||||||
def test_make_prune_flags_returns_flags_from_config_plus_default_prefix_glob():
|
def test_make_prune_flags_returns_flags_from_config_plus_default_prefix_glob():
|
||||||
retention_config = OrderedDict((('keep_daily', 1), ('keep_weekly', 2), ('keep_monthly', 3)))
|
retention_config = OrderedDict((('keep_daily', 1), ('keep_weekly', 2), ('keep_monthly', 3)))
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
result = module.make_prune_flags(retention_config)
|
result = module.make_prune_flags(retention_config, local_borg_version='1.2.3')
|
||||||
|
|
||||||
assert tuple(result) == BASE_PRUNE_FLAGS + (('--glob-archives', '{hostname}-*'),)
|
assert tuple(result) == BASE_PRUNE_FLAGS + (('--match-archives', 'sh:{hostname}-*'),)
|
||||||
|
|
||||||
|
|
||||||
def test_make_prune_flags_accepts_prefix_with_placeholders():
|
def test_make_prune_flags_accepts_prefix_with_placeholders():
|
||||||
retention_config = OrderedDict((('keep_daily', 1), ('prefix', 'Documents_{hostname}-{now}')))
|
retention_config = OrderedDict((('keep_daily', 1), ('prefix', 'Documents_{hostname}-{now}')))
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
result = module.make_prune_flags(retention_config)
|
result = module.make_prune_flags(retention_config, local_borg_version='1.2.3')
|
||||||
|
|
||||||
|
expected = (('--keep-daily', '1'), ('--match-archives', 'sh:Documents_{hostname}-{now}*'))
|
||||||
|
|
||||||
|
assert tuple(result) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_make_prune_flags_with_prefix_without_borg_features_uses_glob_archives():
|
||||||
|
retention_config = OrderedDict((('keep_daily', 1), ('prefix', 'Documents_{hostname}-{now}')))
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(False)
|
||||||
|
|
||||||
|
result = module.make_prune_flags(retention_config, local_borg_version='1.2.3')
|
||||||
|
|
||||||
expected = (('--keep-daily', '1'), ('--glob-archives', 'Documents_{hostname}-{now}*'))
|
expected = (('--keep-daily', '1'), ('--glob-archives', 'Documents_{hostname}-{now}*'))
|
||||||
|
|
||||||
@@ -41,8 +54,9 @@ def test_make_prune_flags_accepts_prefix_with_placeholders():
|
|||||||
|
|
||||||
def test_make_prune_flags_treats_empty_prefix_as_no_prefix():
|
def test_make_prune_flags_treats_empty_prefix_as_no_prefix():
|
||||||
retention_config = OrderedDict((('keep_daily', 1), ('prefix', '')))
|
retention_config = OrderedDict((('keep_daily', 1), ('prefix', '')))
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
result = module.make_prune_flags(retention_config)
|
result = module.make_prune_flags(retention_config, local_borg_version='1.2.3')
|
||||||
|
|
||||||
expected = (('--keep-daily', '1'),)
|
expected = (('--keep-daily', '1'),)
|
||||||
|
|
||||||
@@ -51,8 +65,9 @@ def test_make_prune_flags_treats_empty_prefix_as_no_prefix():
|
|||||||
|
|
||||||
def test_make_prune_flags_treats_none_prefix_as_no_prefix():
|
def test_make_prune_flags_treats_none_prefix_as_no_prefix():
|
||||||
retention_config = OrderedDict((('keep_daily', 1), ('prefix', None)))
|
retention_config = OrderedDict((('keep_daily', 1), ('prefix', None)))
|
||||||
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
|
|
||||||
result = module.make_prune_flags(retention_config)
|
result = module.make_prune_flags(retention_config, local_borg_version='1.2.3')
|
||||||
|
|
||||||
expected = (('--keep-daily', '1'),)
|
expected = (('--keep-daily', '1'),)
|
||||||
|
|
||||||
@@ -63,10 +78,7 @@ PRUNE_COMMAND = ('borg', 'prune', '--keep-daily', '1', '--keep-weekly', '2', '--
|
|||||||
|
|
||||||
|
|
||||||
def test_prune_archives_calls_borg_with_parameters():
|
def test_prune_archives_calls_borg_with_parameters():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('repo',), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('repo',), logging.INFO)
|
||||||
|
|
||||||
@@ -74,16 +86,13 @@ def test_prune_archives_calls_borg_with_parameters():
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_log_info_calls_borg_with_info_parameter():
|
def test_prune_archives_with_log_info_calls_borg_with_info_parameter():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--info', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--info', 'repo'), logging.INFO)
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
@@ -92,16 +101,13 @@ def test_prune_archives_with_log_info_calls_borg_with_info_parameter():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_log_debug_calls_borg_with_debug_parameter():
|
def test_prune_archives_with_log_debug_calls_borg_with_debug_parameter():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--debug', '--show-rc', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--debug', '--show-rc', 'repo'), logging.INFO)
|
||||||
insert_logging_mock(logging.DEBUG)
|
insert_logging_mock(logging.DEBUG)
|
||||||
@@ -110,16 +116,13 @@ def test_prune_archives_with_log_debug_calls_borg_with_debug_parameter():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_dry_run_calls_borg_with_dry_run_parameter():
|
def test_prune_archives_with_dry_run_calls_borg_with_dry_run_parameter():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--dry-run', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--dry-run', 'repo'), logging.INFO)
|
||||||
|
|
||||||
@@ -127,16 +130,13 @@ def test_prune_archives_with_dry_run_calls_borg_with_dry_run_parameter():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
dry_run=True,
|
dry_run=True,
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_local_path_calls_borg_via_local_path():
|
def test_prune_archives_with_local_path_calls_borg_via_local_path():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(('borg1',) + PRUNE_COMMAND[1:] + ('repo',), logging.INFO)
|
insert_execute_command_mock(('borg1',) + PRUNE_COMMAND[1:] + ('repo',), logging.INFO)
|
||||||
|
|
||||||
@@ -144,17 +144,14 @@ def test_prune_archives_with_local_path_calls_borg_via_local_path():
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
local_path='borg1',
|
local_path='borg1',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_remote_path_calls_borg_with_remote_path_parameters():
|
def test_prune_archives_with_remote_path_calls_borg_with_remote_path_parameters():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--remote-path', 'borg1', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--remote-path', 'borg1', 'repo'), logging.INFO)
|
||||||
|
|
||||||
@@ -162,17 +159,14 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_parameters(
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
remote_path='borg1',
|
remote_path='borg1',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_stats_calls_borg_with_stats_parameter_and_warning_output_log_level():
|
def test_prune_archives_with_stats_calls_borg_with_stats_parameter_and_warning_output_log_level():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--stats', 'repo'), logging.WARNING)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--stats', 'repo'), logging.WARNING)
|
||||||
|
|
||||||
@@ -180,17 +174,14 @@ def test_prune_archives_with_stats_calls_borg_with_stats_parameter_and_warning_o
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
stats=True,
|
stats=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_stats_and_log_info_calls_borg_with_stats_parameter_and_info_output_log_level():
|
def test_prune_archives_with_stats_and_log_info_calls_borg_with_stats_parameter_and_info_output_log_level():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--stats', '--info', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--stats', '--info', 'repo'), logging.INFO)
|
||||||
@@ -199,17 +190,14 @@ def test_prune_archives_with_stats_and_log_info_calls_borg_with_stats_parameter_
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
stats=True,
|
stats=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_files_calls_borg_with_list_parameter_and_warning_output_log_level():
|
def test_prune_archives_with_files_calls_borg_with_list_parameter_and_warning_output_log_level():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--list', 'repo'), logging.WARNING)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--list', 'repo'), logging.WARNING)
|
||||||
|
|
||||||
@@ -217,17 +205,14 @@ def test_prune_archives_with_files_calls_borg_with_list_parameter_and_warning_ou
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
list_archives=True,
|
list_archives=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_files_and_log_info_calls_borg_with_list_parameter_and_info_output_log_level():
|
def test_prune_archives_with_files_and_log_info_calls_borg_with_list_parameter_and_info_output_log_level():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--info', '--list', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--info', '--list', 'repo'), logging.INFO)
|
||||||
@@ -236,7 +221,7 @@ def test_prune_archives_with_files_and_log_info_calls_borg_with_list_parameter_a
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
list_archives=True,
|
list_archives=True,
|
||||||
)
|
)
|
||||||
@@ -244,10 +229,7 @@ def test_prune_archives_with_files_and_log_info_calls_borg_with_list_parameter_a
|
|||||||
|
|
||||||
def test_prune_archives_with_umask_calls_borg_with_umask_parameters():
|
def test_prune_archives_with_umask_calls_borg_with_umask_parameters():
|
||||||
storage_config = {'umask': '077'}
|
storage_config = {'umask': '077'}
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--umask', '077', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--umask', '077', 'repo'), logging.INFO)
|
||||||
|
|
||||||
@@ -255,17 +237,14 @@ def test_prune_archives_with_umask_calls_borg_with_umask_parameters():
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config=storage_config,
|
storage_config=storage_config,
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
||||||
storage_config = {'lock_wait': 5}
|
storage_config = {'lock_wait': 5}
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--lock-wait', '5', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--lock-wait', '5', 'repo'), logging.INFO)
|
||||||
|
|
||||||
@@ -273,16 +252,13 @@ def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config=storage_config,
|
storage_config=storage_config,
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
|
def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
|
||||||
retention_config = flexmock()
|
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
|
||||||
flexmock(module).should_receive('make_prune_flags').with_args(retention_config).and_return(
|
|
||||||
BASE_PRUNE_FLAGS
|
|
||||||
)
|
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
insert_execute_command_mock(PRUNE_COMMAND + ('--extra', '--options', 'repo'), logging.INFO)
|
insert_execute_command_mock(PRUNE_COMMAND + ('--extra', '--options', 'repo'), logging.INFO)
|
||||||
|
|
||||||
@@ -290,6 +266,6 @@ def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
|
|||||||
dry_run=False,
|
dry_run=False,
|
||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={'extra_borg_options': {'prune': '--extra --options'}},
|
storage_config={'extra_borg_options': {'prune': '--extra --options'}},
|
||||||
retention_config=retention_config,
|
retention_config=flexmock(),
|
||||||
local_borg_version='1.2.3',
|
local_borg_version='1.2.3',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -68,11 +68,8 @@ def test_display_repository_info_with_log_info_and_json_suppresses_most_borg_out
|
|||||||
flexmock(module.feature).should_receive('available').and_return(True)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'rinfo', '--json', '--repo', 'repo'),
|
('borg', 'rinfo', '--json', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
|
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
@@ -110,11 +107,8 @@ def test_display_repository_info_with_log_debug_and_json_suppresses_most_borg_ou
|
|||||||
flexmock(module.feature).should_receive('available').and_return(True)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'rinfo', '--json', '--repo', 'repo'),
|
('borg', 'rinfo', '--json', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
|
|
||||||
insert_logging_mock(logging.DEBUG)
|
insert_logging_mock(logging.DEBUG)
|
||||||
@@ -132,11 +126,8 @@ def test_display_repository_info_with_json_calls_borg_with_json_parameter():
|
|||||||
flexmock(module.feature).should_receive('available').and_return(True)
|
flexmock(module.feature).should_receive('available').and_return(True)
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo',))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'rinfo', '--json', '--repo', 'repo'),
|
('borg', 'rinfo', '--json', '--repo', 'repo'), extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('[]')
|
).and_return('[]')
|
||||||
|
|
||||||
json_output = module.display_repository_info(
|
json_output = module.display_repository_info(
|
||||||
|
|||||||
@@ -28,11 +28,8 @@ def test_resolve_archive_name_passes_through_non_latest_archive_name():
|
|||||||
def test_resolve_archive_name_calls_borg_with_parameters():
|
def test_resolve_archive_name_calls_borg_with_parameters():
|
||||||
expected_archive = 'archive-name'
|
expected_archive = 'archive-name'
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg', 'list') + BORG_LIST_LATEST_ARGUMENTS, extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return(expected_archive + '\n')
|
).and_return(expected_archive + '\n')
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@@ -41,14 +38,11 @@ def test_resolve_archive_name_calls_borg_with_parameters():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_archive_name_with_log_info_calls_borg_with_info_parameter():
|
def test_resolve_archive_name_with_log_info_calls_borg_without_info_parameter():
|
||||||
expected_archive = 'archive-name'
|
expected_archive = 'archive-name'
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list', '--info') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg', 'list') + BORG_LIST_LATEST_ARGUMENTS, extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return(expected_archive + '\n')
|
).and_return(expected_archive + '\n')
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
|
|
||||||
@@ -58,14 +52,11 @@ def test_resolve_archive_name_with_log_info_calls_borg_with_info_parameter():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_resolve_archive_name_with_log_debug_calls_borg_with_debug_parameter():
|
def test_resolve_archive_name_with_log_debug_calls_borg_without_debug_parameter():
|
||||||
expected_archive = 'archive-name'
|
expected_archive = 'archive-name'
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list', '--debug', '--show-rc') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg', 'list') + BORG_LIST_LATEST_ARGUMENTS, extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return(expected_archive + '\n')
|
).and_return(expected_archive + '\n')
|
||||||
insert_logging_mock(logging.DEBUG)
|
insert_logging_mock(logging.DEBUG)
|
||||||
|
|
||||||
@@ -78,11 +69,8 @@ def test_resolve_archive_name_with_log_debug_calls_borg_with_debug_parameter():
|
|||||||
def test_resolve_archive_name_with_local_path_calls_borg_via_local_path():
|
def test_resolve_archive_name_with_local_path_calls_borg_via_local_path():
|
||||||
expected_archive = 'archive-name'
|
expected_archive = 'archive-name'
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg1', 'list') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg1', 'list') + BORG_LIST_LATEST_ARGUMENTS, extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg1',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return(expected_archive + '\n')
|
).and_return(expected_archive + '\n')
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@@ -96,10 +84,8 @@ def test_resolve_archive_name_with_local_path_calls_borg_via_local_path():
|
|||||||
def test_resolve_archive_name_with_remote_path_calls_borg_with_remote_path_parameters():
|
def test_resolve_archive_name_with_remote_path_calls_borg_with_remote_path_parameters():
|
||||||
expected_archive = 'archive-name'
|
expected_archive = 'archive-name'
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list', '--remote-path', 'borg1') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg', 'list', '--remote-path', 'borg1') + BORG_LIST_LATEST_ARGUMENTS,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
).and_return(expected_archive + '\n')
|
).and_return(expected_archive + '\n')
|
||||||
|
|
||||||
@@ -113,11 +99,8 @@ def test_resolve_archive_name_with_remote_path_calls_borg_with_remote_path_param
|
|||||||
|
|
||||||
def test_resolve_archive_name_without_archives_raises():
|
def test_resolve_archive_name_without_archives_raises():
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg', 'list') + BORG_LIST_LATEST_ARGUMENTS, extra_environment=None,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
|
||||||
).and_return('')
|
).and_return('')
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@@ -128,10 +111,8 @@ def test_resolve_archive_name_with_lock_wait_calls_borg_with_lock_wait_parameter
|
|||||||
expected_archive = 'archive-name'
|
expected_archive = 'archive-name'
|
||||||
|
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('borg', 'list', '--lock-wait', 'okay') + BORG_LIST_LATEST_ARGUMENTS,
|
('borg', 'list', '--lock-wait', 'okay') + BORG_LIST_LATEST_ARGUMENTS,
|
||||||
output_log_level=None,
|
|
||||||
borg_local_path='borg',
|
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
).and_return(expected_archive + '\n')
|
).and_return(expected_archive + '\n')
|
||||||
|
|
||||||
@@ -273,9 +254,9 @@ def test_make_rlist_command_includes_remote_path():
|
|||||||
assert command == ('borg', 'list', '--remote-path', 'borg2', 'repo')
|
assert command == ('borg', 'list', '--remote-path', 'borg2', 'repo')
|
||||||
|
|
||||||
|
|
||||||
def test_make_rlist_command_transforms_prefix_into_glob_archives():
|
def test_make_rlist_command_transforms_prefix_into_match_archives():
|
||||||
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
|
flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
|
||||||
('--glob-archives', 'foo*')
|
('--match-archives', 'sh:foo*')
|
||||||
)
|
)
|
||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
|
||||||
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
|
||||||
@@ -287,7 +268,7 @@ def test_make_rlist_command_transforms_prefix_into_glob_archives():
|
|||||||
rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix='foo'),
|
rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix='foo'),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert command == ('borg', 'list', '--glob-archives', 'foo*', 'repo')
|
assert command == ('borg', 'list', '--match-archives', 'sh:foo*', 'repo')
|
||||||
|
|
||||||
|
|
||||||
def test_make_rlist_command_includes_short():
|
def test_make_rlist_command_includes_short():
|
||||||
@@ -308,7 +289,7 @@ def test_make_rlist_command_includes_short():
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'argument_name',
|
'argument_name',
|
||||||
(
|
(
|
||||||
'glob_archives',
|
'match_archives',
|
||||||
'sort_by',
|
'sort_by',
|
||||||
'first',
|
'first',
|
||||||
'last',
|
'last',
|
||||||
@@ -385,7 +366,7 @@ def test_list_repository_with_json_returns_borg_output():
|
|||||||
remote_path=None,
|
remote_path=None,
|
||||||
).and_return(('borg', 'rlist', 'repo'))
|
).and_return(('borg', 'rlist', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').and_return(json_output)
|
flexmock(module).should_receive('execute_command_and_capture_output').and_return(json_output)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
module.list_repository(
|
module.list_repository(
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def test_transfer_archives_calls_borg_with_flags():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ def test_transfer_archives_with_dry_run_calls_borg_with_dry_run_flag():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ def test_transfer_archives_with_log_info_calls_borg_with_info_flag():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -92,20 +92,20 @@ def test_transfer_archives_with_log_debug_calls_borg_with_debug_flag():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_transfer_archives_with_archive_calls_borg_with_glob_archives_flag():
|
def test_transfer_archives_with_archive_calls_borg_with_match_archives_flag():
|
||||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||||
flexmock(module.flags).should_receive('make_flags').with_args(
|
flexmock(module.flags).should_receive('make_flags').with_args(
|
||||||
'glob-archives', 'archive'
|
'match-archives', 'archive'
|
||||||
).and_return(('--glob-archives', 'archive'))
|
).and_return(('--match-archives', 'archive'))
|
||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').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'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'transfer', '--glob-archives', 'archive', '--repo', 'repo'),
|
('borg', 'transfer', '--match-archives', 'archive', '--repo', 'repo'),
|
||||||
output_log_level=logging.WARNING,
|
output_log_level=logging.WARNING,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
@@ -116,20 +116,20 @@ def test_transfer_archives_with_archive_calls_borg_with_glob_archives_flag():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive='archive', glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive='archive', match_archives=None, source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_transfer_archives_with_glob_archives_calls_borg_with_glob_archives_flag():
|
def test_transfer_archives_with_match_archives_calls_borg_with_match_archives_flag():
|
||||||
flexmock(module.flags).should_receive('make_flags').and_return(())
|
flexmock(module.flags).should_receive('make_flags').and_return(())
|
||||||
flexmock(module.flags).should_receive('make_flags').with_args(
|
flexmock(module.flags).should_receive('make_flags').with_args(
|
||||||
'glob-archives', 'foo*'
|
'match-archives', 'sh:foo*'
|
||||||
).and_return(('--glob-archives', 'foo*'))
|
).and_return(('--match-archives', 'sh:foo*'))
|
||||||
flexmock(module.flags).should_receive('make_flags_from_arguments').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'))
|
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
('borg', 'transfer', '--glob-archives', 'foo*', '--repo', 'repo'),
|
('borg', 'transfer', '--match-archives', 'sh:foo*', '--repo', 'repo'),
|
||||||
output_log_level=logging.WARNING,
|
output_log_level=logging.WARNING,
|
||||||
borg_local_path='borg',
|
borg_local_path='borg',
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
@@ -140,7 +140,7 @@ def test_transfer_archives_with_glob_archives_calls_borg_with_glob_archives_flag
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives='foo*', source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives='sh:foo*', source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ def test_transfer_archives_with_local_path_calls_borg_via_local_path():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
local_path='borg2',
|
local_path='borg2',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ def test_transfer_archives_with_remote_path_calls_borg_with_remote_path_flags():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
remote_path='borg2',
|
remote_path='borg2',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ def test_transfer_archives_with_lock_wait_calls_borg_with_lock_wait_flags():
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config=storage_config,
|
storage_config=storage_config,
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository=None),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository=None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ def test_transfer_archives_passes_through_arguments_to_borg(argument_name):
|
|||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(
|
transfer_arguments=flexmock(
|
||||||
archive=None, glob_archives=None, source_repository=None, **{argument_name: 'value'}
|
archive=None, match_archives=None, source_repository=None, **{argument_name: 'value'}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -263,5 +263,5 @@ def test_transfer_archives_with_source_repository_calls_borg_with_other_repo_fla
|
|||||||
repository='repo',
|
repository='repo',
|
||||||
storage_config={},
|
storage_config={},
|
||||||
local_borg_version='2.3.4',
|
local_borg_version='2.3.4',
|
||||||
transfer_arguments=flexmock(archive=None, glob_archives=None, source_repository='other'),
|
transfer_arguments=flexmock(archive=None, match_archives=None, source_repository='other'),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,22 +10,24 @@ from ..test_verbosity import insert_logging_mock
|
|||||||
VERSION = '1.2.3'
|
VERSION = '1.2.3'
|
||||||
|
|
||||||
|
|
||||||
def insert_execute_command_mock(command, borg_local_path='borg', version_output=f'borg {VERSION}'):
|
def insert_execute_command_and_capture_output_mock(
|
||||||
|
command, borg_local_path='borg', version_output=f'borg {VERSION}'
|
||||||
|
):
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
command, output_log_level=None, borg_local_path=borg_local_path, extra_environment=None,
|
command, extra_environment=None,
|
||||||
).once().and_return(version_output)
|
).once().and_return(version_output)
|
||||||
|
|
||||||
|
|
||||||
def test_local_borg_version_calls_borg_with_required_parameters():
|
def test_local_borg_version_calls_borg_with_required_parameters():
|
||||||
insert_execute_command_mock(('borg', '--version'))
|
insert_execute_command_and_capture_output_mock(('borg', '--version'))
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
|
||||||
assert module.local_borg_version({}) == VERSION
|
assert module.local_borg_version({}) == VERSION
|
||||||
|
|
||||||
|
|
||||||
def test_local_borg_version_with_log_info_calls_borg_with_info_parameter():
|
def test_local_borg_version_with_log_info_calls_borg_with_info_parameter():
|
||||||
insert_execute_command_mock(('borg', '--version', '--info'))
|
insert_execute_command_and_capture_output_mock(('borg', '--version', '--info'))
|
||||||
insert_logging_mock(logging.INFO)
|
insert_logging_mock(logging.INFO)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ def test_local_borg_version_with_log_info_calls_borg_with_info_parameter():
|
|||||||
|
|
||||||
|
|
||||||
def test_local_borg_version_with_log_debug_calls_borg_with_debug_parameters():
|
def test_local_borg_version_with_log_debug_calls_borg_with_debug_parameters():
|
||||||
insert_execute_command_mock(('borg', '--version', '--debug', '--show-rc'))
|
insert_execute_command_and_capture_output_mock(('borg', '--version', '--debug', '--show-rc'))
|
||||||
insert_logging_mock(logging.DEBUG)
|
insert_logging_mock(logging.DEBUG)
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
|
||||||
@@ -41,14 +43,14 @@ def test_local_borg_version_with_log_debug_calls_borg_with_debug_parameters():
|
|||||||
|
|
||||||
|
|
||||||
def test_local_borg_version_with_local_borg_path_calls_borg_with_it():
|
def test_local_borg_version_with_local_borg_path_calls_borg_with_it():
|
||||||
insert_execute_command_mock(('borg1', '--version'), borg_local_path='borg1')
|
insert_execute_command_and_capture_output_mock(('borg1', '--version'), borg_local_path='borg1')
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
|
||||||
assert module.local_borg_version({}, 'borg1') == VERSION
|
assert module.local_borg_version({}, 'borg1') == VERSION
|
||||||
|
|
||||||
|
|
||||||
def test_local_borg_version_with_invalid_version_raises():
|
def test_local_borg_version_with_invalid_version_raises():
|
||||||
insert_execute_command_mock(('borg', '--version'), version_output='wtf')
|
insert_execute_command_and_capture_output_mock(('borg', '--version'), version_output='wtf')
|
||||||
flexmock(module.environment).should_receive('make_environment')
|
flexmock(module.environment).should_receive('make_environment')
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
|
|||||||
@@ -455,7 +455,8 @@ def test_run_actions_executes_and_calls_hooks_for_create_action():
|
|||||||
flexmock(module.command).should_receive('execute_hook').times(
|
flexmock(module.command).should_receive('execute_hook').times(
|
||||||
4
|
4
|
||||||
) # Before/after extract and before/after actions.
|
) # Before/after extract and before/after actions.
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').and_return({}).times(3)
|
flexmock(module.dispatch).should_receive('call_hooks').and_return({})
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks_even_if_unconfigured').and_return({})
|
||||||
arguments = {
|
arguments = {
|
||||||
'global': flexmock(monitoring_verbosity=1, dry_run=False),
|
'global': flexmock(monitoring_verbosity=1, dry_run=False),
|
||||||
'create': flexmock(
|
'create': flexmock(
|
||||||
@@ -712,6 +713,31 @@ def test_run_actions_does_not_raise_for_info_action():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_actions_does_not_raise_for_break_lock_action():
|
||||||
|
flexmock(module.validate).should_receive('repositories_match').and_return(True)
|
||||||
|
flexmock(module.borg_break_lock).should_receive('break_lock')
|
||||||
|
arguments = {
|
||||||
|
'global': flexmock(monitoring_verbosity=1, dry_run=False),
|
||||||
|
'break-lock': flexmock(repository=flexmock()),
|
||||||
|
}
|
||||||
|
|
||||||
|
list(
|
||||||
|
module.run_actions(
|
||||||
|
arguments=arguments,
|
||||||
|
config_filename='test.yaml',
|
||||||
|
location={'repositories': ['repo']},
|
||||||
|
storage={},
|
||||||
|
retention={},
|
||||||
|
consistency={},
|
||||||
|
hooks={},
|
||||||
|
local_path=None,
|
||||||
|
remote_path=None,
|
||||||
|
local_borg_version=None,
|
||||||
|
repository_path='repo',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_run_actions_does_not_raise_for_borg_action():
|
def test_run_actions_does_not_raise_for_borg_action():
|
||||||
flexmock(module.validate).should_receive('repositories_match').and_return(True)
|
flexmock(module.validate).should_receive('repositories_match').and_return(True)
|
||||||
flexmock(module.borg_rlist).should_receive('resolve_archive_name').and_return(flexmock())
|
flexmock(module.borg_rlist).should_receive('resolve_archive_name').and_return(flexmock())
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ from borgmatic.config import normalize as module
|
|||||||
{'location': {'source_directories': ['foo', 'bar']}},
|
{'location': {'source_directories': ['foo', 'bar']}},
|
||||||
False,
|
False,
|
||||||
),
|
),
|
||||||
|
({'location': None}, {'location': None}, False,),
|
||||||
(
|
(
|
||||||
{'storage': {'compression': 'yes_please'}},
|
{'storage': {'compression': 'yes_please'}},
|
||||||
{'storage': {'compression': 'yes_please'}},
|
{'storage': {'compression': 'yes_please'}},
|
||||||
False,
|
False,
|
||||||
),
|
),
|
||||||
|
({'storage': None}, {'storage': None}, False,),
|
||||||
(
|
(
|
||||||
{'hooks': {'healthchecks': 'https://example.com'}},
|
{'hooks': {'healthchecks': 'https://example.com'}},
|
||||||
{'hooks': {'healthchecks': {'ping_url': 'https://example.com'}}},
|
{'hooks': {'healthchecks': {'ping_url': 'https://example.com'}}},
|
||||||
@@ -46,11 +48,18 @@ from borgmatic.config import normalize as module
|
|||||||
{'hooks': {'cronhub': {'ping_url': 'https://example.com'}}},
|
{'hooks': {'cronhub': {'ping_url': 'https://example.com'}}},
|
||||||
False,
|
False,
|
||||||
),
|
),
|
||||||
|
({'hooks': None}, {'hooks': None}, False,),
|
||||||
(
|
(
|
||||||
{'consistency': {'checks': ['archives']}},
|
{'consistency': {'checks': ['archives']}},
|
||||||
{'consistency': {'checks': [{'name': 'archives'}]}},
|
{'consistency': {'checks': [{'name': 'archives'}]}},
|
||||||
False,
|
False,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{'consistency': {'checks': ['archives']}},
|
||||||
|
{'consistency': {'checks': [{'name': 'archives'}]}},
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
({'consistency': None}, {'consistency': None}, False,),
|
||||||
({'location': {'numeric_owner': False}}, {'location': {'numeric_ids': False}}, False,),
|
({'location': {'numeric_owner': False}}, {'location': {'numeric_ids': False}}, False,),
|
||||||
({'location': {'bsd_flags': False}}, {'location': {'flags': False}}, False,),
|
({'location': {'bsd_flags': False}}, {'location': {'flags': False}}, False,),
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -27,13 +27,18 @@ def test_call_hook_invokes_module_function_with_arguments_and_returns_value():
|
|||||||
assert return_value == expected_return_value
|
assert return_value == expected_return_value
|
||||||
|
|
||||||
|
|
||||||
def test_call_hook_without_hook_config_skips_call():
|
def test_call_hook_without_hook_config_invokes_module_function_with_arguments_and_returns_value():
|
||||||
hooks = {'other_hook': flexmock()}
|
hooks = {'other_hook': flexmock()}
|
||||||
|
expected_return_value = flexmock()
|
||||||
test_module = sys.modules[__name__]
|
test_module = sys.modules[__name__]
|
||||||
flexmock(module).HOOK_NAME_TO_MODULE = {'super_hook': test_module}
|
flexmock(module).HOOK_NAME_TO_MODULE = {'super_hook': test_module}
|
||||||
flexmock(test_module).should_receive('hook_function').never()
|
flexmock(test_module).should_receive('hook_function').with_args(
|
||||||
|
{}, 'prefix', 55, value=66
|
||||||
|
).and_return(expected_return_value).once()
|
||||||
|
|
||||||
module.call_hook('hook_function', hooks, 'prefix', 'super_hook', 55, value=66)
|
return_value = module.call_hook('hook_function', hooks, 'prefix', 'super_hook', 55, value=66)
|
||||||
|
|
||||||
|
assert return_value == expected_return_value
|
||||||
|
|
||||||
|
|
||||||
def test_call_hook_without_corresponding_module_raises():
|
def test_call_hook_without_corresponding_module_raises():
|
||||||
@@ -76,3 +81,31 @@ def test_call_hooks_calls_skips_return_values_for_null_hooks():
|
|||||||
return_values = module.call_hooks('do_stuff', hooks, 'prefix', ('super_hook', 'other_hook'), 55)
|
return_values = module.call_hooks('do_stuff', hooks, 'prefix', ('super_hook', 'other_hook'), 55)
|
||||||
|
|
||||||
assert return_values == expected_return_values
|
assert return_values == expected_return_values
|
||||||
|
|
||||||
|
|
||||||
|
def test_call_hooks_even_if_unconfigured_calls_each_hook_and_collects_return_values():
|
||||||
|
hooks = {'super_hook': flexmock(), 'other_hook': flexmock()}
|
||||||
|
expected_return_values = {'super_hook': flexmock(), 'other_hook': flexmock()}
|
||||||
|
flexmock(module).should_receive('call_hook').and_return(
|
||||||
|
expected_return_values['super_hook']
|
||||||
|
).and_return(expected_return_values['other_hook'])
|
||||||
|
|
||||||
|
return_values = module.call_hooks_even_if_unconfigured(
|
||||||
|
'do_stuff', hooks, 'prefix', ('super_hook', 'other_hook'), 55
|
||||||
|
)
|
||||||
|
|
||||||
|
assert return_values == expected_return_values
|
||||||
|
|
||||||
|
|
||||||
|
def test_call_hooks_even_if_unconfigured_calls_each_hook_configured_or_not_and_collects_return_values():
|
||||||
|
hooks = {'other_hook': flexmock()}
|
||||||
|
expected_return_values = {'super_hook': flexmock(), 'other_hook': flexmock()}
|
||||||
|
flexmock(module).should_receive('call_hook').and_return(
|
||||||
|
expected_return_values['super_hook']
|
||||||
|
).and_return(expected_return_values['other_hook'])
|
||||||
|
|
||||||
|
return_values = module.call_hooks_even_if_unconfigured(
|
||||||
|
'do_stuff', hooks, 'prefix', ('super_hook', 'other_hook'), 55
|
||||||
|
)
|
||||||
|
|
||||||
|
assert return_values == expected_return_values
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ def test_database_names_to_dump_queries_mysql_for_database_names():
|
|||||||
extra_environment = flexmock()
|
extra_environment = flexmock()
|
||||||
log_prefix = ''
|
log_prefix = ''
|
||||||
dry_run_label = ''
|
dry_run_label = ''
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
('mysql', '--skip-column-names', '--batch', '--execute', 'show schemas'),
|
('mysql', '--skip-column-names', '--batch', '--execute', 'show schemas'),
|
||||||
output_log_level=None,
|
|
||||||
extra_environment=extra_environment,
|
extra_environment=extra_environment,
|
||||||
).and_return('foo\nbar\nmysql\n').once()
|
).and_return('foo\nbar\nmysql\n').once()
|
||||||
|
|
||||||
@@ -200,7 +199,7 @@ def test_dump_databases_runs_mysqldump_for_all_databases():
|
|||||||
|
|
||||||
def test_database_names_to_dump_runs_mysql_with_list_options():
|
def test_database_names_to_dump_runs_mysql_with_list_options():
|
||||||
database = {'name': 'all', 'list_options': '--defaults-extra-file=my.cnf'}
|
database = {'name': 'all', 'list_options': '--defaults-extra-file=my.cnf'}
|
||||||
flexmock(module).should_receive('execute_command').with_args(
|
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||||
(
|
(
|
||||||
'mysql',
|
'mysql',
|
||||||
'--defaults-extra-file=my.cnf',
|
'--defaults-extra-file=my.cnf',
|
||||||
@@ -209,7 +208,6 @@ def test_database_names_to_dump_runs_mysql_with_list_options():
|
|||||||
'--execute',
|
'--execute',
|
||||||
'show schemas',
|
'show schemas',
|
||||||
),
|
),
|
||||||
output_log_level=None,
|
|
||||||
extra_environment=None,
|
extra_environment=None,
|
||||||
).and_return(('foo\nbar')).once()
|
).and_return(('foo\nbar')).once()
|
||||||
|
|
||||||
|
|||||||
@@ -223,6 +223,36 @@ def test_dump_databases_runs_pg_dumpall_for_all_databases():
|
|||||||
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=False) == [process]
|
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=False) == [process]
|
||||||
|
|
||||||
|
|
||||||
|
def test_dump_databases_runs_non_default_pg_dump():
|
||||||
|
databases = [{'name': 'foo', 'pg_dump_command': 'special_pg_dump'}]
|
||||||
|
process = flexmock()
|
||||||
|
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||||
|
flexmock(module.dump).should_receive('make_database_dump_filename').and_return(
|
||||||
|
'databases/localhost/foo'
|
||||||
|
)
|
||||||
|
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
|
|
||||||
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
|
(
|
||||||
|
'special_pg_dump',
|
||||||
|
'--no-password',
|
||||||
|
'--clean',
|
||||||
|
'--if-exists',
|
||||||
|
'--format',
|
||||||
|
'custom',
|
||||||
|
'foo',
|
||||||
|
'>',
|
||||||
|
'databases/localhost/foo',
|
||||||
|
),
|
||||||
|
shell=True,
|
||||||
|
extra_environment={'PGSSLMODE': 'disable'},
|
||||||
|
run_to_completion=False,
|
||||||
|
).and_return(process).once()
|
||||||
|
|
||||||
|
assert module.dump_databases(databases, 'test.yaml', {}, dry_run=False) == [process]
|
||||||
|
|
||||||
|
|
||||||
def test_restore_database_dump_runs_pg_restore():
|
def test_restore_database_dump_runs_pg_restore():
|
||||||
database_config = [{'name': 'foo'}]
|
database_config = [{'name': 'foo'}]
|
||||||
extract_process = flexmock(stdout=flexmock())
|
extract_process = flexmock(stdout=flexmock())
|
||||||
@@ -388,6 +418,40 @@ def test_restore_database_dump_runs_psql_for_all_database_dump():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_restore_database_dump_runs_non_default_pg_restore_and_psql():
|
||||||
|
database_config = [
|
||||||
|
{'name': 'foo', 'pg_restore_command': 'special_pg_restore', 'psql_command': 'special_psql'}
|
||||||
|
]
|
||||||
|
extract_process = flexmock(stdout=flexmock())
|
||||||
|
|
||||||
|
flexmock(module).should_receive('make_dump_path')
|
||||||
|
flexmock(module.dump).should_receive('make_database_dump_filename')
|
||||||
|
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
|
||||||
|
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||||
|
(
|
||||||
|
'special_pg_restore',
|
||||||
|
'--no-password',
|
||||||
|
'--if-exists',
|
||||||
|
'--exit-on-error',
|
||||||
|
'--clean',
|
||||||
|
'--dbname',
|
||||||
|
'foo',
|
||||||
|
),
|
||||||
|
processes=[extract_process],
|
||||||
|
output_log_level=logging.DEBUG,
|
||||||
|
input_file=extract_process.stdout,
|
||||||
|
extra_environment={'PGSSLMODE': 'disable'},
|
||||||
|
).once()
|
||||||
|
flexmock(module).should_receive('execute_command').with_args(
|
||||||
|
('special_psql', '--no-password', '--quiet', '--dbname', 'foo', '--command', 'ANALYZE'),
|
||||||
|
extra_environment={'PGSSLMODE': 'disable'},
|
||||||
|
).once()
|
||||||
|
|
||||||
|
module.restore_database_dump(
|
||||||
|
database_config, 'test.yaml', {}, dry_run=False, extract_process=extract_process
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_restore_database_dump_with_dry_run_skips_restore():
|
def test_restore_database_dump_with_dry_run_skips_restore():
|
||||||
database_config = [{'name': 'foo'}]
|
database_config = [{'name': 'foo'}]
|
||||||
|
|
||||||
|
|||||||
+27
-14
@@ -213,57 +213,70 @@ def test_execute_command_without_run_to_completion_returns_process():
|
|||||||
assert module.execute_command(full_command, run_to_completion=False) == process
|
assert module.execute_command(full_command, run_to_completion=False) == process
|
||||||
|
|
||||||
|
|
||||||
def test_execute_command_captures_output():
|
def test_execute_command_and_capture_output_returns_stdout():
|
||||||
full_command = ['foo', 'bar']
|
full_command = ['foo', 'bar']
|
||||||
expected_output = '[]'
|
expected_output = '[]'
|
||||||
flexmock(module.os, environ={'a': 'b'})
|
flexmock(module.os, environ={'a': 'b'})
|
||||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||||
full_command, shell=False, env=None, cwd=None
|
full_command, stderr=None, shell=False, env=None, cwd=None
|
||||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||||
|
|
||||||
output = module.execute_command(full_command, output_log_level=None)
|
output = module.execute_command_and_capture_output(full_command)
|
||||||
|
|
||||||
assert output == expected_output
|
assert output == expected_output
|
||||||
|
|
||||||
|
|
||||||
def test_execute_command_captures_output_with_shell():
|
def test_execute_command_and_capture_output_with_capture_stderr_returns_stderr():
|
||||||
full_command = ['foo', 'bar']
|
full_command = ['foo', 'bar']
|
||||||
expected_output = '[]'
|
expected_output = '[]'
|
||||||
flexmock(module.os, environ={'a': 'b'})
|
flexmock(module.os, environ={'a': 'b'})
|
||||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||||
'foo bar', shell=True, env=None, cwd=None
|
full_command, stderr=module.subprocess.STDOUT, shell=False, env=None, cwd=None
|
||||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||||
|
|
||||||
output = module.execute_command(full_command, output_log_level=None, shell=True)
|
output = module.execute_command_and_capture_output(full_command, capture_stderr=True)
|
||||||
|
|
||||||
assert output == expected_output
|
assert output == expected_output
|
||||||
|
|
||||||
|
|
||||||
def test_execute_command_captures_output_with_extra_environment():
|
def test_execute_command_and_capture_output_returns_output_with_shell():
|
||||||
full_command = ['foo', 'bar']
|
full_command = ['foo', 'bar']
|
||||||
expected_output = '[]'
|
expected_output = '[]'
|
||||||
flexmock(module.os, environ={'a': 'b'})
|
flexmock(module.os, environ={'a': 'b'})
|
||||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||||
full_command, shell=False, env={'a': 'b', 'c': 'd'}, cwd=None
|
'foo bar', stderr=None, shell=True, env=None, cwd=None
|
||||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||||
|
|
||||||
output = module.execute_command(
|
output = module.execute_command_and_capture_output(full_command, shell=True)
|
||||||
full_command, output_log_level=None, shell=False, extra_environment={'c': 'd'}
|
|
||||||
|
assert output == expected_output
|
||||||
|
|
||||||
|
|
||||||
|
def test_execute_command_and_capture_output_returns_output_with_extra_environment():
|
||||||
|
full_command = ['foo', 'bar']
|
||||||
|
expected_output = '[]'
|
||||||
|
flexmock(module.os, environ={'a': 'b'})
|
||||||
|
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||||
|
full_command, stderr=None, shell=False, env={'a': 'b', 'c': 'd'}, cwd=None,
|
||||||
|
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||||
|
|
||||||
|
output = module.execute_command_and_capture_output(
|
||||||
|
full_command, shell=False, extra_environment={'c': 'd'}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert output == expected_output
|
assert output == expected_output
|
||||||
|
|
||||||
|
|
||||||
def test_execute_command_captures_output_with_working_directory():
|
def test_execute_command_and_capture_output_returns_output_with_working_directory():
|
||||||
full_command = ['foo', 'bar']
|
full_command = ['foo', 'bar']
|
||||||
expected_output = '[]'
|
expected_output = '[]'
|
||||||
flexmock(module.os, environ={'a': 'b'})
|
flexmock(module.os, environ={'a': 'b'})
|
||||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||||
full_command, shell=False, env=None, cwd='/working'
|
full_command, stderr=None, shell=False, env=None, cwd='/working'
|
||||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||||
|
|
||||||
output = module.execute_command(
|
output = module.execute_command_and_capture_output(
|
||||||
full_command, output_log_level=None, shell=False, working_directory='/working'
|
full_command, shell=False, working_directory='/working'
|
||||||
)
|
)
|
||||||
|
|
||||||
assert output == expected_output
|
assert output == expected_output
|
||||||
|
|||||||
Reference in New Issue
Block a user