Browse Source

Fix error when configured source directories are not present on the filesystem at the time of backup (#387).

master
Dan Helfman 2 months ago
parent
commit
449896f661
  1. 2
      NEWS
  2. 14
      borgmatic/borg/create.py
  3. 25
      tests/unit/borg/test_create.py

2
NEWS

@ -1,4 +1,6 @@
1.5.19.dev0
* #387: Fix error when configured source directories are not present on the filesystem at the time
of backup. Now, Borg will complain, but the backup will still continue.
* Update sample systemd service file with more granular read-only filesystem settings.
* Move Gitea and GitHub hosting from a personal namespace to an organization for better
collaboration with related projects.

14
borgmatic/borg/create.py

@ -44,13 +44,18 @@ def _expand_home_directories(directories):
return tuple(os.path.expanduser(directory) for directory in directories)
def map_directories_to_devices(directories): # pragma: no cover
def map_directories_to_devices(directories):
'''
Given a sequence of directories, return a map from directory to an identifier for the device on
which that directory resides. This is handy for determining whether two different directories
are on the same filesystem (have the same device identifier).
which that directory resides or None if the path doesn't exist.
This is handy for determining whether two different directories are on the same filesystem (have
the same device identifier).
'''
return {directory: os.stat(directory).st_dev for directory in directories}
return {
directory: os.stat(directory).st_dev if os.path.exists(directory) else None
for directory in directories
}
def deduplicate_directories(directory_devices):
@ -82,6 +87,7 @@ def deduplicate_directories(directory_devices):
for parent in parents:
if (
pathlib.PurePath(other_directory) == parent
and directory_devices[directory] is not None
and directory_devices[other_directory] == directory_devices[directory]
):
if directory in deduplicated:

25
tests/unit/borg/test_create.py

@ -60,6 +60,30 @@ def test_expand_home_directories_considers_none_as_no_directories():
assert paths == ()
def test_map_directories_to_devices_gives_device_id_per_path():
flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
flexmock(module.os).should_receive('stat').with_args('/bar').and_return(flexmock(st_dev=66))
device_map = module.map_directories_to_devices(('/foo', '/bar'))
assert device_map == {
'/foo': 55,
'/bar': 66,
}
def test_map_directories_to_devices_with_missing_path_does_not_error():
flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
flexmock(module.os).should_receive('stat').with_args('/bar').and_raise(FileNotFoundError)
device_map = module.map_directories_to_devices(('/foo', '/bar'))
assert device_map == {
'/foo': 55,
'/bar': None,
}
@pytest.mark.parametrize(
'directories,expected_directories',
(
@ -72,6 +96,7 @@ def test_expand_home_directories_considers_none_as_no_directories():
({'/root': 1, '/root/foo/': 1}, ('/root',)),
({'/root': 1, '/root/foo': 2}, ('/root', '/root/foo')),
({'/root/foo': 1, '/root': 1}, ('/root',)),
({'/root': None, '/root/foo': None}, ('/root', '/root/foo')),
({'/root': 1, '/etc': 1, '/root/foo/bar': 1}, ('/etc', '/root')),
({'/root': 1, '/root/foo': 1, '/root/foo/bar': 1}, ('/root',)),
({'/dup': 1, '/dup': 1}, ('/dup',)),

Loading…
Cancel
Save