Bladeren bron

Fix error with "info --match-archives" and fix "--match-archives" overriding logic (#666).

Dan Helfman 2 jaren geleden
bovenliggende
commit
616eb6b6da

+ 5 - 0
NEWS

@@ -1,3 +1,8 @@
+1.7.12.dev0
+ * #666: Fix error when running the "info" action with the "--match-archives" flag. Also fix the
+   "--match-archives" flag to correctly override the "match_archives" configuration option for
+   the "transfer", "list", "rlist", and "info" actions.
+
 1.7.11
 1.7.11
  * #479, #588: BREAKING: Automatically use the "archive_name_format" option to filter which archives
  * #479, #588: BREAKING: Automatically use the "archive_name_format" option to filter which archives
    get used for borgmatic actions that operate on multiple archives. Override this behavior with the
    get used for borgmatic actions that operate on multiple archives. Override this behavior with the

+ 4 - 7
borgmatic/borg/info.py

@@ -46,21 +46,18 @@ def display_archives_info(
             if info_arguments.prefix
             if info_arguments.prefix
             else (
             else (
                 flags.make_match_archives_flags(
                 flags.make_match_archives_flags(
-                    storage_config.get('match_archives'),
+                    info_arguments.match_archives
+                    or info_arguments.archive
+                    or storage_config.get('match_archives'),
                     storage_config.get('archive_name_format'),
                     storage_config.get('archive_name_format'),
                     local_borg_version,
                     local_borg_version,
                 )
                 )
             )
             )
         )
         )
         + flags.make_flags_from_arguments(
         + flags.make_flags_from_arguments(
-            info_arguments, excludes=('repository', 'archive', 'prefix')
+            info_arguments, excludes=('repository', 'archive', 'prefix', 'match_archives')
         )
         )
         + flags.make_repository_flags(repository_path, local_borg_version)
         + flags.make_repository_flags(repository_path, local_borg_version)
-        + (
-            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)
-        )
     )
     )
 
 
     if info_arguments.json:
     if info_arguments.json:

+ 2 - 2
borgmatic/borg/rlist.py

@@ -52,7 +52,7 @@ def resolve_archive_name(
     return latest_archive
     return latest_archive
 
 
 
 
-MAKE_FLAGS_EXCLUDES = ('repository', 'prefix')
+MAKE_FLAGS_EXCLUDES = ('repository', 'prefix', 'match_archives')
 
 
 
 
 def make_rlist_command(
 def make_rlist_command(
@@ -96,7 +96,7 @@ def make_rlist_command(
             if rlist_arguments.prefix
             if rlist_arguments.prefix
             else (
             else (
                 flags.make_match_archives_flags(
                 flags.make_match_archives_flags(
-                    storage_config.get('match_archives'),
+                    rlist_arguments.match_archives or storage_config.get('match_archives'),
                     storage_config.get('archive_name_format'),
                     storage_config.get('archive_name_format'),
                     local_borg_version,
                     local_borg_version,
                 )
                 )

+ 3 - 7
borgmatic/borg/transfer.py

@@ -28,12 +28,6 @@ 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))
-        + (('--progress',) if transfer_arguments.progress else ())
-        + (
-            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,
@@ -41,7 +35,9 @@ def transfer_archives(
             )
             )
             or (
             or (
                 flags.make_match_archives_flags(
                 flags.make_match_archives_flags(
-                    storage_config.get('match_archives'),
+                    transfer_arguments.match_archives
+                    or transfer_arguments.archive
+                    or storage_config.get('match_archives'),
                     storage_config.get('archive_name_format'),
                     storage_config.get('archive_name_format'),
                     local_borg_version,
                     local_borg_version,
                 )
                 )

+ 16 - 4
borgmatic/commands/arguments.py

@@ -652,7 +652,7 @@ def make_parsers():
         '--json', default=False, action='store_true', help='Output results as JSON'
         '--json', default=False, action='store_true', help='Output results as JSON'
     )
     )
     rlist_group.add_argument(
     rlist_group.add_argument(
-        '-P', '--prefix', help='Only list archive names starting with this prefix'
+        '-P', '--prefix', help='Deprecated. Only list archive names starting with this prefix'
     )
     )
     rlist_group.add_argument(
     rlist_group.add_argument(
         '-a',
         '-a',
@@ -707,7 +707,7 @@ def make_parsers():
         '--json', default=False, action='store_true', help='Output results as JSON'
         '--json', default=False, action='store_true', help='Output results as JSON'
     )
     )
     list_group.add_argument(
     list_group.add_argument(
-        '-P', '--prefix', help='Only list archive names starting with this prefix'
+        '-P', '--prefix', help='Deprecated. Only list archive names starting with this prefix'
     )
     )
     list_group.add_argument(
     list_group.add_argument(
         '-a',
         '-a',
@@ -779,7 +779,9 @@ def make_parsers():
         '--json', dest='json', default=False, action='store_true', help='Output results as JSON'
         '--json', dest='json', default=False, action='store_true', help='Output results as JSON'
     )
     )
     info_group.add_argument(
     info_group.add_argument(
-        '-P', '--prefix', help='Only show info for archive names starting with this prefix'
+        '-P',
+        '--prefix',
+        help='Deprecated. Only show info for archive names starting with this prefix',
     )
     )
     info_group.add_argument(
     info_group.add_argument(
         '-a',
         '-a',
@@ -877,7 +879,17 @@ def parse_arguments(*unparsed_arguments):
         and arguments['transfer'].match_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 --match-archives flags can be used.'
+        )
+
+    if 'list' in arguments and (arguments['list'].prefix and arguments['list'].match_archives):
+        raise ValueError(
+            'With the list action, only one of --prefix or --match-archives flags can be used.'
+        )
+
+    if 'rlist' in arguments and (arguments['rlist'].prefix and arguments['rlist'].match_archives):
+        raise ValueError(
+            'With the rlist action, only one of --prefix or --match-archives flags can be used.'
         )
         )
 
 
     if 'info' in arguments and (
     if 'info' in arguments and (

+ 6 - 2
docs/how-to/make-per-application-backups.md

@@ -128,13 +128,17 @@ documentation](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg-
 for more information. For Borg 2.x, see the [match archives
 for more information. For Borg 2.x, see the [match archives
 documentation](https://borgbackup.readthedocs.io/en/2.0.0b5/usage/help.html#borg-help-match-archives).
 documentation](https://borgbackup.readthedocs.io/en/2.0.0b5/usage/help.html#borg-help-match-archives).
 
 
+Some borgmatic command-line actions also have a `--match-archives` flag that
+overrides both the auto-matching behavior and the `match_archives`
+configuration option.
+
 <span class="minilink minilink-addedin">Prior to 1.7.11</span> The way to
 <span class="minilink minilink-addedin">Prior to 1.7.11</span> The way to
 limit the archives used for the `prune` action was a `prefix` option in the
 limit the archives used for the `prune` action was a `prefix` option in the
 `retention` section for matching against the start of archive names. And the
 `retention` section for matching against the start of archive names. And the
 option for limiting the archives used for the `check` action was a separate
 option for limiting the archives used for the `check` action was a separate
 `prefix` in the `consistency` section. Both of these options are deprecated in
 `prefix` in the `consistency` section. Both of these options are deprecated in
-favor of the auto-matching behavior (or `match_archives`) in newer versions of
-borgmatic.
+favor of the auto-matching behavior (or `match_archives`/`--match-archives`)
+in newer versions of borgmatic.
 
 
 
 
 ## Configuration includes
 ## Configuration includes

+ 1 - 1
setup.py

@@ -1,6 +1,6 @@
 from setuptools import find_packages, setup
 from setuptools import find_packages, setup
 
 
-VERSION = '1.7.11'
+VERSION = '1.7.12.dev0'
 
 
 
 
 setup(
 setup(

+ 104 - 0
tests/integration/borg/test_commands.py

@@ -0,0 +1,104 @@
+import copy
+
+import flexmock
+
+import borgmatic.borg.info
+import borgmatic.borg.list
+import borgmatic.borg.rlist
+import borgmatic.borg.transfer
+import borgmatic.commands.arguments
+
+
+def assert_command_does_not_duplicate_flags(command, *args, **kwargs):
+    '''
+    Assert that the given Borg command sequence does not contain any duplicated flags, e.g.
+    "--match-archives" twice anywhere in the command.
+    '''
+    flag_counts = {}
+
+    for flag_name in command:
+        if not flag_name.startswith('--'):
+            continue
+
+        if flag_name in flag_counts:
+            flag_counts[flag_name] += 1
+        else:
+            flag_counts[flag_name] = 1
+
+    assert flag_counts == {
+        flag_name: 1 for flag_name in flag_counts
+    }, f"Duplicate flags found in: {' '.join(command)}"
+
+
+def fuzz_argument(arguments, argument_name):
+    '''
+    Given an argparse.Namespace instance of arguments and an argument name in it, copy the arguments
+    namespace and set the argument name in the copy with a fake value. Return the copied arguments.
+
+    This is useful for "fuzzing" a unit under test by passing it each possible argument in turn,
+    making sure it doesn't blow up or duplicate Borg arguments.
+    '''
+    arguments_copy = copy.copy(arguments)
+    value = getattr(arguments_copy, argument_name)
+    setattr(arguments_copy, argument_name, not value if isinstance(value, bool) else 'value')
+
+    return arguments_copy
+
+
+def test_transfer_archives_command_does_not_duplicate_flags_or_raise():
+    arguments = borgmatic.commands.arguments.parse_arguments(
+        'transfer', '--source-repository', 'foo'
+    )['transfer']
+    flexmock(borgmatic.borg.transfer).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.transfer.transfer_archives(
+            False, 'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name)
+        )
+
+
+def test_make_list_command_does_not_duplicate_flags_or_raise():
+    arguments = borgmatic.commands.arguments.parse_arguments('list')['list']
+
+    for argument_name in dir(arguments):
+        if argument_name.startswith('_'):
+            continue
+
+        borgmatic.borg.list.make_list_command(
+            'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name)
+        )
+
+
+def test_make_rlist_command_does_not_duplicate_flags_or_raise():
+    arguments = borgmatic.commands.arguments.parse_arguments('rlist')['rlist']
+
+    for argument_name in dir(arguments):
+        if argument_name.startswith('_'):
+            continue
+
+        borgmatic.borg.rlist.make_rlist_command(
+            'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name)
+        )
+
+
+def test_display_archives_info_command_does_not_duplicate_flags_or_raise():
+    arguments = borgmatic.commands.arguments.parse_arguments('info')['info']
+    flexmock(borgmatic.borg.info).should_receive('execute_command_and_capture_output').replace_with(
+        assert_command_does_not_duplicate_flags
+    )
+    flexmock(borgmatic.borg.info).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.info.display_archives_info(
+            'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name)
+        )

+ 14 - 0
tests/integration/commands/test_arguments.py

@@ -465,6 +465,20 @@ def test_parse_arguments_disallows_transfer_with_both_archive_and_match_archives
         )
         )
 
 
 
 
+def test_parse_arguments_disallows_list_with_both_prefix_and_match_archives():
+    flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
+
+    with pytest.raises(ValueError):
+        module.parse_arguments('list', '--prefix', 'foo', '--match-archives', 'sh:*bar')
+
+
+def test_parse_arguments_disallows_rlist_with_both_prefix_and_match_archives():
+    flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
+
+    with pytest.raises(ValueError):
+        module.parse_arguments('rlist', '--prefix', 'foo', '--match-archives', 'sh:*bar')
+
+
 def test_parse_arguments_disallows_info_with_both_archive_and_match_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'])
 
 

+ 71 - 19
tests/unit/borg/test_info.py

@@ -29,7 +29,7 @@ def test_display_archives_info_calls_borg_with_parameters():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
     )
     )
 
 
 
 
@@ -54,7 +54,7 @@ def test_display_archives_info_with_log_info_calls_borg_with_info_parameter():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
     )
     )
 
 
 
 
@@ -77,7 +77,7 @@ def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_outpu
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=True, prefix=None),
+        info_arguments=flexmock(archive=None, json=True, prefix=None, match_archives=None),
     )
     )
 
 
     assert json_output == '[]'
     assert json_output == '[]'
@@ -105,7 +105,7 @@ def test_display_archives_info_with_log_debug_calls_borg_with_debug_parameter():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
     )
     )
 
 
 
 
@@ -128,7 +128,7 @@ def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_outp
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=True, prefix=None),
+        info_arguments=flexmock(archive=None, json=True, prefix=None, match_archives=None),
     )
     )
 
 
     assert json_output == '[]'
     assert json_output == '[]'
@@ -152,7 +152,7 @@ def test_display_archives_info_with_json_calls_borg_with_json_parameter():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=True, prefix=None),
+        info_arguments=flexmock(archive=None, json=True, prefix=None, match_archives=None),
     )
     )
 
 
     assert json_output == '[]'
     assert json_output == '[]'
@@ -162,17 +162,14 @@ def test_display_archives_info_with_archive_calls_borg_with_match_archives_param
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     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(
-        'match-archives', 'archive'
-    ).and_return(('--match-archives', 'archive'))
     flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
     flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
-        None, None, '2.3.4'
-    ).and_return(())
+        'archive', None, '2.3.4'
+    ).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', '--match-archives', 'archive'),
+        ('borg', 'info', '--match-archives', 'archive', '--repo', 'repo'),
         output_log_level=module.borgmatic.logger.ANSWER,
         output_log_level=module.borgmatic.logger.ANSWER,
         borg_local_path='borg',
         borg_local_path='borg',
         extra_environment=None,
         extra_environment=None,
@@ -182,7 +179,7 @@ def test_display_archives_info_with_archive_calls_borg_with_match_archives_param
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive='archive', json=False, prefix=None),
+        info_arguments=flexmock(archive='archive', json=False, prefix=None, match_archives=None),
     )
     )
 
 
 
 
@@ -207,7 +204,7 @@ def test_display_archives_info_with_local_path_calls_borg_via_local_path():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
         local_path='borg1',
         local_path='borg1',
     )
     )
 
 
@@ -236,7 +233,7 @@ def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_para
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
         remote_path='borg1',
         remote_path='borg1',
     )
     )
 
 
@@ -266,7 +263,7 @@ def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_paramete
         repository_path='repo',
         repository_path='repo',
         storage_config=storage_config,
         storage_config=storage_config,
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
     )
     )
 
 
 
 
@@ -347,11 +344,64 @@ def test_display_archives_info_transforms_archive_name_format_into_match_archive
         repository_path='repo',
         repository_path='repo',
         storage_config={'archive_name_format': 'bar-{now}'},  # noqa: FS003
         storage_config={'archive_name_format': 'bar-{now}'},  # noqa: FS003
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
+    )
+
+
+def test_display_archives_with_match_archives_option_calls_borg_with_match_archives_parameter():
+    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(
+        'sh:foo-*', 'bar-{now}', '2.3.4'  # noqa: FS003
+    ).and_return(('--match-archives', 'sh:foo-*'))
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
+    flexmock(module.environment).should_receive('make_environment')
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'info', '--match-archives', 'sh:foo-*', '--repo', 'repo'),
+        output_log_level=module.borgmatic.logger.ANSWER,
+        borg_local_path='borg',
+        extra_environment=None,
+    )
+
+    module.display_archives_info(
+        repository_path='repo',
+        storage_config={
+            'archive_name_format': 'bar-{now}',  # noqa: FS003
+            'match_archives': 'sh:foo-*',
+        },
+        local_borg_version='2.3.4',
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
+    )
+
+
+def test_display_archives_with_match_archives_flag_calls_borg_with_match_archives_parameter():
+    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(
+        'sh:foo-*', 'bar-{now}', '2.3.4'  # noqa: FS003
+    ).and_return(('--match-archives', 'sh:foo-*'))
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
+    flexmock(module.environment).should_receive('make_environment')
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'info', '--match-archives', 'sh:foo-*', '--repo', 'repo'),
+        output_log_level=module.borgmatic.logger.ANSWER,
+        borg_local_path='borg',
+        extra_environment=None,
+    )
+
+    module.display_archives_info(
+        repository_path='repo',
+        storage_config={'archive_name_format': 'bar-{now}'},  # noqa: FS003
+        local_borg_version='2.3.4',
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives='sh:foo-*'),
     )
     )
 
 
 
 
-@pytest.mark.parametrize('argument_name', ('match_archives', 'sort_by', 'first', 'last'))
+@pytest.mark.parametrize('argument_name', ('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):
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
@@ -376,5 +426,7 @@ def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
-        info_arguments=flexmock(archive=None, json=False, prefix=None, **{argument_name: 'value'}),
+        info_arguments=flexmock(
+            archive=None, json=False, prefix=None, match_archives=None, **{argument_name: 'value'}
+        ),
     )
     )

+ 61 - 20
tests/unit/borg/test_rlist.py

@@ -137,7 +137,9 @@ def test_make_rlist_command_includes_log_info():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--info', 'repo')
     assert command == ('borg', 'list', '--info', 'repo')
@@ -156,7 +158,9 @@ def test_make_rlist_command_includes_json_but_not_info():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=True, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=True, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--json', 'repo')
     assert command == ('borg', 'list', '--json', 'repo')
@@ -175,7 +179,9 @@ def test_make_rlist_command_includes_log_debug():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--debug', '--show-rc', 'repo')
     assert command == ('borg', 'list', '--debug', '--show-rc', 'repo')
@@ -194,7 +200,9 @@ def test_make_rlist_command_includes_json_but_not_debug():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=True, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=True, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--json', 'repo')
     assert command == ('borg', 'list', '--json', 'repo')
@@ -212,7 +220,9 @@ def test_make_rlist_command_includes_json():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=True, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=True, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--json', 'repo')
     assert command == ('borg', 'list', '--json', 'repo')
@@ -232,7 +242,9 @@ def test_make_rlist_command_includes_lock_wait():
         repository_path='repo',
         repository_path='repo',
         storage_config={'lock_wait': 5},
         storage_config={'lock_wait': 5},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--lock-wait', '5', 'repo')
     assert command == ('borg', 'list', '--lock-wait', '5', 'repo')
@@ -250,7 +262,9 @@ def test_make_rlist_command_includes_local_path():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
         local_path='borg2',
         local_path='borg2',
     )
     )
 
 
@@ -271,7 +285,9 @@ def test_make_rlist_command_includes_remote_path():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
         remote_path='borg2',
         remote_path='borg2',
     )
     )
 
 
@@ -328,7 +344,9 @@ def test_make_rlist_command_transforms_archive_name_format_into_match_archives()
         repository_path='repo',
         repository_path='repo',
         storage_config={'archive_name_format': 'bar-{now}'},  # noqa: FS003
         storage_config={'archive_name_format': 'bar-{now}'},  # noqa: FS003
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--match-archives', 'sh:bar-*', 'repo')
     assert command == ('borg', 'list', '--match-archives', 'sh:bar-*', 'repo')
@@ -346,7 +364,9 @@ def test_make_rlist_command_includes_short():
         repository_path='repo',
         repository_path='repo',
         storage_config={},
         storage_config={},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
-        rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None, short=True),
+        rlist_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None, short=True
+        ),
     )
     )
 
 
     assert command == ('borg', 'list', '--short', 'repo')
     assert command == ('borg', 'list', '--short', 'repo')
@@ -354,16 +374,7 @@ def test_make_rlist_command_includes_short():
 
 
 @pytest.mark.parametrize(
 @pytest.mark.parametrize(
     'argument_name',
     'argument_name',
-    (
-        'match_archives',
-        'sort_by',
-        'first',
-        'last',
-        'exclude',
-        'exclude_from',
-        'pattern',
-        'patterns_from',
-    ),
+    ('sort_by', 'first', 'last', 'exclude', 'exclude_from', 'pattern', 'patterns_from',),
 )
 )
 def test_make_rlist_command_includes_additional_flags(argument_name):
 def test_make_rlist_command_includes_additional_flags(argument_name):
     flexmock(module.flags).should_receive('make_flags').and_return(())
     flexmock(module.flags).should_receive('make_flags').and_return(())
@@ -384,6 +395,7 @@ def test_make_rlist_command_includes_additional_flags(argument_name):
             paths=None,
             paths=None,
             json=False,
             json=False,
             prefix=None,
             prefix=None,
+            match_archives=None,
             find_paths=None,
             find_paths=None,
             format=None,
             format=None,
             **{argument_name: 'value'},
             **{argument_name: 'value'},
@@ -393,6 +405,35 @@ def test_make_rlist_command_includes_additional_flags(argument_name):
     assert command == ('borg', 'list', '--' + argument_name.replace('_', '-'), 'value', 'repo')
     assert command == ('borg', 'list', '--' + argument_name.replace('_', '-'), 'value', 'repo')
 
 
 
 
+def test_make_rlist_command_with_match_archives_calls_borg_with_match_archives_parameters():
+    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_match_archives_flags').with_args(
+        'foo-*', None, '1.2.3',
+    ).and_return(('--match-archives', 'foo-*'))
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
+
+    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='foo-*',
+            find_paths=None,
+            format=None,
+        ),
+    )
+
+    assert command == ('borg', 'list', '--match-archives', 'foo-*', 'repo')
+
+
 def test_list_repository_calls_borg_with_parameters():
 def test_list_repository_calls_borg_with_parameters():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER

+ 5 - 7
tests/unit/borg/test_transfer.py

@@ -124,10 +124,9 @@ def test_transfer_archives_with_archive_calls_borg_with_match_archives_flag():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     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(
-        'match-archives', 'archive'
+    flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
+        'archive', 'bar-{now}', '2.3.4'  # noqa: FS003
     ).and_return(('--match-archives', 'archive'))
     ).and_return(('--match-archives', 'archive'))
-    flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
     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')
@@ -154,10 +153,9 @@ def test_transfer_archives_with_match_archives_calls_borg_with_match_archives_fl
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     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(
-        'match-archives', 'sh:foo*'
+    flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
+        'sh:foo*', 'bar-{now}', '2.3.4'  # noqa: FS003
     ).and_return(('--match-archives', 'sh:foo*'))
     ).and_return(('--match-archives', 'sh:foo*'))
-    flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
     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')
@@ -304,7 +302,7 @@ def test_transfer_archives_with_progress_calls_borg_with_progress_flag():
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.flags).should_receive('make_flags').and_return(())
     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_match_archives_flags').and_return(())
-    flexmock(module.flags).should_receive('make_flags_from_arguments').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.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(