diff --git a/NEWS b/NEWS index b753753b2..b20033c87 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,15 @@ repository info). If you install Borg 2, you'll need to manually "borg transfer" or "borgmatic transfer" your existing Borg 1 repositories before use. See the Borg 2.0 changelog for more information about Borg 2: https://www.borgbackup.org/releases/borg-2.0.html + * #557: Rename several configuration options to match Borg 2: "remote_rate_limit" is now + "upload_rate_limit", "numeric_owner" is "numeric_ids", and "bsd_flags" is "flags". borgmatic + still works with the old options. + * #557: Remote repository paths without the "ssh://" syntax are deprecated but still supported for + now. However, remote repository paths containing "~" will no longer work. + * #557: Omitting the "--archive" flag on the "list" action is deprecated when using Borg 2. Use + the new "rlist" action instead. And when using the "--archive" or "--find" flags on the "list" + action with Borg 2, several flags are no longer supported: "--prefix", "--glob-archives", + "--sort-by", "--first", and "--last". * #565: Fix handling of "repository" and "data" consistency checks to prevent invalid Borg flags. * #566: Modify "mount" and "extract" actions to require the "--repository" flag when multiple repositories are configured. diff --git a/borgmatic/borg/create.py b/borgmatic/borg/create.py index 6cee09cba..9977e05a3 100644 --- a/borgmatic/borg/create.py +++ b/borgmatic/borg/create.py @@ -233,7 +233,7 @@ def create_archive( checkpoint_interval = storage_config.get('checkpoint_interval', None) chunker_params = storage_config.get('chunker_params', None) compression = storage_config.get('compression', None) - remote_rate_limit = storage_config.get('remote_rate_limit', None) + upload_rate_limit = storage_config.get('upload_rate_limit', None) umask = storage_config.get('umask', None) lock_wait = storage_config.get('lock_wait', None) files_cache = location_config.get('files_cache') @@ -246,22 +246,22 @@ def create_archive( atime_flags = ('--noatime',) if location_config.get('atime') is False else () if feature.available(feature.Feature.NOFLAGS, local_borg_version): - noflags_flags = ('--noflags',) if location_config.get('bsd_flags') is False else () + noflags_flags = ('--noflags',) if location_config.get('flags') is False else () else: - noflags_flags = ('--nobsdflags',) if location_config.get('bsd_flags') is False else () + noflags_flags = ('--nobsdflags',) if location_config.get('flags') is False else () if feature.available(feature.Feature.NUMERIC_IDS, local_borg_version): - numeric_ids_flags = ('--numeric-ids',) if location_config.get('numeric_owner') else () + numeric_ids_flags = ('--numeric-ids',) if location_config.get('numeric_ids') else () else: - numeric_ids_flags = ('--numeric-owner',) if location_config.get('numeric_owner') else () + numeric_ids_flags = ('--numeric-owner',) if location_config.get('numeric_ids') else () if feature.available(feature.Feature.UPLOAD_RATELIMIT, local_borg_version): upload_ratelimit_flags = ( - ('--upload-ratelimit', str(remote_rate_limit)) if remote_rate_limit else () + ('--upload-ratelimit', str(upload_rate_limit)) if upload_rate_limit else () ) else: upload_ratelimit_flags = ( - ('--remote-ratelimit', str(remote_rate_limit)) if remote_rate_limit else () + ('--remote-ratelimit', str(upload_rate_limit)) if upload_rate_limit else () ) ensure_files_readable(location_config.get('patterns_from'), location_config.get('exclude_from')) diff --git a/borgmatic/borg/extract.py b/borgmatic/borg/extract.py index 5e2a58d2c..8ea8bbbd3 100644 --- a/borgmatic/borg/extract.py +++ b/borgmatic/borg/extract.py @@ -83,9 +83,9 @@ def extract_archive( raise ValueError('progress and extract_to_stdout cannot both be set') if feature.available(feature.Feature.NUMERIC_IDS, local_borg_version): - numeric_ids_flags = ('--numeric-ids',) if location_config.get('numeric_owner') else () + numeric_ids_flags = ('--numeric-ids',) if location_config.get('numeric_ids') else () else: - numeric_ids_flags = ('--numeric-owner',) if location_config.get('numeric_owner') else () + numeric_ids_flags = ('--numeric-owner',) if location_config.get('numeric_ids') else () full_command = ( (local_path, 'extract') diff --git a/borgmatic/commands/arguments.py b/borgmatic/commands/arguments.py index bcc4b7450..990b96866 100644 --- a/borgmatic/commands/arguments.py +++ b/borgmatic/commands/arguments.py @@ -314,8 +314,8 @@ def make_parsers(): create_parser = subparsers.add_parser( 'create', aliases=SUBPARSER_ALIASES['create'], - help='Create archives (actually perform backups)', - description='Create archives (actually perform backups)', + help='Create an archive (actually perform a backup)', + description='Create an archive (actually perform a backup)', add_help=False, ) create_group = create_parser.add_argument_group('create arguments') diff --git a/borgmatic/config/generate.py b/borgmatic/config/generate.py index a454f662c..e864a3c0c 100644 --- a/borgmatic/config/generate.py +++ b/borgmatic/config/generate.py @@ -283,7 +283,7 @@ def generate_sample_configuration( if source_filename: source_config = load.load_configuration(source_filename) - normalize.normalize(source_config) + normalize.normalize(source_filename, source_config) destination_config = merge_source_configuration_into_destination( _schema_to_sample_configuration(schema), source_config diff --git a/borgmatic/config/normalize.py b/borgmatic/config/normalize.py index 3e57f538c..19cf5e9d8 100644 --- a/borgmatic/config/normalize.py +++ b/borgmatic/config/normalize.py @@ -36,12 +36,24 @@ def normalize(config_filename, config): if isinstance(checks, list) and len(checks) and isinstance(checks[0], str): config['consistency']['checks'] = [{'name': check_type} for check_type in checks] + # Rename various configuration options. + numeric_owner = config.get('location', {}).pop('numeric_owner', None) + if numeric_owner is not None: + config['location']['numeric_ids'] = numeric_owner + + bsd_flags = config.get('location', {}).pop('bsd_flags', None) + if bsd_flags is not None: + config['location']['flags'] = bsd_flags + + remote_rate_limit = config.get('storage', {}).pop('remote_rate_limit', None) + if remote_rate_limit is not None: + config['storage']['upload_rate_limit'] = remote_rate_limit + # Upgrade remote repositories to ssh:// syntax, required in Borg 2. repositories = config.get('location', {}).get('repositories') if repositories: config['location']['repositories'] = [] for repository in repositories: - # TODO: Instead of logging directly here, return logs and bubble them up to be displayed *after* logging is initialized. if '~' in repository: logs.append( logging.makeLogRecord( diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 83c163d4f..2434eccd0 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -58,7 +58,7 @@ properties: database hook is used, the setting here is ignored and one_file_system is considered true. example: true - numeric_owner: + numeric_ids: type: boolean description: | Only store/extract numeric user and group identifiers. @@ -90,10 +90,10 @@ properties: used, the setting here is ignored and read_special is considered true. example: false - bsd_flags: + flags: type: boolean description: | - Record bsdflags (e.g. NODUMP, IMMUTABLE) in archive. + Record filesystem flags (e.g. NODUMP, IMMUTABLE) in archive. Defaults to true. example: true files_cache: @@ -255,7 +255,7 @@ properties: http://borgbackup.readthedocs.io/en/stable/usage/create.html for details. Defaults to "lz4". example: lz4 - remote_rate_limit: + upload_rate_limit: type: integer description: | Remote network upload rate limit in kiBytes/second. Defaults diff --git a/tests/unit/borg/test_create.py b/tests/unit/borg/test_create.py index 163000679..453dbf427 100644 --- a/tests/unit/borg/test_create.py +++ b/tests/unit/borg/test_create.py @@ -794,7 +794,7 @@ def test_create_archive_with_compression_calls_borg_with_compression_parameters( @pytest.mark.parametrize( 'feature_available,option_flag', ((True, '--upload-ratelimit'), (False, '--remote-ratelimit')), ) -def test_create_archive_with_remote_rate_limit_calls_borg_with_upload_ratelimit_parameters( +def test_create_archive_with_upload_rate_limit_calls_borg_with_upload_ratelimit_parameters( feature_available, option_flag ): flexmock(module).should_receive('borgmatic_source_directories').and_return([]) @@ -829,7 +829,7 @@ def test_create_archive_with_remote_rate_limit_calls_borg_with_upload_ratelimit_ 'repositories': ['repo'], 'exclude_patterns': None, }, - storage_config={'remote_rate_limit': 100}, + storage_config={'upload_rate_limit': 100}, local_borg_version='1.2.3', ) @@ -917,7 +917,7 @@ def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_par @pytest.mark.parametrize( 'feature_available,option_flag', ((True, '--numeric-ids'), (False, '--numeric-owner')), ) -def test_create_archive_with_numeric_owner_calls_borg_with_numeric_ids_parameter( +def test_create_archive_with_numeric_ids_calls_borg_with_numeric_ids_parameter( feature_available, option_flag ): flexmock(module).should_receive('borgmatic_source_directories').and_return([]) @@ -950,7 +950,7 @@ def test_create_archive_with_numeric_owner_calls_borg_with_numeric_ids_parameter location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], - 'numeric_owner': True, + 'numeric_ids': True, 'exclude_patterns': None, }, storage_config={}, @@ -1102,7 +1102,7 @@ def test_create_archive_with_atime_option_calls_borg_with_corresponding_paramete (False, False, '--nobsdflags'), ), ) -def test_create_archive_with_bsd_flags_option_calls_borg_with_corresponding_parameter( +def test_create_archive_with_flags_option_calls_borg_with_corresponding_parameter( option_value, feature_available, option_flag ): flexmock(module).should_receive('borgmatic_source_directories').and_return([]) @@ -1135,7 +1135,7 @@ def test_create_archive_with_bsd_flags_option_calls_borg_with_corresponding_para location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], - 'bsd_flags': option_value, + 'flags': option_value, 'exclude_patterns': None, }, storage_config={}, diff --git a/tests/unit/borg/test_extract.py b/tests/unit/borg/test_extract.py index 8e54dbc03..d572ff9e4 100644 --- a/tests/unit/borg/test_extract.py +++ b/tests/unit/borg/test_extract.py @@ -174,7 +174,7 @@ def test_extract_archive_calls_borg_with_numeric_ids_parameter(feature_available repository='repo', archive='archive', paths=None, - location_config={'numeric_owner': True}, + location_config={'numeric_ids': True}, storage_config={}, local_borg_version='1.2.3', ) diff --git a/tests/unit/config/test_normalize.py b/tests/unit/config/test_normalize.py index dfb41bb8f..93508ecc2 100644 --- a/tests/unit/config/test_normalize.py +++ b/tests/unit/config/test_normalize.py @@ -51,6 +51,13 @@ from borgmatic.config import normalize as module {'consistency': {'checks': [{'name': 'archives'}]}}, False, ), + ({'location': {'numeric_owner': False}}, {'location': {'numeric_ids': False}}, False,), + ({'location': {'bsd_flags': False}}, {'location': {'flags': False}}, False,), + ( + {'storage': {'remote_rate_limit': False}}, + {'storage': {'upload_rate_limit': False}}, + False, + ), ( {'location': {'repositories': ['foo@bar:/repo']}}, {'location': {'repositories': ['ssh://foo@bar/repo']}},