diff --git a/borgmatic/borg/export_tar.py b/borgmatic/borg/export_tar.py index 5ed494c8..a5b752c3 100644 --- a/borgmatic/borg/export_tar.py +++ b/borgmatic/borg/export_tar.py @@ -46,11 +46,7 @@ def export_tar_archive( + (('--dry-run',) if dry_run else ()) + (('--tar-filter', tar_filter) if tar_filter else ()) + (('--strip-components', str(strip_components)) if strip_components else ()) - + flags.make_repository_archive_flags( - repository if ':' in repository else os.path.abspath(repository), - archive, - local_borg_version, - ) + + flags.make_repository_archive_flags(repository, archive, local_borg_version,) + (destination_path,) + (tuple(paths) if paths else ()) ) diff --git a/borgmatic/borg/extract.py b/borgmatic/borg/extract.py index bbf36edf..6c32f7f0 100644 --- a/borgmatic/borg/extract.py +++ b/borgmatic/borg/extract.py @@ -106,11 +106,7 @@ def extract_archive( + (('--strip-components', str(strip_components)) if strip_components else ()) + (('--progress',) if progress else ()) + (('--stdout',) if extract_to_stdout else ()) - + flags.make_repository_archive_flags( - repository if ':' in repository else os.path.abspath(repository), - archive, - local_borg_version, - ) + + flags.make_repository_archive_flags(repository, archive, local_borg_version,) + (tuple(paths) if paths else ()) ) diff --git a/borgmatic/config/normalize.py b/borgmatic/config/normalize.py index 574a48a1..a143a192 100644 --- a/borgmatic/config/normalize.py +++ b/borgmatic/config/normalize.py @@ -1,4 +1,5 @@ import logging +import os def normalize(config_filename, config): @@ -68,20 +69,25 @@ def normalize(config_filename, config): ) ) ) - if ':' in repository and not repository.startswith('ssh://'): - rewritten_repository = ( - f"ssh://{repository.replace(':~', '/~').replace(':/', '/').replace(':', '/./')}" - ) - logs.append( - logging.makeLogRecord( - dict( - levelno=logging.WARNING, - levelname='WARNING', - msg=f'{config_filename}: Remote repository paths without ssh:// syntax are deprecated. Interpreting "{repository}" as "{rewritten_repository}"', + if ':' in repository: + if repository.startswith('file://'): + config['location']['repositories'].append( + os.path.abspath(repository.partition('file://')[-1]) + ) + elif repository.startswith('ssh://'): + config['location']['repositories'].append(repository) + else: + rewritten_repository = f"ssh://{repository.replace(':~', '/~').replace(':/', '/').replace(':', '/./')}" + logs.append( + logging.makeLogRecord( + dict( + levelno=logging.WARNING, + levelname='WARNING', + msg=f'{config_filename}: Remote repository paths without ssh:// syntax are deprecated. Interpreting "{repository}" as "{rewritten_repository}"', + ) ) ) - ) - config['location']['repositories'].append(rewritten_repository) + config['location']['repositories'].append(rewritten_repository) else: config['location']['repositories'].append(repository) diff --git a/borgmatic/config/validate.py b/borgmatic/config/validate.py index 044e22d8..5828380e 100644 --- a/borgmatic/config/validate.py +++ b/borgmatic/config/validate.py @@ -126,12 +126,15 @@ def normalize_repository_path(repository): ''' Given a repository path, return the absolute path of it (for local repositories). ''' - # A colon in the repository indicates it's a remote repository. Bail. - if ':' in repository: + # 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) + elif repository.startswith('file://'): + return os.path.abspath(repository.partition('file://')[-1]) + else: return repository - return os.path.abspath(repository) - def repositories_match(first, second): ''' diff --git a/tests/unit/config/test_normalize.py b/tests/unit/config/test_normalize.py index 384dd7e3..821c3202 100644 --- a/tests/unit/config/test_normalize.py +++ b/tests/unit/config/test_normalize.py @@ -87,6 +87,11 @@ from borgmatic.config import normalize as module {'location': {'repositories': ['ssh://foo@bar:1234/repo']}}, False, ), + ( + {'location': {'repositories': ['file:///repo']}}, + {'location': {'repositories': ['/repo']}}, + False, + ), ), ) def test_normalize_applies_hard_coded_normalization_to_config( diff --git a/tests/unit/config/test_validate.py b/tests/unit/config/test_validate.py index 713ecc7a..6a9f4a4e 100644 --- a/tests/unit/config/test_validate.py +++ b/tests/unit/config/test_validate.py @@ -83,6 +83,13 @@ def test_normalize_repository_path_passes_through_remote_repository(): module.normalize_repository_path(repository) == 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') + + module.normalize_repository_path(repository) == '/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)