Merge branch jacksonchen666-btrfs-remove-pid into btrfs-remove-pid and streamline the docs a bit.

This commit is contained in:
Dan Helfman
2025-12-20 16:02:42 -08:00
4 changed files with 119 additions and 149 deletions
+3 -3
View File
@@ -171,7 +171,7 @@ def get_subvolumes(btrfs_command, patterns):
return tuple(sorted(subvolumes, key=lambda subvolume: subvolume.path))
BORGMATIC_SNAPSHOT_PREFIX = '.borgmatic-snapshot-'
BORGMATIC_SNAPSHOT_PREFIX = '.borgmatic-snapshot'
def make_snapshot_path(subvolume_path):
@@ -180,7 +180,7 @@ def make_snapshot_path(subvolume_path):
'''
return os.path.join(
subvolume_path,
f'{BORGMATIC_SNAPSHOT_PREFIX}{os.getpid()}',
f'{BORGMATIC_SNAPSHOT_PREFIX}',
# Included so that the snapshot ends up in the Borg archive at the "original" subvolume path.
) + subvolume_path.rstrip(os.path.sep)
@@ -235,7 +235,7 @@ def make_borg_snapshot_pattern(subvolume_path, pattern):
rewritten_path = initial_caret + os.path.join(
subvolume_path,
f'{BORGMATIC_SNAPSHOT_PREFIX}{os.getpid()}',
f'{BORGMATIC_SNAPSHOT_PREFIX}',
# Use the Borg 1.4+ "slashdot" hack to prevent the snapshot path prefix from getting
# included in the archive—but only if there's not already a slashdot hack present in the
# pattern.
@@ -70,26 +70,24 @@ temporary snapshot directory in use at the time the archive was created, as Borg
## Performance
<span class="minilink minilink-addedin">With Borg version 1.x</span> Because of
the way that Btrfs snapshot paths change from one borgmatic invocation to the
next, the [Borg file
<span class="minilink minilink-addedin">New in borgmatic version 2.0.13, with
Borg version 1.x</span> borgmatic uses consistent snapshot paths between
invocations, so Btrfs snapshots are cached correctly. No configuration is
necessary.
<span class="minilink minilink-addedin">Prior to borgmatic version 2.0.13, with
Borg version 1.x</span> Because of the way that Btrfs snapshot paths change from
one borgmatic invocation to the next, the [Borg file
cache](https://borgbackup.readthedocs.io/en/stable/internals/data-structures.html#cache)
will never get cache hits on snapshotted files. This makes backing up Btrfs
never gets cache hits on snapshotted files. This makes backing up Btrfs
snapshots a little slower than non-snapshotted files that have consistent paths.
**It is also not possible to mitigate cache misses**, as the Btrfs hook uses
snapshot paths which change between borgmatic invocations, and the snapshots
are located outside the [runtime
directory](https://torsion.org/borgmatic/reference/configuration/runtime-directory/),
contrary to
[ZFS](https://torsion.org/borgmatic/reference/configuration/data-sources/zfs/#performance)
and
[LVM](https://torsion.org/borgmatic/reference/configuration/data-sources/lvm/#performance).
If this is an issue for you, upgrade to borgmatic to 2.0.13+.
<span class="minilink minilink-addedin">With Borg version 2.x</span> Even
snapshotted files should get cache hits, because Borg 2.x is smarter about how
it looks up file paths in its cache—it constructs the cache key with the path
*as it's seen in the archive* (which is consistent across runs) rather than the
full absolute source path (which changes).
snapshotted files get cache hits, because Borg 2.x is smarter about how it looks
up file paths in its cache—it constructs the cache key with the path *as it's
seen in the archive* (which is consistent across runs) rather than the full
absolute source path (which changes).
## systemd settings
@@ -28,12 +28,12 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
flexmock(module).should_receive('snapshot_subvolume').with_args(
'btrfs',
'/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).once()
flexmock(module).should_receive('snapshot_subvolume').with_args(
'btrfs',
'/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).once()
assert (
@@ -50,19 +50,19 @@ def test_dump_data_sources_snapshots_each_subvolume_and_updates_patterns():
assert patterns == [
Pattern(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2/.borgmatic-snapshot-1234',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
Pattern('/foo'),
Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1'),
Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1/.cache', Pattern_type.EXCLUDE),
Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2'),
Pattern('/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1'),
Pattern('/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1/.cache', Pattern_type.EXCLUDE),
Pattern('/mnt/subvol2/.borgmatic-snapshot/./mnt/subvol2'),
]
assert config == {
'btrfs': {},
+95 -123
View File
@@ -331,8 +331,8 @@ def test_get_subvolumes_skips_non_config_patterns():
@pytest.mark.parametrize(
'subvolume_path,expected_snapshot_path',
(
('/foo/bar', '/foo/bar/.borgmatic-snapshot-1234/foo/bar'),
('/', '/.borgmatic-snapshot-1234'),
('/foo/bar', '/foo/bar/.borgmatic-snapshot/foo/bar'),
('/', '/.borgmatic-snapshot'),
),
)
def test_make_snapshot_path_includes_stripped_subvolume_path(
@@ -350,14 +350,14 @@ def test_make_snapshot_path_includes_stripped_subvolume_path(
(
'/foo/bar',
Pattern('/foo/bar/baz'),
Pattern('/foo/bar/.borgmatic-snapshot-1234/./foo/bar/baz'),
Pattern('/foo/bar/.borgmatic-snapshot/./foo/bar/baz'),
),
('/foo/bar', Pattern('/foo/bar'), Pattern('/foo/bar/.borgmatic-snapshot-1234/./foo/bar')),
('/foo/bar', Pattern('/foo/bar'), Pattern('/foo/bar/.borgmatic-snapshot/./foo/bar')),
(
'/foo/bar',
Pattern('^/foo/bar', Pattern_type.INCLUDE, Pattern_style.REGULAR_EXPRESSION),
Pattern(
'^/foo/bar/.borgmatic-snapshot-1234/./foo/bar',
'^/foo/bar/.borgmatic-snapshot/./foo/bar',
Pattern_type.INCLUDE,
Pattern_style.REGULAR_EXPRESSION,
),
@@ -366,17 +366,17 @@ def test_make_snapshot_path_includes_stripped_subvolume_path(
'/foo/bar',
Pattern('/foo/bar', Pattern_type.INCLUDE, Pattern_style.REGULAR_EXPRESSION),
Pattern(
'/foo/bar/.borgmatic-snapshot-1234/./foo/bar',
'/foo/bar/.borgmatic-snapshot/./foo/bar',
Pattern_type.INCLUDE,
Pattern_style.REGULAR_EXPRESSION,
),
),
('/', Pattern('/foo'), Pattern('/.borgmatic-snapshot-1234/./foo')),
('/', Pattern('/'), Pattern('/.borgmatic-snapshot-1234/./')),
('/', Pattern('/foo'), Pattern('/.borgmatic-snapshot/./foo')),
('/', Pattern('/'), Pattern('/.borgmatic-snapshot/./')),
(
'/foo/bar',
Pattern('/foo/bar/./baz'),
Pattern('/foo/bar/.borgmatic-snapshot-1234/foo/bar/./baz'),
Pattern('/foo/bar/.borgmatic-snapshot/foo/bar/./baz'),
),
),
)
@@ -400,26 +400,26 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol2').and_return(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
)
flexmock(module).should_receive('snapshot_subvolume').with_args(
'btrfs',
'/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).once()
flexmock(module).should_receive('snapshot_subvolume').with_args(
'btrfs',
'/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).once()
flexmock(module).should_receive('make_snapshot_exclude_pattern').with_args(
'/mnt/subvol1',
).and_return(
Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -428,7 +428,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
'/mnt/subvol2',
).and_return(
Pattern(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2/.borgmatic-snapshot-1234',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -436,16 +436,16 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
flexmock(module).should_receive('make_borg_snapshot_pattern').with_args(
'/mnt/subvol1',
object,
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1'))
flexmock(module).should_receive('make_borg_snapshot_pattern').with_args(
'/mnt/subvol2',
object,
).and_return(Pattern('/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2'))
).and_return(Pattern('/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2'))
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
object,
Pattern('/mnt/subvol1'),
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
),
).once()
@@ -453,14 +453,14 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
object,
Pattern('/mnt/subvol2'),
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
),
).once()
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
object,
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -468,7 +468,7 @@ def test_dump_data_sources_snapshots_each_subvolume_and_replaces_patterns():
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
object,
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2/.borgmatic-snapshot-1234',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -498,18 +498,18 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
(module.Subvolume('/mnt/subvol1', contained_patterns=(Pattern('/mnt/subvol1'),)),),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
)
flexmock(module).should_receive('snapshot_subvolume').with_args(
'/usr/local/bin/btrfs',
'/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).once()
flexmock(module).should_receive('make_snapshot_exclude_pattern').with_args(
'/mnt/subvol1',
).and_return(
Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -517,19 +517,19 @@ def test_dump_data_sources_uses_custom_btrfs_command_in_commands():
flexmock(module).should_receive('make_borg_snapshot_pattern').with_args(
'/mnt/subvol1',
object,
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1'))
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
object,
Pattern('/mnt/subvol1'),
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
),
).once()
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
object,
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -565,18 +565,18 @@ def test_dump_data_sources_with_findmnt_command_warns():
(module.Subvolume('/mnt/subvol1', contained_patterns=(Pattern('/mnt/subvol1'),)),),
).once()
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
)
flexmock(module).should_receive('snapshot_subvolume').with_args(
'btrfs',
'/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).once()
flexmock(module).should_receive('make_snapshot_exclude_pattern').with_args(
'/mnt/subvol1',
).and_return(
Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -584,19 +584,19 @@ def test_dump_data_sources_with_findmnt_command_warns():
flexmock(module).should_receive('make_borg_snapshot_pattern').with_args(
'/mnt/subvol1',
object,
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1'))
).and_return(Pattern('/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1'))
flexmock(module.borgmatic.hooks.data_source.config).should_receive('replace_pattern').with_args(
object,
Pattern('/mnt/subvol1'),
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
source=module.borgmatic.borg.pattern.Pattern_source.HOOK,
),
).once()
flexmock(module.borgmatic.hooks.data_source.config).should_receive('inject_pattern').with_args(
object,
module.borgmatic.borg.pattern.Pattern(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1/.borgmatic-snapshot',
Pattern_type.NO_RECURSE,
Pattern_style.FNMATCH,
),
@@ -628,7 +628,7 @@ def test_dump_data_sources_with_dry_run_skips_snapshot_and_patterns_update():
(module.Subvolume('/mnt/subvol1', contained_patterns=(Pattern('/mnt/subvol1'),)),),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
)
flexmock(module).should_receive('snapshot_subvolume').never()
flexmock(module).should_receive('make_snapshot_exclude_pattern').never()
@@ -684,91 +684,63 @@ def test_remove_data_source_dumps_deletes_snapshots():
),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1',
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol2').and_return(
'/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/./mnt/subvol2',
)
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol1/.borgmatic-*/mnt/subvol1')
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol2/.borgmatic-*/mnt/subvol2')
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol1/.borgmatic-*/mnt/subvol1',
).and_return(
(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
),
)
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol2/.borgmatic-*/mnt/subvol2',
).and_return(
(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
),
)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
).and_return(False)
flexmock(module).should_receive('delete_snapshot').with_args(
'btrfs',
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).once()
flexmock(module).should_receive('delete_snapshot').with_args(
'btrfs',
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).once()
flexmock(module).should_receive('delete_snapshot').with_args(
'btrfs',
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
).once()
flexmock(module).should_receive('delete_snapshot').with_args(
'btrfs',
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
).never()
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-5678',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-5678',
'/mnt/subvol2/.borgmatic-snapshot',
).and_return(True)
flexmock(module.shutil).should_receive('rmtree').with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234',
'/mnt/subvol1/.borgmatic-snapshot',
).once()
flexmock(module.shutil).should_receive('rmtree').with_args(
'/mnt/subvol1/.borgmatic-snapshot-5678',
'/mnt/subvol2/.borgmatic-snapshot',
).once()
flexmock(module.shutil).should_receive('rmtree').with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234',
).once()
flexmock(module.shutil).should_receive('rmtree').with_args(
'/mnt/subvol2/.borgmatic-snapshot-5678',
).never()
module.remove_data_source_dumps(
hook_config=config['btrfs'],
@@ -846,50 +818,50 @@ def test_remove_data_source_dumps_with_dry_run_skips_deletes():
),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1',
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol2').and_return(
'/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/./mnt/subvol2',
)
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol1/.borgmatic-*/mnt/subvol1')
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol2/.borgmatic-*/mnt/subvol2')
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol1/.borgmatic-*/mnt/subvol1',
).and_return(
(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
),
)
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol2/.borgmatic-*/mnt/subvol2',
).and_return(
(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
),
)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(False)
flexmock(module).should_receive('delete_snapshot').never()
flexmock(module.shutil).should_receive('rmtree').never()
@@ -931,21 +903,21 @@ def test_remove_data_source_without_snapshots_skips_deletes():
),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1',
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol2').and_return(
'/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/./mnt/subvol2',
)
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol1/.borgmatic-*/mnt/subvol1')
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol2/.borgmatic-*/mnt/subvol2')
flexmock(module.glob).should_receive('glob').and_return(())
@@ -971,50 +943,50 @@ def test_remove_data_source_dumps_with_delete_snapshot_file_not_found_error_bail
),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1',
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol2').and_return(
'/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/./mnt/subvol2',
)
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol1/.borgmatic-*/mnt/subvol1')
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol2/.borgmatic-*/mnt/subvol2')
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol1/.borgmatic-*/mnt/subvol1',
).and_return(
(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
),
)
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol2/.borgmatic-*/mnt/subvol2',
).and_return(
(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
),
)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(False)
flexmock(module).should_receive('delete_snapshot').and_raise(FileNotFoundError)
flexmock(module.shutil).should_receive('rmtree').never()
@@ -1037,50 +1009,50 @@ def test_remove_data_source_dumps_with_delete_snapshot_called_process_error_bail
),
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol1').and_return(
'/mnt/subvol1/.borgmatic-snapshot-1234/./mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/./mnt/subvol1',
)
flexmock(module).should_receive('make_snapshot_path').with_args('/mnt/subvol2').and_return(
'/mnt/subvol2/.borgmatic-snapshot-1234/./mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/./mnt/subvol2',
)
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol1/.borgmatic-*/mnt/subvol1')
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/mnt/subvol2/.borgmatic-*/mnt/subvol2')
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol1/.borgmatic-*/mnt/subvol1',
).and_return(
(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
),
)
flexmock(module.glob).should_receive('glob').with_args(
'/mnt/subvol2/.borgmatic-*/mnt/subvol2',
).and_return(
(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
),
)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-1234/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol1/.borgmatic-snapshot-5678/mnt/subvol1',
'/mnt/subvol1/.borgmatic-snapshot/mnt/subvol1',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-1234/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(True)
flexmock(module.os.path).should_receive('isdir').with_args(
'/mnt/subvol2/.borgmatic-snapshot-5678/mnt/subvol2',
'/mnt/subvol2/.borgmatic-snapshot/mnt/subvol2',
).and_return(False)
flexmock(module).should_receive('delete_snapshot').and_raise(
module.subprocess.CalledProcessError(1, 'command', 'error'),
@@ -1103,36 +1075,36 @@ def test_remove_data_source_dumps_with_root_subvolume_skips_duplicate_removal():
)
flexmock(module).should_receive('make_snapshot_path').with_args('/').and_return(
'/.borgmatic-snapshot-1234',
'/.borgmatic-snapshot',
)
flexmock(module.borgmatic.config.paths).should_receive(
'replace_temporary_subdirectory_with_glob',
).with_args(
'/.borgmatic-snapshot-1234',
'/.borgmatic-snapshot',
temporary_directory_prefix=module.BORGMATIC_SNAPSHOT_PREFIX,
).and_return('/.borgmatic-*')
flexmock(module.glob).should_receive('glob').with_args('/.borgmatic-*').and_return(
('/.borgmatic-snapshot-1234', '/.borgmatic-snapshot-5678'),
('/.borgmatic-snapshot', '/.borgmatic-snapshot'),
)
flexmock(module.os.path).should_receive('isdir').with_args(
'/.borgmatic-snapshot-1234'
'/.borgmatic-snapshot'
).and_return(
True,
).and_return(False)
flexmock(module.os.path).should_receive('isdir').with_args(
'/.borgmatic-snapshot-5678'
'/.borgmatic-snapshot'
).and_return(
True,
).and_return(False)
flexmock(module).should_receive('delete_snapshot').with_args(
'btrfs', '/.borgmatic-snapshot-1234'
'btrfs', '/.borgmatic-snapshot'
).once()
flexmock(module).should_receive('delete_snapshot').with_args(
'btrfs', '/.borgmatic-snapshot-5678'
'btrfs', '/.borgmatic-snapshot'
).once()
flexmock(module.os.path).should_receive('isdir').with_args('').and_return(False)