Fix extracting from remote repositories with working_directory defined (#1037).

Reviewed-on: https://projects.torsion.org/borgmatic-collective/borgmatic/pulls/1038
Reviewed-by: Dan Helfman <witten@torsion.org>
This commit is contained in:
Dan Helfman
2025-03-21 22:40:18 +00:00
4 changed files with 59 additions and 10 deletions
+1 -3
View File
@@ -134,9 +134,7 @@ def extract_archive(
# Make the repository path absolute so the destination directory used below via changing
# the working directory doesn't prevent Borg from finding the repo. But also apply the
# user's configured working directory (if any) to the repo path.
borgmatic.config.validate.normalize_repository_path(
os.path.join(working_directory or '', repository)
),
borgmatic.config.validate.normalize_repository_path(repository, working_directory),
archive,
local_borg_version,
)
+9 -3
View File
@@ -138,16 +138,22 @@ def parse_configuration(config_filename, schema_filename, overrides=None, resolv
return config, config_paths, logs
def normalize_repository_path(repository):
def normalize_repository_path(repository, base=None):
'''
Given a repository path, return the absolute path of it (for local repositories).
Optionally, use a base path for resolving relative paths, e.g. to the configured working directory.
'''
# A colon in the repository could mean that it's either a file:// URL or a remote repository.
# If it's a remote repository, we don't want to normalize it. If it's a file:// URL, we do.
if ':' not in repository:
return os.path.abspath(repository)
return (
os.path.abspath(os.path.join(base, repository)) if base else os.path.abspath(repository)
)
elif repository.startswith('file://'):
return os.path.abspath(repository.partition('file://')[-1])
local_path = repository.partition('file://')[-1]
return (
os.path.abspath(os.path.join(base, local_path)) if base else os.path.abspath(local_path)
)
else:
return repository
+2 -2
View File
@@ -710,7 +710,7 @@ def test_extract_archive_uses_configured_working_directory_in_repo_path_and_dest
)
flexmock(module.borgmatic.config.validate).should_receive(
'normalize_repository_path'
).with_args('/working/dir/repo').and_return('/working/dir/repo').once()
).with_args('repo', '/working/dir').and_return('/working/dir/repo').once()
module.extract_archive(
dry_run=False,
@@ -733,7 +733,7 @@ def test_extract_archive_uses_configured_working_directory_in_repo_path_when_des
)
flexmock(module.borgmatic.config.validate).should_receive(
'normalize_repository_path'
).with_args('/working/dir/repo').and_return('/working/dir/repo').once()
).with_args('repo', '/working/dir').and_return('/working/dir/repo').once()
module.extract_archive(
dry_run=False,
+47 -2
View File
@@ -94,13 +94,40 @@ def test_normalize_repository_path_passes_through_remote_repository():
module.normalize_repository_path(repository) == repository
def test_normalize_repository_path_passes_through_remote_repository_with_base_dir():
repository = 'example.org:test.borg'
flexmock(module.os.path).should_receive('abspath').never()
module.normalize_repository_path(repository, '/working') == repository
def test_normalize_repository_path_passes_through_file_repository():
repository = 'file:///foo/bar/test.borg'
flexmock(module.os.path).should_receive('abspath').and_return('/foo/bar/test.borg')
flexmock(module.os.path).should_receive('abspath').with_args('/foo/bar/test.borg').and_return(
'/foo/bar/test.borg'
)
module.normalize_repository_path(repository) == '/foo/bar/test.borg'
def test_normalize_repository_path_passes_through_absolute_file_repository_with_base_dir():
repository = 'file:///foo/bar/test.borg'
flexmock(module.os.path).should_receive('abspath').with_args('/foo/bar/test.borg').and_return(
'/foo/bar/test.borg'
)
module.normalize_repository_path(repository, '/working') == '/foo/bar/test.borg'
def test_normalize_repository_path_resolves_relative_file_repository_with_base_dir():
repository = 'file://foo/bar/test.borg'
flexmock(module.os.path).should_receive('abspath').with_args(
'/working/foo/bar/test.borg'
).and_return('/working/foo/bar/test.borg')
module.normalize_repository_path(repository, '/working') == '/working/foo/bar/test.borg'
def test_normalize_repository_path_passes_through_absolute_repository():
repository = '/foo/bar/test.borg'
flexmock(module.os.path).should_receive('abspath').and_return(repository)
@@ -108,14 +135,32 @@ def test_normalize_repository_path_passes_through_absolute_repository():
module.normalize_repository_path(repository) == repository
def test_normalize_repository_path_passes_through_absolute_repository_with_base_dir():
repository = '/foo/bar/test.borg'
flexmock(module.os.path).should_receive('abspath').and_return(repository)
module.normalize_repository_path(repository, '/working') == repository
def test_normalize_repository_path_resolves_relative_repository():
repository = 'test.borg'
absolute = '/foo/bar/test.borg'
flexmock(module.os.path).should_receive('abspath').and_return(absolute)
flexmock(module.os.path).should_receive('abspath').with_args(repository).and_return(absolute)
module.normalize_repository_path(repository) == absolute
def test_normalize_repository_path_resolves_relative_repository_with_base_dir():
repository = 'test.borg'
base = '/working'
absolute = '/working/test.borg'
flexmock(module.os.path).should_receive('abspath').with_args('/working/test.borg').and_return(
absolute
)
module.normalize_repository_path(repository, base) == absolute
@pytest.mark.parametrize(
'first,second,expected_result',
(