When using the "bsd_flags" option, tailor the flags passed to Borg depending on the Borg version (#394).

This commit is contained in:
Dan Helfman 2022-02-09 21:11:00 -08:00
parent 4b5af2770d
commit 6bf6ac310b
6 changed files with 65 additions and 16 deletions

3
NEWS
View file

@ -2,7 +2,8 @@
* #394: Compact repository segments and free space with new "borgmatic compact" action. Borg 1.2+
only. Also run "compact" by default when no actions are specified, as "prune" in Borg 1.2 no
longer frees up space unless "compact" is run.
* #394: When the "atime" option is used, tailor the flags passed to Borg depending on version.
* #394: When using the "atime" or "bsd_flags" options, tailor the flags passed to Borg depending on
the Borg version.
* #480, #482: Fix traceback when a YAML validation error occurs.
1.5.22

View file

@ -227,12 +227,16 @@ def create_archive(
archive_name_format = storage_config.get('archive_name_format', DEFAULT_ARCHIVE_NAME_FORMAT)
extra_borg_options = storage_config.get('extra_borg_options', {}).get('create', '')
atime_feature_available = feature.available(feature.Feature.ATIME, local_borg_version)
if atime_feature_available:
if feature.available(feature.Feature.ATIME, local_borg_version):
atime_flags = ('--atime',) if location_config.get('atime') is True else ()
else:
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 ()
else:
noflags_flags = ('--nobsdflags',) if location_config.get('bsd_flags') is False else ()
full_command = (
tuple(local_path.split(' '))
+ ('create',)
@ -252,7 +256,7 @@ def create_archive(
+ (('--noctime',) if location_config.get('ctime') is False else ())
+ (('--nobirthtime',) if location_config.get('birthtime') is False else ())
+ (('--read-special',) if (location_config.get('read_special') or stream_processes) else ())
+ (('--nobsdflags',) if location_config.get('bsd_flags') is False else ())
+ noflags_flags
+ (('--files-cache', files_cache) if files_cache else ())
+ (('--remote-path', remote_path) if remote_path else ())
+ (('--umask', str(umask)) if umask else ())

View file

@ -6,11 +6,13 @@ from pkg_resources import parse_version
class Feature(Enum):
COMPACT = 1
ATIME = 2
NOFLAGS = 3
FEATURE_TO_MINIMUM_BORG_VERSION = {
Feature.COMPACT: parse_version('1.2.0a2'),
Feature.ATIME: parse_version('1.2.0a7'),
Feature.COMPACT: parse_version('1.2.0a2'), # borg compact
Feature.ATIME: parse_version('1.2.0a7'), # borg create --atime
Feature.NOFLAGS: parse_version('1.2.0a8'), # borg create --noflags
}

View file

@ -111,10 +111,10 @@ properties:
type: string
description: |
Any paths matching these patterns are included/excluded from
backups. Globs are expanded. (Tildes are not.) Note that
Borg considers this option experimental. See the output of
"borg help patterns" for more details. Quote any value if it
contains leading punctuation, so it parses correctly.
backups. Globs are expanded. (Tildes are not.) See the
output of "borg help patterns" for more details. Quote any
value if it contains leading punctuation, so it parses
correctly.
example:
- 'R /'
- '- /home/*/.cache'

View file

@ -38,7 +38,7 @@ for sub_command in prune create check list info; do
| grep -v '^--json$' \
| grep -v '^--keep-last$' \
| grep -v '^--list$' \
| grep -v '^--nobsdflags$' \
| grep -v '^--bsdflags$' \
| grep -v '^--pattern$' \
| grep -v '^--progress$' \
| grep -v '^--stats$' \

View file

@ -768,11 +768,9 @@ def test_create_archive_with_read_special_calls_borg_with_read_special_parameter
('ctime', False),
('birthtime', True),
('birthtime', False),
('bsd_flags', True),
('bsd_flags', False),
),
)
def test_create_archive_with_option_calls_borg_without_corresponding_parameter(
def test_create_archive_with_basic_option_calls_borg_with_corresponding_parameter(
option_name, option_value
):
option_flag = '--no' + option_name.replace('_', '') if option_value is False else None
@ -815,7 +813,7 @@ def test_create_archive_with_option_calls_borg_without_corresponding_parameter(
(False, False, '--noatime'),
),
)
def test_create_archive_with_atime_option_calls_borg_without_corresponding_parameter(
def test_create_archive_with_atime_option_calls_borg_with_corresponding_parameter(
option_value, feature_available, option_flag
):
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
@ -824,7 +822,8 @@ def test_create_archive_with_atime_option_calls_borg_without_corresponding_param
flexmock(module).should_receive('_expand_directories').and_return(())
flexmock(module).should_receive('_expand_home_directories').and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module.feature).should_receive('available').and_return(feature_available)
flexmock(module.feature).should_receive('available').with_args(module.feature.Feature.ATIME, '1.2.3').and_return(feature_available)
flexmock(module.feature).should_receive('available').with_args(module.feature.Feature.NOFLAGS, '1.2.3').and_return(True)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
flexmock(module).should_receive('execute_command').with_args(
@ -848,6 +847,49 @@ def test_create_archive_with_atime_option_calls_borg_without_corresponding_param
)
@pytest.mark.parametrize(
'option_value,feature_available,option_flag',
(
(True, True, None),
(True, False, None),
(False, True, '--noflags'),
(False, False, '--nobsdflags'),
),
)
def test_create_archive_with_bsd_flags_option_calls_borg_with_corresponding_parameter(
option_value, feature_available, option_flag
):
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
flexmock(module).should_receive('map_directories_to_devices').and_return({})
flexmock(module).should_receive('_expand_directories').and_return(())
flexmock(module).should_receive('_expand_home_directories').and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module.feature).should_receive('available').with_args(module.feature.Feature.ATIME, '1.2.3').and_return(True)
flexmock(module.feature).should_receive('available').with_args(module.feature.Feature.NOFLAGS, '1.2.3').and_return(feature_available)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
flexmock(module).should_receive('execute_command').with_args(
('borg', 'create') + ((option_flag,) if option_flag else ()) + ARCHIVE_WITH_PATHS,
output_log_level=logging.INFO,
output_file=None,
borg_local_path='borg',
)
module.create_archive(
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
'repositories': ['repo'],
'bsd_flags': option_value,
'exclude_patterns': None,
},
storage_config={},
local_borg_version='1.2.3',
)
def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters():
flexmock(module).should_receive('borgmatic_source_directories').and_return([])
flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))