Add Borg 2 date-based matching flags for archive selection (#659).

Reviewed-on: https://projects.torsion.org/borgmatic-collective/borgmatic/pulls/661
This commit is contained in:
Dan Helfman 2023-05-23 21:26:17 +00:00
commit 35b5c62ca6
11 changed files with 473 additions and 77 deletions

View file

@ -40,10 +40,7 @@ def run_mount(
local_path,
remote_path,
),
mount_arguments.mount_point,
mount_arguments.paths,
mount_arguments.foreground,
mount_arguments.options,
mount_arguments,
storage,
local_borg_version,
global_arguments,

View file

@ -45,10 +45,9 @@ def run_prune(
retention,
local_borg_version,
global_arguments,
prune_arguments,
local_path=local_path,
remote_path=remote_path,
stats=prune_arguments.stats,
list_archives=prune_arguments.list_archives,
)
borgmatic.hooks.command.execute_hook(
hooks.get('after_prune'),

View file

@ -9,10 +9,7 @@ logger = logging.getLogger(__name__)
def mount_archive(
repository_path,
archive,
mount_point,
paths,
foreground,
options,
mount_arguments,
storage_config,
local_borg_version,
global_arguments,
@ -36,8 +33,11 @@ def mount_archive(
+ (('--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 ())
+ (('--foreground',) if foreground else ())
+ (('-o', options) if options else ())
+ flags.make_flags_from_arguments(
mount_arguments,
excludes=('repository', 'archive', 'mount_point', 'paths', 'options'),
)
+ (('-o', mount_arguments.options) if mount_arguments.options else ())
+ (
(
flags.make_repository_flags(repository_path, local_borg_version)
@ -54,14 +54,14 @@ def mount_archive(
else flags.make_repository_flags(repository_path, local_borg_version)
)
)
+ (mount_point,)
+ (tuple(paths) if paths else ())
+ (mount_arguments.mount_point,)
+ (tuple(mount_arguments.paths) if mount_arguments.paths else ())
)
borg_environment = environment.make_environment(storage_config)
# Don't capture the output when foreground mode is used so that ctrl-C can work properly.
if foreground:
if mount_arguments.foreground:
execute_command(
full_command,
output_file=DO_NOT_CAPTURE,

View file

@ -53,11 +53,10 @@ def prune_archives(
storage_config,
retention_config,
local_borg_version,
prune_arguments,
global_arguments,
local_path='borg',
remote_path=None,
stats=False,
list_archives=False,
):
'''
Given dry-run flag, a local or remote repository path, a storage config dict, and a
@ -76,16 +75,20 @@ def prune_archives(
+ (('--umask', str(umask)) if umask else ())
+ (('--log-json',) if global_arguments.log_json else ())
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
+ (('--stats',) if stats and not dry_run else ())
+ (('--stats',) if prune_arguments.stats and not dry_run else ())
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+ (('--list',) if list_archives else ())
+ flags.make_flags_from_arguments(
prune_arguments,
excludes=('repository', 'stats', 'list_archives'),
)
+ (('--list',) if prune_arguments.list_archives else ())
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
+ (('--dry-run',) if dry_run else ())
+ (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
+ flags.make_repository_flags(repository_path, local_borg_version)
)
if stats or list_archives:
if prune_arguments.stats or prune_arguments.list_archives:
output_log_level = logging.ANSWER
else:
output_log_level = logging.INFO

View file

@ -259,7 +259,7 @@ def make_parsers():
'--source-repository',
'--other-repo',
metavar='KEY_REPOSITORY',
help='Path to an existing Borg repository whose key material should be reused (Borg 2.x+ only)',
help='Path to an existing Borg repository whose key material should be reused [Borg 2.x+ only]',
)
rcreate_group.add_argument(
'--repository',
@ -268,7 +268,7 @@ def make_parsers():
rcreate_group.add_argument(
'--copy-crypt-key',
action='store_true',
help='Copy the crypt key used for authenticated encryption from the source repository, defaults to a new random key (Borg 2.x+ only)',
help='Copy the crypt key used for authenticated encryption from the source repository, defaults to a new random key [Borg 2.x+ only]',
)
rcreate_group.add_argument(
'--append-only',
@ -291,8 +291,8 @@ def make_parsers():
transfer_parser = subparsers.add_parser(
'transfer',
aliases=SUBPARSER_ALIASES['transfer'],
help='Transfer archives from one repository to another, optionally upgrading the transferred data (Borg 2.0+ only)',
description='Transfer archives from one repository to another, optionally upgrading the transferred data (Borg 2.0+ only)',
help='Transfer archives from one repository to another, optionally upgrading the transferred data [Borg 2.0+ only]',
description='Transfer archives from one repository to another, optionally upgrading the transferred data [Borg 2.0+ only]',
add_help=False,
)
transfer_group = transfer_parser.add_argument_group('transfer arguments')
@ -337,6 +337,26 @@ def make_parsers():
transfer_group.add_argument(
'--last', metavar='N', help='Only transfer last N archives after other filters are applied'
)
transfer_group.add_argument(
'--oldest',
metavar='TIMESPAN',
help='Transfer archives within a specified time range starting from the timestamp of the oldest archive (e.g. 7d or 12m) [Borg 2.x+ only]',
)
transfer_group.add_argument(
'--newest',
metavar='TIMESPAN',
help='Transfer archives within a time range that ends at timestamp of the newest archive and starts a specified time range ago (e.g. 7d or 12m) [Borg 2.x+ only]',
)
transfer_group.add_argument(
'--older',
metavar='TIMESPAN',
help='Transfer archives that are older than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
transfer_group.add_argument(
'--newer',
metavar='TIMESPAN',
help='Transfer archives that are newer than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
transfer_group.add_argument(
'-h', '--help', action='help', help='Show this help message and exit'
)
@ -363,13 +383,33 @@ def make_parsers():
prune_group.add_argument(
'--list', dest='list_archives', action='store_true', help='List archives kept/pruned'
)
prune_group.add_argument(
'--oldest',
metavar='TIMESPAN',
help='Prune archives within a specified time range starting from the timestamp of the oldest archive (e.g. 7d or 12m) [Borg 2.x+ only]',
)
prune_group.add_argument(
'--newest',
metavar='TIMESPAN',
help='Prune archives within a time range that ends at timestamp of the newest archive and starts a specified time range ago (e.g. 7d or 12m) [Borg 2.x+ only]',
)
prune_group.add_argument(
'--older',
metavar='TIMESPAN',
help='Prune archives that are older than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
prune_group.add_argument(
'--newer',
metavar='TIMESPAN',
help='Prune archives that are newer than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
prune_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
compact_parser = subparsers.add_parser(
'compact',
aliases=SUBPARSER_ALIASES['compact'],
help='Compact segments to free space (Borg 1.2+, borgmatic 1.5.23+ only)',
description='Compact segments to free space (Borg 1.2+, borgmatic 1.5.23+ only)',
help='Compact segments to free space [Borg 1.2+, borgmatic 1.5.23+ only]',
description='Compact segments to free space [Borg 1.2+, borgmatic 1.5.23+ only]',
add_help=False,
)
compact_group = compact_parser.add_argument_group('compact arguments')
@ -389,7 +429,7 @@ def make_parsers():
dest='cleanup_commits',
default=False,
action='store_true',
help='Cleanup commit-only 17-byte segment files left behind by Borg 1.1 (flag in Borg 1.2 only)',
help='Cleanup commit-only 17-byte segment files left behind by Borg 1.1 [flag in Borg 1.2 only]',
)
compact_group.add_argument(
'--threshold',
@ -603,6 +643,34 @@ def make_parsers():
action='store_true',
help='Stay in foreground until ctrl-C is pressed',
)
mount_group.add_argument(
'--first',
metavar='N',
help='Mount first N archives after other filters are applied',
)
mount_group.add_argument(
'--last', metavar='N', help='Mount last N archives after other filters are applied'
)
mount_group.add_argument(
'--oldest',
metavar='TIMESPAN',
help='Mount archives within a specified time range starting from the timestamp of the oldest archive (e.g. 7d or 12m) [Borg 2.x+ only]',
)
mount_group.add_argument(
'--newest',
metavar='TIMESPAN',
help='Mount archives within a time range that ends at timestamp of the newest archive and starts a specified time range ago (e.g. 7d or 12m) [Borg 2.x+ only]',
)
mount_group.add_argument(
'--older',
metavar='TIMESPAN',
help='Mount archives that are older than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
mount_group.add_argument(
'--newer',
metavar='TIMESPAN',
help='Mount archives that are newer than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
mount_group.add_argument('--options', dest='options', help='Extra Borg mount options')
mount_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
@ -694,6 +762,26 @@ def make_parsers():
rlist_group.add_argument(
'--last', metavar='N', help='List last N archives after other filters are applied'
)
rlist_group.add_argument(
'--oldest',
metavar='TIMESPAN',
help='List archives within a specified time range starting from the timestamp of the oldest archive (e.g. 7d or 12m) [Borg 2.x+ only]',
)
rlist_group.add_argument(
'--newest',
metavar='TIMESPAN',
help='List archives within a time range that ends at timestamp of the newest archive and starts a specified time range ago (e.g. 7d or 12m) [Borg 2.x+ only]',
)
rlist_group.add_argument(
'--older',
metavar='TIMESPAN',
help='List archives that are older than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
rlist_group.add_argument(
'--newer',
metavar='TIMESPAN',
help='List archives that are newer than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
rlist_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
list_parser = subparsers.add_parser(
@ -825,6 +913,26 @@ def make_parsers():
info_group.add_argument(
'--last', metavar='N', help='Show info for last N archives after other filters are applied'
)
info_group.add_argument(
'--oldest',
metavar='TIMESPAN',
help='Show info for archives within a specified time range starting from the timestamp of the oldest archive (e.g. 7d or 12m) [Borg 2.x+ only]',
)
info_group.add_argument(
'--newest',
metavar='TIMESPAN',
help='Show info for archives within a time range that ends at timestamp of the newest archive and starts a specified time range ago (e.g. 7d or 12m) [Borg 2.x+ only]',
)
info_group.add_argument(
'--older',
metavar='TIMESPAN',
help='Show info for archives that are older than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
info_group.add_argument(
'--newer',
metavar='TIMESPAN',
help='Show info for archives that are newer than the specified time range (e.g. 7d or 12m) from the current time [Borg 2.x+ only]',
)
info_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
break_lock_parser = subparsers.add_parser(

View file

@ -124,3 +124,24 @@ def test_display_archives_info_command_does_not_duplicate_flags_or_raise():
fuzz_argument(arguments, argument_name),
argparse.Namespace(log_json=False),
)
def test_prune_archives_command_does_not_duplicate_flags_or_raise():
arguments = borgmatic.commands.arguments.parse_arguments('prune')['prune']
flexmock(borgmatic.borg.prune).should_receive('execute_command').replace_with(
assert_command_does_not_duplicate_flags
)
for argument_name in dir(arguments):
if argument_name.startswith('_'):
continue
borgmatic.borg.prune.prune_archives(
False,
'repo',
{},
{},
'2.3.4',
fuzz_argument(arguments, argument_name),
argparse.Namespace(log_json=False),
)

View file

@ -478,3 +478,53 @@ def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
archive=None, json=False, prefix=None, match_archives=None, **{argument_name: 'value'}
),
)
def test_display_archives_info_with_date_based_matching_calls_borg_with_date_based_flags():
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
flexmock(module.flags).should_receive('make_flags').and_return(())
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
None, None, '2.3.4'
).and_return(())
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(
('--newer', '1d', '--newest', '1y', '--older', '1m', '--oldest', '1w')
)
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
flexmock(module.environment).should_receive('make_environment')
flexmock(module).should_receive('execute_command').with_args(
(
'borg',
'info',
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'--repo',
'repo',
),
output_log_level=module.borgmatic.logger.ANSWER,
borg_local_path='borg',
extra_environment=None,
)
info_arguments = flexmock(
archive=None,
json=False,
prefix=None,
match_archives=None,
newer='1d',
newest='1y',
older='1m',
oldest='1w',
)
module.display_archives_info(
repository_path='repo',
storage_config={},
local_borg_version='2.3.4',
global_arguments=flexmock(log_json=False),
info_arguments=info_arguments,
)

View file

@ -21,13 +21,11 @@ def test_mount_archive_calls_borg_with_required_flags():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(('borg', 'mount', 'repo', '/mnt'))
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive=None,
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -46,13 +44,11 @@ def test_mount_archive_with_borg_features_calls_borg_with_repository_and_match_a
('borg', 'mount', '--repo', 'repo', '--match-archives', 'archive', '/mnt')
)
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -66,13 +62,11 @@ def test_mount_archive_without_archive_calls_borg_with_repository_flags_only():
)
insert_execute_command_mock(('borg', 'mount', 'repo::archive', '/mnt'))
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -86,13 +80,13 @@ def test_mount_archive_calls_borg_with_path_flags():
)
insert_execute_command_mock(('borg', 'mount', 'repo::archive', '/mnt', 'path1', 'path2'))
mount_arguments = flexmock(
mount_point='/mnt', options=None, paths=['path1', 'path2'], foreground=False
)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=['path1', 'path2'],
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -108,13 +102,11 @@ def test_mount_archive_calls_borg_with_remote_path_flags():
('borg', 'mount', '--remote-path', 'borg1', 'repo::archive', '/mnt')
)
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -129,13 +121,11 @@ def test_mount_archive_calls_borg_with_umask_flags():
)
insert_execute_command_mock(('borg', 'mount', '--umask', '0770', 'repo::archive', '/mnt'))
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={'umask': '0770'},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -149,13 +139,11 @@ def test_mount_archive_calls_borg_with_log_json_flags():
)
insert_execute_command_mock(('borg', 'mount', '--log-json', 'repo::archive', '/mnt'))
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=True),
@ -169,13 +157,11 @@ def test_mount_archive_calls_borg_with_lock_wait_flags():
)
insert_execute_command_mock(('borg', 'mount', '--lock-wait', '5', 'repo::archive', '/mnt'))
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={'lock_wait': '5'},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -190,13 +176,11 @@ def test_mount_archive_with_log_info_calls_borg_with_info_parameter():
insert_execute_command_mock(('borg', 'mount', '--info', 'repo::archive', '/mnt'))
insert_logging_mock(logging.INFO)
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -211,13 +195,11 @@ def test_mount_archive_with_log_debug_calls_borg_with_debug_flags():
insert_execute_command_mock(('borg', 'mount', '--debug', '--show-rc', 'repo::archive', '/mnt'))
insert_logging_mock(logging.DEBUG)
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=False)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -237,13 +219,11 @@ def test_mount_archive_calls_borg_with_foreground_parameter():
extra_environment=None,
).once()
mount_arguments = flexmock(mount_point='/mnt', options=None, paths=None, foreground=True)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=True,
options=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
@ -257,13 +237,74 @@ def test_mount_archive_calls_borg_with_options_flags():
)
insert_execute_command_mock(('borg', 'mount', '-o', 'super_mount', 'repo::archive', '/mnt'))
mount_arguments = flexmock(
mount_point='/mnt', options='super_mount', paths=None, foreground=False
)
module.mount_archive(
repository_path='repo',
archive='archive',
mount_point='/mnt',
paths=None,
foreground=False,
options='super_mount',
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
)
def test_mount_archive_with_date_based_matching_calls_borg_with_date_based_flags():
flexmock(module.flags).should_receive('make_flags').and_return(())
flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(
(
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'--match-archives',
None,
)
)
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
flexmock(module.environment).should_receive('make_environment')
flexmock(module).should_receive('execute_command').with_args(
(
'borg',
'mount',
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'--match-archives',
None,
'--repo',
'repo',
'/mnt',
),
borg_local_path='borg',
extra_environment=None,
)
mount_arguments = flexmock(
mount_point='/mnt',
options=None,
paths=None,
foreground=False,
newer='1d',
newest='1y',
older='1m',
oldest='1w',
)
module.mount_archive(
repository_path='repo',
archive=None,
mount_arguments=mount_arguments,
storage_config={},
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),

View file

@ -117,6 +117,7 @@ def test_prune_archives_calls_borg_with_flags():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('repo',), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -124,6 +125,7 @@ def test_prune_archives_calls_borg_with_flags():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
@ -135,6 +137,7 @@ def test_prune_archives_with_log_info_calls_borg_with_info_flag():
insert_execute_command_mock(PRUNE_COMMAND + ('--info', 'repo'), logging.INFO)
insert_logging_mock(logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
repository_path='repo',
storage_config={},
@ -142,6 +145,7 @@ def test_prune_archives_with_log_info_calls_borg_with_info_flag():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
@ -153,6 +157,7 @@ def test_prune_archives_with_log_debug_calls_borg_with_debug_flag():
insert_execute_command_mock(PRUNE_COMMAND + ('--debug', '--show-rc', 'repo'), logging.INFO)
insert_logging_mock(logging.DEBUG)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
repository_path='repo',
storage_config={},
@ -160,6 +165,7 @@ def test_prune_archives_with_log_debug_calls_borg_with_debug_flag():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
@ -170,6 +176,7 @@ def test_prune_archives_with_dry_run_calls_borg_with_dry_run_flag():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--dry-run', 'repo'), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
repository_path='repo',
storage_config={},
@ -177,6 +184,7 @@ def test_prune_archives_with_dry_run_calls_borg_with_dry_run_flag():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
@ -187,6 +195,7 @@ def test_prune_archives_with_local_path_calls_borg_via_local_path():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(('borg1',) + PRUNE_COMMAND[1:] + ('repo',), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -195,6 +204,7 @@ def test_prune_archives_with_local_path_calls_borg_via_local_path():
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
local_path='borg1',
prune_arguments=prune_arguments,
)
@ -205,6 +215,7 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_flags():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--remote-path', 'borg1', 'repo'), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -213,6 +224,7 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_flags():
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
remote_path='borg1',
prune_arguments=prune_arguments,
)
@ -223,6 +235,7 @@ def test_prune_archives_with_stats_calls_borg_with_stats_flag_and_answer_output_
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--stats', 'repo'), module.borgmatic.logger.ANSWER)
prune_arguments = flexmock(stats=True, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -230,7 +243,7 @@ def test_prune_archives_with_stats_calls_borg_with_stats_flag_and_answer_output_
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
stats=True,
prune_arguments=prune_arguments,
)
@ -241,6 +254,7 @@ def test_prune_archives_with_files_calls_borg_with_list_flag_and_answer_output_l
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--list', 'repo'), module.borgmatic.logger.ANSWER)
prune_arguments = flexmock(stats=False, list_archives=True)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -248,7 +262,7 @@ def test_prune_archives_with_files_calls_borg_with_list_flag_and_answer_output_l
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
list_archives=True,
prune_arguments=prune_arguments,
)
@ -260,6 +274,7 @@ def test_prune_archives_with_umask_calls_borg_with_umask_flags():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--umask', '077', 'repo'), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -267,6 +282,7 @@ def test_prune_archives_with_umask_calls_borg_with_umask_flags():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
@ -277,6 +293,7 @@ def test_prune_archives_with_log_json_calls_borg_with_log_json_flag():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--log-json', 'repo'), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -284,6 +301,7 @@ def test_prune_archives_with_log_json_calls_borg_with_log_json_flag():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=True),
prune_arguments=prune_arguments,
)
@ -295,6 +313,7 @@ def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_flags():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--lock-wait', '5', 'repo'), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -302,6 +321,7 @@ def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_flags():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
@ -312,6 +332,7 @@ def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
insert_execute_command_mock(PRUNE_COMMAND + ('--extra', '--options', 'repo'), logging.INFO)
prune_arguments = flexmock(stats=False, list_archives=False)
module.prune_archives(
dry_run=False,
repository_path='repo',
@ -319,4 +340,69 @@ def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)
def test_prune_archives_with_date_based_matching_calls_borg_with_date_based_flags():
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
flexmock(module.flags).should_receive('make_flags').and_return(())
flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(
(
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'--match-archives',
None,
)
)
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
flexmock(module.environment).should_receive('make_environment')
flexmock(module).should_receive('execute_command').with_args(
(
'borg',
'prune',
'--keep-daily',
'1',
'--keep-weekly',
'2',
'--keep-monthly',
'3',
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'--match-archives',
None,
'--repo',
'repo',
),
output_log_level=logging.INFO,
borg_local_path='borg',
extra_environment=None,
)
prune_arguments = flexmock(
stats=False, list_archives=False, newer='1d', newest='1y', older='1m', oldest='1w'
)
module.prune_archives(
dry_run=False,
repository_path='repo',
storage_config={},
retention_config=flexmock(),
local_borg_version='1.2.3',
global_arguments=flexmock(log_json=False),
prune_arguments=prune_arguments,
)

View file

@ -614,3 +614,46 @@ def test_list_repository_with_json_returns_borg_output():
)
== json_output
)
def test_make_rlist_command_with_date_based_matching_calls_borg_with_date_based_flags():
flexmock(module.flags).should_receive('make_flags').and_return(())
flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
None, None, '1.2.3'
).and_return(())
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(
('--newer', '1d', '--newest', '1y', '--older', '1m', '--oldest', '1w')
)
flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
command = module.make_rlist_command(
repository_path='repo',
storage_config={},
local_borg_version='1.2.3',
rlist_arguments=flexmock(
archive=None,
paths=None,
json=False,
prefix=None,
match_archives=None,
newer='1d',
newest='1y',
older='1m',
oldest='1w',
),
global_arguments=flexmock(log_json=False),
)
assert command == (
'borg',
'list',
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'repo',
)

View file

@ -430,3 +430,51 @@ def test_transfer_archives_with_source_repository_calls_borg_with_other_repo_fla
),
global_arguments=flexmock(log_json=False),
)
def test_transfer_archives_with_date_based_matching_calls_borg_with_date_based_flags():
flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
flexmock(module.flags).should_receive('make_flags').and_return(())
flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(
('--newer', '1d', '--newest', '1y', '--older', '1m', '--oldest', '1w')
)
flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
flexmock(module.environment).should_receive('make_environment')
flexmock(module).should_receive('execute_command').with_args(
(
'borg',
'transfer',
'--newer',
'1d',
'--newest',
'1y',
'--older',
'1m',
'--oldest',
'1w',
'--repo',
'repo',
),
output_log_level=module.borgmatic.logger.ANSWER,
output_file=None,
borg_local_path='borg',
extra_environment=None,
)
module.transfer_archives(
dry_run=False,
repository_path='repo',
storage_config={},
local_borg_version='2.3.4',
global_arguments=flexmock(log_json=False),
transfer_arguments=flexmock(
archive=None,
progress=None,
source_repository='other',
newer='1d',
newest='1y',
older='1m',
oldest='1w',
),
)