diff --git a/borgmatic/actions/compact.py b/borgmatic/actions/compact.py index 7386d230..dbc2e573 100644 --- a/borgmatic/actions/compact.py +++ b/borgmatic/actions/compact.py @@ -37,9 +37,17 @@ def run_compact( global_arguments, local_path=local_path, remote_path=remote_path, - progress=compact_arguments.progress or config.get('progress'), + progress=( + config.get('progress') + if compact_arguments.progress is None + else compact_arguments.progress + ), cleanup_commits=compact_arguments.cleanup_commits, - threshold=compact_arguments.threshold or config.get('compact_threshold'), + threshold=( + config.get('compact_threshold') + if compact_arguments.threshold is None + else compact_arguments.threshold + ), ) else: # pragma: nocover logger.info('Skipping compact (only available/needed in Borg 1.2+)') diff --git a/borgmatic/actions/create.py b/borgmatic/actions/create.py index c771f3d2..e0ef3b1f 100644 --- a/borgmatic/actions/create.py +++ b/borgmatic/actions/create.py @@ -327,10 +327,22 @@ def run_create( borgmatic_runtime_directory, local_path=local_path, remote_path=remote_path, - progress=create_arguments.progress or config.get('progress'), - stats=create_arguments.stats or config.get('stats'), + progress=( + config.get('progress') + if create_arguments.progress is None + else create_arguments.progress + ), + stats=( + config.get('statistics') + if create_arguments.stats is None + else create_arguments.stats + ), json=create_arguments.json, - list_files=create_arguments.list_files or config.get('list'), + list_files=( + config.get('list_details') + if create_arguments.list_files is None + else create_arguments.list_files + ), stream_processes=stream_processes, ) diff --git a/borgmatic/actions/export_tar.py b/borgmatic/actions/export_tar.py index 1b41548b..cc18aeeb 100644 --- a/borgmatic/actions/export_tar.py +++ b/borgmatic/actions/export_tar.py @@ -43,6 +43,10 @@ def run_export_tar( local_path=local_path, remote_path=remote_path, tar_filter=export_tar_arguments.tar_filter, - list_files=export_tar_arguments.list_files or config.get('list'), + list_files=( + config.get('list_details') + if export_tar_arguments.list_files is None + else export_tar_arguments.list_files + ), strip_components=export_tar_arguments.strip_components, ) diff --git a/borgmatic/actions/extract.py b/borgmatic/actions/extract.py index 83f81176..3e42b57d 100644 --- a/borgmatic/actions/extract.py +++ b/borgmatic/actions/extract.py @@ -45,5 +45,9 @@ def run_extract( remote_path=remote_path, destination_path=extract_arguments.destination, strip_components=extract_arguments.strip_components, - progress=extract_arguments.progress or config.get('progress'), + progress=( + config.get('progress') + if extract_arguments.progress is None + else extract_arguments.progress + ), ) diff --git a/borgmatic/actions/repo_create.py b/borgmatic/actions/repo_create.py index 49f4e6c0..5166b9b8 100644 --- a/borgmatic/actions/repo_create.py +++ b/borgmatic/actions/repo_create.py @@ -41,9 +41,21 @@ def run_repo_create( encryption_mode, repo_create_arguments.source_repository, repo_create_arguments.copy_crypt_key, - repo_create_arguments.append_only or repository.get('append_only'), - repo_create_arguments.storage_quota or repository.get('storage_quota'), - repo_create_arguments.make_parent_dirs or repository.get('make_parent_dirs'), + ( + repository.get('append_only') + if repo_create_arguments.append_only is None + else repo_create_arguments.append_only + ), + ( + repository.get('storage_quota') + if repo_create_arguments.storage_quota is None + else repo_create_arguments.storage_quota + ), + ( + repository.get('make_parent_dirs') + if repo_create_arguments.make_parent_dirs is None + else repo_create_arguments.make_parent_dirs + ), local_path=local_path, remote_path=remote_path, ) diff --git a/borgmatic/borg/check.py b/borgmatic/borg/check.py index 13f4ffca..c02b6ec4 100644 --- a/borgmatic/borg/check.py +++ b/borgmatic/borg/check.py @@ -143,7 +143,9 @@ def check_archives( umask = config.get('umask') borg_exit_codes = config.get('borg_exit_codes') working_directory = borgmatic.config.paths.get_working_directory(config) - progress = check_arguments.progress or config.get('progress') + progress = ( + config.get('progress') if check_arguments.progress is None else check_arguments.progress + ) if 'data' in checks: checks.add('archives') diff --git a/borgmatic/borg/delete.py b/borgmatic/borg/delete.py index a9c3478c..f31730ce 100644 --- a/borgmatic/borg/delete.py +++ b/borgmatic/borg/delete.py @@ -35,7 +35,12 @@ def make_delete_command( + borgmatic.borg.flags.make_flags('log-json', global_arguments.log_json) + borgmatic.borg.flags.make_flags('lock-wait', config.get('lock_wait')) + borgmatic.borg.flags.make_flags( - 'list', delete_arguments.list_archives or config.get('list') + 'list', + ( + config.get('list_details') + if delete_arguments.list_archives is None + else delete_arguments.list_archives + ), ) + ( (('--force',) + (('--force',) if delete_arguments.force >= 2 else ())) diff --git a/borgmatic/borg/prune.py b/borgmatic/borg/prune.py index 5eef3a29..b29cbe67 100644 --- a/borgmatic/borg/prune.py +++ b/borgmatic/borg/prune.py @@ -66,7 +66,12 @@ def prune_archives( borgmatic.logger.add_custom_log_levels() umask = config.get('umask', None) lock_wait = config.get('lock_wait', None) - stats = prune_arguments.stats or config.get('stats') + stats = config.get('statistics') if prune_arguments.stats is None else prune_arguments.stats + list_archives = ( + config.get('list_details') + if prune_arguments.list_archives is None + else prune_arguments.list_archives + ) extra_borg_options = config.get('extra_borg_options', {}).get('prune', '') full_command = ( @@ -88,14 +93,14 @@ def prune_archives( prune_arguments, excludes=('repository', 'match_archives', 'stats', 'list_archives'), ) - + (('--list',) if prune_arguments.list_archives or config.get('list') else ()) + + (('--list',) if 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 prune_arguments.list_archives: + if stats or list_archives: output_log_level = logging.ANSWER else: output_log_level = logging.INFO diff --git a/borgmatic/borg/transfer.py b/borgmatic/borg/transfer.py index ca90063e..528cd64c 100644 --- a/borgmatic/borg/transfer.py +++ b/borgmatic/borg/transfer.py @@ -52,13 +52,16 @@ def transfer_archives( + flags.make_flags('other-repo', transfer_arguments.source_repository) + flags.make_flags('dry-run', dry_run) ) + progress = ( + config.get('progress') + if transfer_arguments.progress is None + else transfer_arguments.progress + ) return execute_command( full_command, output_log_level=logging.ANSWER, - output_file=( - DO_NOT_CAPTURE if (transfer_arguments.progress or config.get('progress')) else None - ), + output_file=DO_NOT_CAPTURE if progress else None, environment=environment.make_environment(config), working_directory=borgmatic.config.paths.get_working_directory(config), borg_local_path=local_path, diff --git a/borgmatic/commands/arguments.py b/borgmatic/commands/arguments.py index 7ad600d9..6344a0b2 100644 --- a/borgmatic/commands/arguments.py +++ b/borgmatic/commands/arguments.py @@ -287,7 +287,7 @@ def parse_arguments_for_actions(unparsed_arguments, action_parsers, global_parse ) -OMITTED_FLAG_NAMES = {'match_archives', 'progress', 'stats', 'list'} +OMITTED_FLAG_NAMES = {'match_archives', 'progress', 'statistics', 'list_files'} def make_argument_description(schema, flag_name): @@ -520,9 +520,9 @@ def make_parsers(schema, unparsed_arguments): config_paths = collect.get_default_config_paths(expand_home=True) unexpanded_config_paths = collect.get_default_config_paths(expand_home=False) - # allow_abbrev=False prevents the global parser from erroring about "ambiguous" options like - # --encryption. Such options are intended for an action parser rather than the global parser, - # and so we don't want to error on them here. + # Using allow_abbrev=False here prevents the global parser from erroring about "ambiguous" + # options like --encryption. Such options are intended for an action parser rather than the + # global parser, and so we don't want to error on them here. global_parser = ArgumentParser(allow_abbrev=False, add_help=False) global_group = global_parser.add_argument_group('global arguments') diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index aaeb4476..d0bcaa0f 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -823,7 +823,7 @@ properties: actions. Defaults to false. default: false example: true - stats: + statistics: type: boolean description: | Display statistics for an archive when running supported actions. @@ -831,7 +831,7 @@ properties: false. default: false example: true - list: + list_details: type: boolean description: | Display details for each file or archive as it is processed when diff --git a/tests/end-to-end/test_config_flag.py b/tests/end-to-end/test_config_flag.py index 0300ac4e..279a1c6e 100644 --- a/tests/end-to-end/test_config_flag.py +++ b/tests/end-to-end/test_config_flag.py @@ -40,11 +40,15 @@ def test_config_flags_do_not_error(): generate_configuration(config_path) subprocess.check_call( - shlex.split(f'borgmatic -v 2 --config {config_path} --repositories "[{{path: {repository_path}, label: repo}}]" repo-create --encryption repokey') + shlex.split( + f'borgmatic -v 2 --config {config_path} --repositories "[{{path: {repository_path}, label: repo}}]" repo-create --encryption repokey' + ) ) subprocess.check_call( - shlex.split(f'borgmatic create --config {config_path} --repositories[0].path "{repository_path}"') + shlex.split( + f'borgmatic create --config {config_path} --repositories[0].path "{repository_path}"' + ) ) finally: os.chdir(original_working_directory) diff --git a/tests/unit/actions/test_compact.py b/tests/unit/actions/test_compact.py index 14dcfaad..1531fd59 100644 --- a/tests/unit/actions/test_compact.py +++ b/tests/unit/actions/test_compact.py @@ -51,6 +51,84 @@ def test_compact_runs_with_selected_repository(): ) +def test_compact_favors_flags_over_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive( + 'repositories_match' + ).once().and_return(True) + flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True) + flexmock(module.borgmatic.borg.compact).should_receive('compact_segments').with_args( + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + progress=False, + cleanup_commits=object, + threshold=15, + ).once() + compact_arguments = flexmock( + repository=flexmock(), + progress=False, + cleanup_commits=flexmock(), + threshold=15, + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + module.run_compact( + config_filename='test.yaml', + repository={'path': 'repo'}, + config={'progress': True, 'compact_threshold': 20}, + local_borg_version=None, + compact_arguments=compact_arguments, + global_arguments=global_arguments, + dry_run_label='', + local_path=None, + remote_path=None, + ) + + +def test_compact_favors_defaults_to_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive( + 'repositories_match' + ).once().and_return(True) + flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True) + flexmock(module.borgmatic.borg.compact).should_receive('compact_segments').with_args( + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + progress=True, + cleanup_commits=object, + threshold=20, + ).once() + compact_arguments = flexmock( + repository=flexmock(), + progress=None, + cleanup_commits=flexmock(), + threshold=None, + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + module.run_compact( + config_filename='test.yaml', + repository={'path': 'repo'}, + config={'progress': True, 'compact_threshold': 20}, + local_borg_version=None, + compact_arguments=compact_arguments, + global_arguments=global_arguments, + dry_run_label='', + local_path=None, + remote_path=None, + ) + + def test_compact_bails_if_repository_does_not_match(): flexmock(module.logger).answer = lambda message: None flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True) diff --git a/tests/unit/actions/test_create.py b/tests/unit/actions/test_create.py index 1f6ca7dc..6f40fb50 100644 --- a/tests/unit/actions/test_create.py +++ b/tests/unit/actions/test_create.py @@ -506,6 +506,118 @@ def test_run_create_runs_with_selected_repository(): ) +def test_run_create_favors_flags_over_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive( + 'repositories_match' + ).once().and_return(True) + flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return( + flexmock() + ) + flexmock(module.borgmatic.borg.create).should_receive('create_archive').with_args( + object, + object, + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + progress=False, + stats=False, + json=object, + list_files=False, + stream_processes=object, + ).once() + flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return({}) + flexmock(module.borgmatic.hooks.dispatch).should_receive( + 'call_hooks_even_if_unconfigured' + ).and_return({}) + flexmock(module).should_receive('collect_patterns').and_return(()) + flexmock(module).should_receive('process_patterns').and_return([]) + flexmock(module.os.path).should_receive('join').and_return('/run/borgmatic/bootstrap') + create_arguments = flexmock( + repository=flexmock(), + progress=False, + stats=False, + json=False, + list_files=False, + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + list( + module.run_create( + config_filename='test.yaml', + repository={'path': 'repo'}, + config={'progress': True, 'statistics': True, 'list_details': True}, + config_paths=['/tmp/test.yaml'], + local_borg_version=None, + create_arguments=create_arguments, + global_arguments=global_arguments, + dry_run_label='', + local_path=None, + remote_path=None, + ) + ) + + +def test_run_create_defaults_to_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive( + 'repositories_match' + ).once().and_return(True) + flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return( + flexmock() + ) + flexmock(module.borgmatic.borg.create).should_receive('create_archive').with_args( + object, + object, + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + progress=True, + stats=True, + json=object, + list_files=True, + stream_processes=object, + ).once() + flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return({}) + flexmock(module.borgmatic.hooks.dispatch).should_receive( + 'call_hooks_even_if_unconfigured' + ).and_return({}) + flexmock(module).should_receive('collect_patterns').and_return(()) + flexmock(module).should_receive('process_patterns').and_return([]) + flexmock(module.os.path).should_receive('join').and_return('/run/borgmatic/bootstrap') + create_arguments = flexmock( + repository=flexmock(), + progress=True, + stats=True, + json=False, + list_files=True, + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + list( + module.run_create( + config_filename='test.yaml', + repository={'path': 'repo'}, + config={'progress': True, 'statistics': True, 'list_details': True}, + config_paths=['/tmp/test.yaml'], + local_borg_version=None, + create_arguments=create_arguments, + global_arguments=global_arguments, + dry_run_label='', + local_path=None, + remote_path=None, + ) + ) + + def test_run_create_bails_if_repository_does_not_match(): flexmock(module.logger).answer = lambda message: None flexmock(module.borgmatic.config.validate).should_receive( diff --git a/tests/unit/actions/test_export_tar.py b/tests/unit/actions/test_export_tar.py index aea54af3..b2e91c38 100644 --- a/tests/unit/actions/test_export_tar.py +++ b/tests/unit/actions/test_export_tar.py @@ -27,3 +27,83 @@ def test_run_export_tar_does_not_raise(): local_path=None, remote_path=None, ) + + +def test_run_export_tar_favors_flags_over_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True) + flexmock(module.borgmatic.borg.export_tar).should_receive('export_tar_archive').with_args( + object, + object, + object, + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + tar_filter=object, + list_files=False, + strip_components=object, + ).once() + export_tar_arguments = flexmock( + repository=flexmock(), + archive=flexmock(), + paths=flexmock(), + destination=flexmock(), + tar_filter=flexmock(), + list_files=False, + strip_components=flexmock(), + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + module.run_export_tar( + repository={'path': 'repo'}, + config={'list_details': True}, + local_borg_version=None, + export_tar_arguments=export_tar_arguments, + global_arguments=global_arguments, + local_path=None, + remote_path=None, + ) + + +def test_run_export_tar_defaults_to_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True) + flexmock(module.borgmatic.borg.export_tar).should_receive('export_tar_archive').with_args( + object, + object, + object, + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + tar_filter=object, + list_files=True, + strip_components=object, + ).once() + export_tar_arguments = flexmock( + repository=flexmock(), + archive=flexmock(), + paths=flexmock(), + destination=flexmock(), + tar_filter=flexmock(), + list_files=None, + strip_components=flexmock(), + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + module.run_export_tar( + repository={'path': 'repo'}, + config={'list_details': True}, + local_borg_version=None, + export_tar_arguments=export_tar_arguments, + global_arguments=global_arguments, + local_path=None, + remote_path=None, + ) diff --git a/tests/unit/actions/test_extract.py b/tests/unit/actions/test_extract.py index c483adcc..3707c887 100644 --- a/tests/unit/actions/test_extract.py +++ b/tests/unit/actions/test_extract.py @@ -27,3 +27,81 @@ def test_run_extract_calls_hooks(): local_path=None, remote_path=None, ) + + +def test_run_extract_favors_flags_over_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True) + flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').with_args( + object, + object, + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + destination_path=object, + strip_components=object, + progress=False, + ).once() + extract_arguments = flexmock( + paths=flexmock(), + progress=False, + destination=flexmock(), + strip_components=flexmock(), + archive=flexmock(), + repository='repo', + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + module.run_extract( + config_filename='test.yaml', + repository={'path': 'repo'}, + config={'repositories': ['repo'], 'progress': True}, + local_borg_version=None, + extract_arguments=extract_arguments, + global_arguments=global_arguments, + local_path=None, + remote_path=None, + ) + + +def test_run_extract_defaults_to_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True) + flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').with_args( + object, + object, + object, + object, + object, + object, + object, + local_path=object, + remote_path=object, + destination_path=object, + strip_components=object, + progress=True, + ).once() + extract_arguments = flexmock( + paths=flexmock(), + progress=None, + destination=flexmock(), + strip_components=flexmock(), + archive=flexmock(), + repository='repo', + ) + global_arguments = flexmock(monitoring_verbosity=1, dry_run=False) + + module.run_extract( + config_filename='test.yaml', + repository={'path': 'repo'}, + config={'repositories': ['repo'], 'progress': True}, + local_borg_version=None, + extract_arguments=extract_arguments, + global_arguments=global_arguments, + local_path=None, + remote_path=None, + ) diff --git a/tests/unit/actions/test_repo_create.py b/tests/unit/actions/test_repo_create.py index 035dd623..665d9db7 100644 --- a/tests/unit/actions/test_repo_create.py +++ b/tests/unit/actions/test_repo_create.py @@ -105,3 +105,91 @@ def test_run_repo_create_bails_if_repository_does_not_match(): local_path=None, remote_path=None, ) + + +def test_run_repo_create_favors_flags_over_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True) + flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository').with_args( + object, + object, + object, + object, + object, + object, + object, + object, + append_only=False, + storage_quota=0, + make_parent_dirs=False, + local_path=object, + remote_path=object, + ).once() + arguments = flexmock( + encryption_mode=flexmock(), + source_repository=flexmock(), + repository=flexmock(), + copy_crypt_key=flexmock(), + append_only=False, + storage_quota=0, + make_parent_dirs=False, + ) + + module.run_repo_create( + repository={ + 'path': 'repo', + 'append_only': True, + 'storage_quota': '10G', + 'make_parent_dirs': True, + }, + config={}, + local_borg_version=None, + repo_create_arguments=arguments, + global_arguments=flexmock(dry_run=False), + local_path=None, + remote_path=None, + ) + + +def test_run_repo_create_defaults_to_config(): + flexmock(module.logger).answer = lambda message: None + flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True) + flexmock(module.borgmatic.borg.repo_create).should_receive('create_repository').with_args( + object, + object, + object, + object, + object, + object, + object, + object, + append_only=True, + storage_quota='10G', + make_parent_dirs=True, + local_path=object, + remote_path=object, + ).once() + arguments = flexmock( + encryption_mode=flexmock(), + source_repository=flexmock(), + repository=flexmock(), + copy_crypt_key=flexmock(), + append_only=None, + storage_quota=None, + make_parent_dirs=None, + ) + + module.run_repo_create( + repository={ + 'path': 'repo', + 'append_only': True, + 'storage_quota': '10G', + 'make_parent_dirs': True, + }, + config={}, + local_borg_version=None, + repo_create_arguments=arguments, + global_arguments=flexmock(dry_run=False), + local_path=None, + remote_path=None, + ) diff --git a/tests/unit/borg/test_check.py b/tests/unit/borg/test_check.py index cb3ce67c..80ce0d94 100644 --- a/tests/unit/borg/test_check.py +++ b/tests/unit/borg/test_check.py @@ -331,8 +331,8 @@ def test_get_repository_id_with_missing_json_keys_raises(): ) -def test_check_archives_with_progress_passes_through_to_borg(): - config = {} +def test_check_archives_favors_progress_flag_over_config(): + config = {'progress': False} flexmock(module).should_receive('make_check_name_flags').with_args( {'repository'}, () ).and_return(()) @@ -366,6 +366,41 @@ def test_check_archives_with_progress_passes_through_to_borg(): ) +def test_check_archives_defaults_to_progress_config(): + config = {'progress': True} + flexmock(module).should_receive('make_check_name_flags').with_args( + {'repository'}, () + ).and_return(()) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',)) + flexmock(module.environment).should_receive('make_environment') + flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None) + flexmock(module).should_receive('execute_command').with_args( + ('borg', 'check', '--progress', 'repo'), + output_file=module.DO_NOT_CAPTURE, + environment=None, + working_directory=None, + borg_local_path='borg', + borg_exit_codes=None, + ).once() + + module.check_archives( + repository_path='repo', + config=config, + local_borg_version='1.2.3', + check_arguments=flexmock( + progress=None, + repair=None, + only_checks=None, + force=None, + match_archives=None, + max_duration=None, + ), + global_arguments=flexmock(log_json=False), + checks={'repository'}, + archive_filter_flags=(), + ) + + def test_check_archives_with_repair_passes_through_to_borg(): config = {} flexmock(module).should_receive('make_check_name_flags').with_args( diff --git a/tests/unit/borg/test_delete.py b/tests/unit/borg/test_delete.py index 6d8614b6..f6ace21d 100644 --- a/tests/unit/borg/test_delete.py +++ b/tests/unit/borg/test_delete.py @@ -171,7 +171,7 @@ def test_make_delete_command_includes_lock_wait(): assert command == ('borg', 'delete', '--lock-wait', '5', 'repo') -def test_make_delete_command_includes_list(): +def test_make_delete_command_favors_list_flag_over_config(): flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(()) flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args( 'list', True @@ -184,7 +184,7 @@ def test_make_delete_command_includes_list(): command = module.make_delete_command( repository={'path': 'repo'}, - config={}, + config={'list_details': False}, local_borg_version='1.2.3', delete_arguments=flexmock(list_archives=True, force=0, match_archives=None, archive=None), global_arguments=flexmock(dry_run=False, log_json=False), @@ -195,6 +195,30 @@ def test_make_delete_command_includes_list(): assert command == ('borg', 'delete', '--list', 'repo') +def test_make_delete_command_defaults_to_list_config(): + flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(()) + flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args( + 'list', True + ).and_return(('--list',)) + flexmock(module.borgmatic.borg.flags).should_receive('make_match_archives_flags').and_return(()) + flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(()) + flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return( + ('repo',) + ) + + command = module.make_delete_command( + repository={'path': 'repo'}, + config={'list_details': True}, + local_borg_version='1.2.3', + delete_arguments=flexmock(list_archives=None, force=0, match_archives=None, archive=None), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + remote_path=None, + ) + + assert command == ('borg', 'delete', '--list', 'repo') + + def test_make_delete_command_includes_force(): flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(()) flexmock(module.borgmatic.borg.flags).should_receive('make_match_archives_flags').and_return(()) @@ -287,8 +311,12 @@ def test_make_delete_command_includes_match_archives(): assert command == ('borg', 'delete', '--match-archives', 'sh:foo*', 'repo') +LOGGING_ANSWER = flexmock() + + def test_delete_archives_with_archive_calls_borg_delete(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = LOGGING_ANSWER flexmock(module.borgmatic.borg.repo_delete).should_receive('delete_repository').never() flexmock(module).should_receive('make_delete_command').and_return(flexmock()) flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return( @@ -308,6 +336,7 @@ def test_delete_archives_with_archive_calls_borg_delete(): def test_delete_archives_with_match_archives_calls_borg_delete(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = LOGGING_ANSWER flexmock(module.borgmatic.borg.repo_delete).should_receive('delete_repository').never() flexmock(module).should_receive('make_delete_command').and_return(flexmock()) flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return( @@ -328,6 +357,7 @@ def test_delete_archives_with_match_archives_calls_borg_delete(): @pytest.mark.parametrize('argument_name', module.ARCHIVE_RELATED_ARGUMENT_NAMES[2:]) def test_delete_archives_with_archive_related_argument_calls_borg_delete(argument_name): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = LOGGING_ANSWER flexmock(module.borgmatic.borg.repo_delete).should_receive('delete_repository').never() flexmock(module).should_receive('make_delete_command').and_return(flexmock()) flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return( @@ -347,6 +377,7 @@ def test_delete_archives_with_archive_related_argument_calls_borg_delete(argumen def test_delete_archives_without_archive_related_argument_calls_borg_repo_delete(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = LOGGING_ANSWER flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True) flexmock(module.borgmatic.borg.repo_delete).should_receive('delete_repository').once() flexmock(module).should_receive('make_delete_command').never() @@ -367,6 +398,7 @@ def test_delete_archives_without_archive_related_argument_calls_borg_repo_delete def test_delete_archives_calls_borg_delete_with_working_directory(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = LOGGING_ANSWER flexmock(module.borgmatic.borg.repo_delete).should_receive('delete_repository').never() command = flexmock() flexmock(module).should_receive('make_delete_command').and_return(command) diff --git a/tests/unit/borg/test_prune.py b/tests/unit/borg/test_prune.py index 3f2da33a..1d7888a3 100644 --- a/tests/unit/borg/test_prune.py +++ b/tests/unit/borg/test_prune.py @@ -361,7 +361,7 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_flags(): ) -def test_prune_archives_with_stats_calls_borg_with_stats_flag_and_answer_output_log_level(): +def test_prune_archives_favors_stats_flag_over_config(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS) @@ -375,14 +375,35 @@ def test_prune_archives_with_stats_calls_borg_with_stats_flag_and_answer_output_ module.prune_archives( dry_run=False, repository_path='repo', - config={}, + config={'statistics': False}, local_borg_version='1.2.3', global_arguments=flexmock(log_json=False), prune_arguments=prune_arguments, ) -def test_prune_archives_with_files_calls_borg_with_list_flag_and_answer_output_log_level(): +def test_prune_archives_defaults_to_stats_config(): + flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER + flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',)) + flexmock(module.feature).should_receive('available').with_args( + module.feature.Feature.NO_PRUNE_STATS, '1.2.3' + ).and_return(False) + insert_execute_command_mock(PRUNE_COMMAND + ('--stats', 'repo'), module.borgmatic.logger.ANSWER) + + prune_arguments = flexmock(stats=None, list_archives=False) + module.prune_archives( + dry_run=False, + repository_path='repo', + config={'statistics': True}, + local_borg_version='1.2.3', + global_arguments=flexmock(log_json=False), + prune_arguments=prune_arguments, + ) + + +def test_prune_archives_favors_list_flag_over_config(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS) @@ -396,7 +417,28 @@ def test_prune_archives_with_files_calls_borg_with_list_flag_and_answer_output_l module.prune_archives( dry_run=False, repository_path='repo', - config={}, + config={'list_details': False}, + local_borg_version='1.2.3', + global_arguments=flexmock(log_json=False), + prune_arguments=prune_arguments, + ) + + +def test_prune_archives_defaults_to_list_config(): + flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER + flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',)) + flexmock(module.feature).should_receive('available').with_args( + module.feature.Feature.NO_PRUNE_STATS, '1.2.3' + ).and_return(False) + insert_execute_command_mock(PRUNE_COMMAND + ('--list', 'repo'), module.borgmatic.logger.ANSWER) + + prune_arguments = flexmock(stats=False, list_archives=None) + module.prune_archives( + dry_run=False, + repository_path='repo', + config={'list_details': True}, local_borg_version='1.2.3', global_arguments=flexmock(log_json=False), prune_arguments=prune_arguments, diff --git a/tests/unit/borg/test_transfer.py b/tests/unit/borg/test_transfer.py index edd2131b..9e6618e5 100644 --- a/tests/unit/borg/test_transfer.py +++ b/tests/unit/borg/test_transfer.py @@ -436,7 +436,7 @@ def test_transfer_archives_with_lock_wait_calls_borg_with_lock_wait_flags(): ) -def test_transfer_archives_with_progress_calls_borg_with_progress_flag(): +def test_transfer_archives_favors_progress_flag_over_config(): 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(()) @@ -458,7 +458,7 @@ def test_transfer_archives_with_progress_calls_borg_with_progress_flag(): module.transfer_archives( dry_run=False, repository_path='repo', - config={}, + config={'progress': False}, local_borg_version='2.3.4', transfer_arguments=flexmock( archive=None, progress=True, match_archives=None, source_repository=None @@ -467,6 +467,37 @@ def test_transfer_archives_with_progress_calls_borg_with_progress_flag(): ) +def test_transfer_archives_defaults_to_progress_flag(): + 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.flags).should_receive('make_flags_from_arguments').and_return(('--progress',)) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) + flexmock(module.environment).should_receive('make_environment') + flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None) + flexmock(module).should_receive('execute_command').with_args( + ('borg', 'transfer', '--progress', '--repo', 'repo'), + output_log_level=module.borgmatic.logger.ANSWER, + output_file=module.DO_NOT_CAPTURE, + environment=None, + working_directory=None, + borg_local_path='borg', + borg_exit_codes=None, + ) + + module.transfer_archives( + dry_run=False, + repository_path='repo', + config={'progress': True}, + local_borg_version='2.3.4', + transfer_arguments=flexmock( + archive=None, progress=None, match_archives=None, source_repository=None + ), + global_arguments=flexmock(log_json=False), + ) + + @pytest.mark.parametrize('argument_name', ('upgrader', 'sort_by', 'first', 'last')) def test_transfer_archives_passes_through_arguments_to_borg(argument_name): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')