diff --git a/borgmatic/actions/create.py b/borgmatic/actions/create.py index 126f791d..ffbecd2e 100644 --- a/borgmatic/actions/create.py +++ b/borgmatic/actions/create.py @@ -15,7 +15,7 @@ import borgmatic.hooks.dispatch logger = logging.getLogger(__name__) -def parse_pattern(pattern_line): +def parse_pattern(pattern_line, default_style=borgmatic.borg.pattern.Pattern_style.NONE): ''' Given a Borg pattern as a string, parse it into a borgmatic.borg.pattern.Pattern instance and return it. @@ -26,9 +26,10 @@ def parse_pattern(pattern_line): raise ValueError(f'Invalid pattern: {pattern_line}') try: - (pattern_style, path) = remainder.split(':', maxsplit=1) + (parsed_pattern_style, path) = remainder.split(':', maxsplit=1) + pattern_style = borgmatic.borg.pattern.Pattern_style(parsed_pattern_style) except ValueError: - pattern_style = '' + pattern_style = default_style path = remainder return borgmatic.borg.pattern.Pattern( @@ -54,32 +55,26 @@ def collect_patterns(config): for source_directory in config.get('source_directories', ()) ) + tuple( - parse_pattern(pattern_line.strip()) + parse_pattern(pattern_line.strip(), borgmatic.borg.pattern.Pattern_style.SHELL) for pattern_line in config.get('patterns', ()) if not pattern_line.lstrip().startswith('#') if pattern_line.strip() ) + tuple( - borgmatic.borg.pattern.Pattern( - exclude_line.strip(), - borgmatic.borg.pattern.Pattern_type.EXCLUDE, - borgmatic.borg.pattern.Pattern_style.FNMATCH, - ) + parse_pattern(f'{borgmatic.borg.pattern.Pattern_type.EXCLUDE.value} { + exclude_line.strip()}', borgmatic.borg.pattern.Pattern_style.FNMATCH) for exclude_line in config.get('exclude_patterns', ()) ) + tuple( - parse_pattern(pattern_line.strip()) + parse_pattern(pattern_line.strip(), borgmatic.borg.pattern.Pattern_style.SHELL) for filename in config.get('patterns_from', ()) for pattern_line in open(filename).readlines() if not pattern_line.lstrip().startswith('#') if pattern_line.strip() ) + tuple( - borgmatic.borg.pattern.Pattern( - exclude_line.strip(), - borgmatic.borg.pattern.Pattern_type.EXCLUDE, - borgmatic.borg.pattern.Pattern_style.FNMATCH, - ) + parse_pattern(f'{borgmatic.borg.pattern.Pattern_type.EXCLUDE.value} { + exclude_line.strip()}', borgmatic.borg.pattern.Pattern_style.FNMATCH) for filename in config.get('exclude_from', ()) for exclude_line in open(filename).readlines() if not exclude_line.lstrip().startswith('#') diff --git a/tests/unit/actions/test_create.py b/tests/unit/actions/test_create.py index 523e3dbc..e8322876 100644 --- a/tests/unit/actions/test_create.py +++ b/tests/unit/actions/test_create.py @@ -34,11 +34,13 @@ def test_collect_patterns_converts_source_directories(): def test_collect_patterns_parses_config_patterns(): - flexmock(module).should_receive('parse_pattern').with_args('R /foo').and_return(Pattern('/foo')) + flexmock(module).should_receive('parse_pattern').with_args( + 'R /foo', Pattern_style.SHELL).and_return(Pattern('/foo')) flexmock(module).should_receive('parse_pattern').with_args('# comment').never() flexmock(module).should_receive('parse_pattern').with_args('').never() flexmock(module).should_receive('parse_pattern').with_args(' ').never() - flexmock(module).should_receive('parse_pattern').with_args('R /bar').and_return(Pattern('/bar')) + flexmock(module).should_receive('parse_pattern').with_args( + 'R /bar', Pattern_style.SHELL).and_return(Pattern('/bar')) assert module.collect_patterns({'patterns': ['R /foo', '# comment', '', ' ', 'R /bar']}) == ( Pattern('/foo'), @@ -47,9 +49,10 @@ def test_collect_patterns_parses_config_patterns(): def test_collect_patterns_converts_exclude_patterns(): - assert module.collect_patterns({'exclude_patterns': ['/foo', '/bar']}) == ( + assert module.collect_patterns({'exclude_patterns': ['/foo', '/bar', 'sh:**/baz']}) == ( Pattern('/foo', Pattern_type.EXCLUDE, Pattern_style.FNMATCH), Pattern('/bar', Pattern_type.EXCLUDE, Pattern_style.FNMATCH), + Pattern('**/baz', Pattern_type.EXCLUDE, Pattern_style.SHELL), ) @@ -59,12 +62,15 @@ def test_collect_patterns_reads_config_patterns_from_file(): builtins.should_receive('open').with_args('file2.txt').and_return( io.StringIO('R /bar\n# comment\n\n \nR /baz') ) - flexmock(module).should_receive('parse_pattern').with_args('R /foo').and_return(Pattern('/foo')) + flexmock(module).should_receive('parse_pattern').with_args( + 'R /foo', Pattern_style.SHELL).and_return(Pattern('/foo')) flexmock(module).should_receive('parse_pattern').with_args('# comment').never() flexmock(module).should_receive('parse_pattern').with_args('').never() flexmock(module).should_receive('parse_pattern').with_args(' ').never() - flexmock(module).should_receive('parse_pattern').with_args('R /bar').and_return(Pattern('/bar')) - flexmock(module).should_receive('parse_pattern').with_args('R /baz').and_return(Pattern('/baz')) + flexmock(module).should_receive('parse_pattern').with_args( + 'R /bar', Pattern_style.SHELL).and_return(Pattern('/bar')) + flexmock(module).should_receive('parse_pattern').with_args( + 'R /baz', Pattern_style.SHELL).and_return(Pattern('/baz')) assert module.collect_patterns({'patterns_from': ['file1.txt', 'file2.txt']}) == ( Pattern('/foo'), @@ -88,11 +94,15 @@ def test_collect_patterns_reads_config_exclude_from_file(): builtins.should_receive('open').with_args('file2.txt').and_return( io.StringIO('/bar\n# comment\n\n \n/baz') ) - flexmock(module).should_receive('parse_pattern').with_args('/bar').and_return(Pattern('/bar')) + flexmock(module).should_receive('parse_pattern').with_args( + '- /foo', default_style=Pattern_style.FNMATCH).and_return(Pattern('/foo', Pattern_type.EXCLUDE, Pattern_style.FNMATCH)) + flexmock(module).should_receive('parse_pattern').with_args( + '- /bar', default_style=Pattern_style.FNMATCH).and_return(Pattern('/bar', Pattern_type.EXCLUDE, Pattern_style.FNMATCH)) flexmock(module).should_receive('parse_pattern').with_args('# comment').never() flexmock(module).should_receive('parse_pattern').with_args('').never() flexmock(module).should_receive('parse_pattern').with_args(' ').never() - flexmock(module).should_receive('parse_pattern').with_args('/baz').and_return(Pattern('/baz')) + flexmock(module).should_receive('parse_pattern').with_args( + '- /baz', default_style=Pattern_style.FNMATCH).and_return(Pattern('/baz', Pattern_type.EXCLUDE, Pattern_style.FNMATCH)) assert module.collect_patterns({'exclude_from': ['file1.txt', 'file2.txt']}) == ( Pattern('/foo', Pattern_type.EXCLUDE, Pattern_style.FNMATCH),