Browse Source

Fix a regression in the ZFS, LVM, and Btrfs hooks in which snapshotted paths ignored global excludes (#1195).

Dan Helfman 17 hours ago
parent
commit
50a062611e

+ 2 - 0
NEWS

@@ -4,6 +4,8 @@
    snapshotting these source directories.
  * #1194: Fix for an incorrect diff command shown when running the "generate config" action with a
    source configuration file. 
+ * #1195: Fix a regression in the ZFS, LVM, and Btrfs hooks in which snapshotted paths ignored
+   global excludes.
  * Update the sample systemd timer with a shorter random delay when catching up on a missed run.
 
 2.0.12

+ 1 - 7
borgmatic/hooks/data_source/btrfs.py

@@ -329,15 +329,9 @@ def dump_data_sources(
 
         snapshot_subvolume(btrfs_command, subvolume.path, snapshot_path)
 
-        last_contained_pattern_index = borgmatic.hooks.data_source.config.get_last_pattern_index(
-            patterns, subvolume.contained_patterns
-        )
-
         for pattern in subvolume.contained_patterns:
             snapshot_pattern = make_borg_snapshot_pattern(subvolume.path, pattern)
-            borgmatic.hooks.data_source.config.replace_pattern(
-                patterns, pattern, snapshot_pattern, last_contained_pattern_index
-            )
+            borgmatic.hooks.data_source.config.replace_pattern(patterns, pattern, snapshot_pattern)
 
         borgmatic.hooks.data_source.config.inject_pattern(
             patterns, make_snapshot_exclude_pattern(subvolume.path)

+ 9 - 64
borgmatic/hooks/data_source/config.py

@@ -1,4 +1,3 @@
-import contextlib
 import json
 import logging
 import shutil
@@ -106,18 +105,20 @@ def get_ip_from_container(container):
     )
 
 
-def inject_pattern(patterns, data_source_pattern):
+def inject_pattern(patterns, data_source_pattern, override_excludes=True):
     '''
     Given a list of borgmatic.borg.pattern.Pattern instances representing the configured patterns,
     insert the given data source pattern at the start of the list. The idea is that borgmatic is
     injecting its own custom pattern specific to a data source hook into the user's configured
     patterns so that the hook's data gets included in the backup.
 
-    As part of this injection, if the data source pattern is a root pattern, also insert an
-    "include" version of the given root pattern, in an attempt to preempt any of the user's
-    configured exclude patterns that may follow.
+    As part of this injection, if the data source pattern is a root pattern and override_excludes is
+    True, also insert an "include" version of the given root pattern, in an attempt to preempt any
+    of the user's configured exclude patterns that may follow. The is to support use cases like
+    borgmatic injecting its own patterns for things like database dumps or bootstrap metadata, where
+    we don't want them to get accidentally excluded.
     '''
-    if data_source_pattern.type == borgmatic.borg.pattern.Pattern_type.ROOT:
+    if data_source_pattern.type == borgmatic.borg.pattern.Pattern_type.ROOT and override_excludes:
         patterns.insert(
             0,
             borgmatic.borg.pattern.Pattern(
@@ -132,77 +133,21 @@ def inject_pattern(patterns, data_source_pattern):
     patterns.insert(0, data_source_pattern)
 
 
-def get_last_pattern_index(patterns, patterns_subset):
-    '''
-    Given a sequence of all patterns and a subset of those patterns, find each subset pattern in the
-    all patterns sequence and return the highest (last) index.
-    '''
-    last_pattern_index = 0
-
-    for pattern in patterns_subset:
-        with contextlib.suppress(ValueError):
-            last_pattern_index = max(patterns.index(pattern), last_pattern_index)
-
-    return last_pattern_index
-
-
-def replace_pattern(
-    patterns, pattern_to_replace, data_source_pattern, last_contained_pattern_index
-):
+def replace_pattern(patterns, pattern_to_replace, data_source_pattern):
     '''
     Given a list of borgmatic.borg.pattern.Pattern instances representing the configured patterns,
     replace the given pattern with the given data source pattern. The idea is that borgmatic is
     replacing a configured pattern with its own modified pattern specific to a data source hook so
     that the hook's data gets included in the backup.
 
-    As part of this replacement, if the data source pattern is a root pattern, also insert an
-    "include" version of the given root pattern right after the given last contained pattern index
-    in an attempt to preempt any of the user's configured global exclude patterns that may follow.
-    But we don't want to preempt any intentional partial excludes of the data source pattern itself,
-    which is why the include goes after the last contained pattern index.
-
-    For instance, let's say that the patterns are effectively:
-
-       R /foo
-       R /bar
-       - /bar/.cache
-       R /baz
-       - **
-
-    ... and "R /bar" is the pattern to replace, data source pattern is "R /bar/snapshot", and the
-    last contained pattern index is 2 (corresponding to "- /bar/.cache"). The resulting patterns
-    after calling this function would be:
-
-       R /foo
-       R /bar/snapshot
-       - /bar/snapshot/.cache
-       + /bar/snapshot
-       R /baz
-       - **
-
-    Note that the positioning of "+ /bar/snapshot" means that it overrides the "- **" global exclude
-    but not the "- /bar/snapshot/.cache" contained pattern exclude.
-
     If the pattern to replace can't be found in the given patterns, then just inject the data source
     pattern at the start of the list.
     '''
     try:
         index = patterns.index(pattern_to_replace)
     except ValueError:
-        inject_pattern(patterns, data_source_pattern)
+        inject_pattern(patterns, data_source_pattern, override_excludes=False)
 
         return
 
     patterns[index] = data_source_pattern
-
-    if data_source_pattern.type == borgmatic.borg.pattern.Pattern_type.ROOT:
-        patterns.insert(
-            last_contained_pattern_index + 1,
-            borgmatic.borg.pattern.Pattern(
-                path=data_source_pattern.path,
-                type=borgmatic.borg.pattern.Pattern_type.INCLUDE,
-                style=data_source_pattern.style,
-                device=data_source_pattern.device,
-                source=borgmatic.borg.pattern.Pattern_source.HOOK,
-            ),
-        )

+ 1 - 7
borgmatic/hooks/data_source/lvm.py

@@ -269,10 +269,6 @@ def dump_data_sources(
             snapshot_mount_path,
         )
 
-        last_contained_pattern_index = borgmatic.hooks.data_source.config.get_last_pattern_index(
-            patterns, logical_volume.contained_patterns
-        )
-
         for pattern in logical_volume.contained_patterns:
             snapshot_pattern = make_borg_snapshot_pattern(
                 pattern,
@@ -280,9 +276,7 @@ def dump_data_sources(
                 normalized_runtime_directory,
             )
 
-            borgmatic.hooks.data_source.config.replace_pattern(
-                patterns, pattern, snapshot_pattern, last_contained_pattern_index
-            )
+            borgmatic.hooks.data_source.config.replace_pattern(patterns, pattern, snapshot_pattern)
 
     return []
 

+ 1 - 7
borgmatic/hooks/data_source/zfs.py

@@ -300,10 +300,6 @@ def dump_data_sources(
             snapshot_mount_path,
         )
 
-        last_contained_pattern_index = borgmatic.hooks.data_source.config.get_last_pattern_index(
-            patterns, dataset.contained_patterns
-        )
-
         for pattern in dataset.contained_patterns:
             snapshot_pattern = make_borg_snapshot_pattern(
                 pattern,
@@ -311,9 +307,7 @@ def dump_data_sources(
                 normalized_runtime_directory,
             )
 
-            borgmatic.hooks.data_source.config.replace_pattern(
-                patterns, pattern, snapshot_pattern, last_contained_pattern_index
-            )
+            borgmatic.hooks.data_source.config.replace_pattern(patterns, pattern, snapshot_pattern)
 
     return []
 

+ 0 - 2
tests/integration/hooks/data_source/test_btrfs.py

@@ -62,9 +62,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
         Pattern('/foo'),
         Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1'),
         Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1/.cache', Pattern_type.EXCLUDE),
-        Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1', Pattern_type.INCLUDE),
         Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2'),
-        Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2', Pattern_type.INCLUDE),
     ]
     assert config == {
         'btrfs': {},

+ 0 - 2
tests/integration/hooks/data_source/test_lvm.py

@@ -85,7 +85,5 @@ def test_dump_data_sources_snapshots_and_mounts_and_updates_patterns():
         Pattern(
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir/.cache', Pattern_type.EXCLUDE
         ),
-        Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir', Pattern_type.INCLUDE),
         Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'),
-        Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2', Pattern_type.INCLUDE),
     ]

+ 1 - 2
tests/integration/hooks/data_source/test_zfs.py

@@ -2,7 +2,7 @@ import os
 
 from flexmock import flexmock
 
-from borgmatic.borg.pattern import Pattern, Pattern_type
+from borgmatic.borg.pattern import Pattern
 from borgmatic.hooks.data_source import zfs as module
 
 
@@ -44,5 +44,4 @@ def test_dump_data_sources_snapshots_and_mounts_and_updates_patterns():
 
     assert patterns == [
         Pattern(os.path.join(snapshot_mount_path, 'subdir')),
-        Pattern(os.path.join(snapshot_mount_path, 'subdir'), Pattern_type.INCLUDE),
     ]

+ 0 - 19
tests/unit/hooks/data_source/test_btrfs.py

@@ -450,9 +450,6 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
         '/mnt/subvol2',
         object,
     ).and_return(Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/subvol1'),
@@ -460,7 +457,6 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
             '/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
@@ -469,7 +465,6 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
             '/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
         object,
@@ -532,9 +527,6 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
         '/mnt/subvol1',
         object,
     ).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/subvol1'),
@@ -542,7 +534,6 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
             '/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
         object,
@@ -603,9 +594,6 @@ def test_dump_data_sources_with_findmnt_command_warns():
         '/mnt/subvol1',
         object,
     ).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/subvol1'),
@@ -613,7 +601,6 @@ def test_dump_data_sources_with_findmnt_command_warns():
             '/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
         object,
@@ -654,9 +641,6 @@ def test_dump_data_sources_with_dry_run_skips_snapshot_and_patterns_update():
     )
     flexmock(module).should_receive('snapshot_subvolume').never()
     flexmock(module).should_receive('make_snapshot_exclude_pattern').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').never()
 
@@ -682,9 +666,6 @@ def test_dump_data_sources_without_matching_subvolumes_skips_snapshot_and_patter
     flexmock(module).should_receive('make_snapshot_path').never()
     flexmock(module).should_receive('snapshot_subvolume').never()
     flexmock(module).should_receive('make_snapshot_exclude_pattern').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').never()
 

+ 15 - 69
tests/unit/hooks/data_source/test_config.py

@@ -203,51 +203,24 @@ def test_inject_pattern_with_root_pattern_prepends_it_along_with_corresponding_i
     ]
 
 
-def test_get_last_pattern_index_with_ordered_subset_patterns_finds_last_one():
+def test_inject_pattern_with_root_pattern_and_override_excludes_false_omits_include_pattern():
     patterns = [
-        module.borgmatic.borg.pattern.Pattern('/foo'),
-        module.borgmatic.borg.pattern.Pattern('/bar'),
-        module.borgmatic.borg.pattern.Pattern('/baz'),
-        module.borgmatic.borg.pattern.Pattern('/quux'),
-    ]
-    patterns_subset = [
-        module.borgmatic.borg.pattern.Pattern('/bar'),
-        module.borgmatic.borg.pattern.Pattern('/baz'),
-    ]
-
-    assert module.get_last_pattern_index(patterns, patterns_subset) == 2
-
-
-def test_get_last_pattern_index_with_unordered_subset_patterns_finds_last_one():
-    patterns = [
-        module.borgmatic.borg.pattern.Pattern('/foo'),
-        module.borgmatic.borg.pattern.Pattern('/bar'),
-        module.borgmatic.borg.pattern.Pattern('/baz'),
-        module.borgmatic.borg.pattern.Pattern('/quux'),
-    ]
-    patterns_subset = [
-        module.borgmatic.borg.pattern.Pattern('/baz'),
-        module.borgmatic.borg.pattern.Pattern('/bar'),
+        module.borgmatic.borg.pattern.Pattern('/etc'),
+        module.borgmatic.borg.pattern.Pattern('/var'),
     ]
 
-    assert module.get_last_pattern_index(patterns, patterns_subset) == 2
-
+    module.inject_pattern(
+        patterns,
+        module.borgmatic.borg.pattern.Pattern('/foo/bar'),
+        override_excludes=False,
+    )
 
-def test_get_last_pattern_index_with_unknown_subset_patterns_skips_it():
-    patterns = [
-        module.borgmatic.borg.pattern.Pattern('/foo'),
-        module.borgmatic.borg.pattern.Pattern('/bar'),
-        module.borgmatic.borg.pattern.Pattern('/baz'),
-        module.borgmatic.borg.pattern.Pattern('/quux'),
-    ]
-    patterns_subset = [
-        module.borgmatic.borg.pattern.Pattern('/baz'),
-        module.borgmatic.borg.pattern.Pattern('/unknown'),
-        module.borgmatic.borg.pattern.Pattern('/bar'),
+    assert patterns == [
+        module.borgmatic.borg.pattern.Pattern('/foo/bar'),
+        module.borgmatic.borg.pattern.Pattern('/etc'),
+        module.borgmatic.borg.pattern.Pattern('/var'),
     ]
 
-    assert module.get_last_pattern_index(patterns, patterns_subset) == 2
-
 
 def test_replace_pattern_swaps_out_pattern_in_place():
     patterns = [
@@ -263,7 +236,6 @@ def test_replace_pattern_swaps_out_pattern_in_place():
             '/foo/bar',
             type=module.borgmatic.borg.pattern.Pattern_type.EXCLUDE,
         ),
-        0,
     )
 
     assert patterns == [
@@ -283,39 +255,13 @@ def test_replace_pattern_with_unknown_pattern_falls_back_to_injecting():
         module.borgmatic.borg.pattern.Pattern('/lib'),
     ]
     flexmock(module).should_receive('inject_pattern').with_args(
-        patterns, module.borgmatic.borg.pattern.Pattern('/foo/bar')
-    ).once()
-
-    module.replace_pattern(
         patterns,
-        module.borgmatic.borg.pattern.Pattern('/unknown'),
         module.borgmatic.borg.pattern.Pattern('/foo/bar'),
-        0,
-    )
-
-
-def test_replace_pattern_with_root_pattern_swaps_it_in_along_with_corresponding_include_pattern():
-    patterns = [
-        module.borgmatic.borg.pattern.Pattern('/etc'),
-        module.borgmatic.borg.pattern.Pattern('/var'),
-        module.borgmatic.borg.pattern.Pattern('/lib'),
-        module.borgmatic.borg.pattern.Pattern('/run'),
-    ]
+        override_excludes=False,
+    ).once()
 
     module.replace_pattern(
         patterns,
-        module.borgmatic.borg.pattern.Pattern('/var'),
+        module.borgmatic.borg.pattern.Pattern('/unknown'),
         module.borgmatic.borg.pattern.Pattern('/foo/bar'),
-        2,
     )
-
-    assert patterns == [
-        module.borgmatic.borg.pattern.Pattern('/etc'),
-        module.borgmatic.borg.pattern.Pattern('/foo/bar'),
-        module.borgmatic.borg.pattern.Pattern('/lib'),
-        module.borgmatic.borg.pattern.Pattern(
-            '/foo/bar',
-            type=module.borgmatic.borg.pattern.Pattern_type.INCLUDE,
-        ),
-        module.borgmatic.borg.pattern.Pattern('/run'),
-    ]

+ 0 - 29
tests/unit/hooks/data_source/test_lvm.py

@@ -360,9 +360,6 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
         logical_volumes[1],
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/lvolume1/subdir'),
@@ -370,7 +367,6 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
@@ -379,7 +375,6 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
 
     assert (
@@ -401,9 +396,6 @@ def test_dump_data_sources_with_no_logical_volumes_skips_snapshots():
     flexmock(module).should_receive('get_logical_volumes').and_return(())
     flexmock(module).should_receive('snapshot_logical_volume').never()
     flexmock(module).should_receive('mount_snapshot').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
 
     assert (
@@ -485,9 +477,6 @@ def test_dump_data_sources_uses_snapshot_size_for_snapshot():
         logical_volumes[1],
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/lvolume1/subdir'),
@@ -495,7 +484,6 @@ def test_dump_data_sources_uses_snapshot_size_for_snapshot():
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
@@ -504,7 +492,6 @@ def test_dump_data_sources_uses_snapshot_size_for_snapshot():
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
 
     assert (
@@ -593,9 +580,6 @@ def test_dump_data_sources_uses_custom_commands():
         logical_volumes[1],
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/lvolume1/subdir'),
@@ -603,7 +587,6 @@ def test_dump_data_sources_uses_custom_commands():
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
@@ -612,7 +595,6 @@ def test_dump_data_sources_uses_custom_commands():
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
 
     assert (
@@ -651,9 +633,6 @@ def test_dump_data_sources_with_dry_run_skips_snapshots_and_does_not_touch_patte
     flexmock(module).should_receive('snapshot_logical_volume').never()
     flexmock(module).should_receive('get_snapshots').never()
     flexmock(module).should_receive('mount_snapshot').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
 
     assert (
@@ -735,9 +714,6 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
         logical_volumes[1],
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/lvolume1/subdir'),
@@ -745,7 +721,6 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume1/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
@@ -754,7 +729,6 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
             '/run/borgmatic/lvm_snapshots/b33f/./mnt/lvolume2',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
 
     assert (
@@ -811,9 +785,6 @@ def test_dump_data_sources_with_missing_snapshot_errors():
         snapshot_name='lvolume2_borgmatic-1234',
     ).never()
     flexmock(module).should_receive('mount_snapshot').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
 
     with pytest.raises(ValueError):

+ 0 - 18
tests/unit/hooks/data_source/test_zfs.py

@@ -328,9 +328,6 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir'))
     patterns = [Pattern('/mnt/dataset/subdir')]
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/dataset/subdir'),
@@ -338,7 +335,6 @@ def test_dump_data_sources_snapshots_and_mounts_and_replaces_patterns():
             '/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
 
     assert (
@@ -359,9 +355,6 @@ def test_dump_data_sources_with_no_datasets_skips_snapshots():
     flexmock(module.os).should_receive('getpid').and_return(1234)
     flexmock(module).should_receive('snapshot_dataset').never()
     flexmock(module).should_receive('mount_snapshot').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).never()
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
     patterns = [Pattern('/mnt/dataset')]
 
@@ -407,9 +400,6 @@ def test_dump_data_sources_uses_custom_commands():
         dataset,
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/dataset/subdir'),
@@ -417,7 +407,6 @@ def test_dump_data_sources_uses_custom_commands():
             '/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     patterns = [Pattern('/mnt/dataset/subdir')]
     hook_config = {
@@ -448,9 +437,6 @@ def test_dump_data_sources_with_dry_run_skips_commands_and_does_not_touch_patter
     flexmock(module.os).should_receive('getpid').and_return(1234)
     flexmock(module).should_receive('snapshot_dataset').never()
     flexmock(module).should_receive('mount_snapshot').never()
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').never()
     patterns = [Pattern('/mnt/dataset')]
 
@@ -494,9 +480,6 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
         dataset,
         '/run/borgmatic',
     ).and_return(Pattern('/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir'))
-    flexmock(module.borgmatic.hooks.data_source.config).should_receive(
-        'get_last_pattern_index'
-    ).and_return(0)
     flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
         object,
         Pattern('/mnt/dataset/subdir'),
@@ -504,7 +487,6 @@ def test_dump_data_sources_ignores_mismatch_between_given_patterns_and_contained
             '/run/borgmatic/zfs_snapshots/b33f/./mnt/dataset/subdir',
             source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
         ),
-        0,
     ).once()
     patterns = [Pattern('/hmm')]