diff --git a/NEWS b/NEWS index b8b9a7cb..45ad00ef 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ * #936: Clarify Zabbix monitoring hook documentation about creating items: https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#zabbix-hook * #1017: Fix a regression in which some MariaDB/MySQL passwords were not escaped correctly. + * #1021: Fix a regression in which the "exclude_patterns" option didn't expand "~" (the user's + home directory). This fix means that all "patterns" and "patterns_from" also now expand "~". 1.9.13 * #975: Add a "compression" option to the PostgreSQL database hook. diff --git a/borgmatic/actions/create.py b/borgmatic/actions/create.py index 11928f62..ecc688b5 100644 --- a/borgmatic/actions/create.py +++ b/borgmatic/actions/create.py @@ -130,8 +130,11 @@ def expand_directory(directory, working_directory): def expand_patterns(patterns, working_directory=None, skip_paths=None): ''' Given a sequence of borgmatic.borg.pattern.Pattern instances and an optional working directory, - expand tildes and globs in each root pattern. Return all the resulting patterns (not just the - root patterns) as a tuple. + expand tildes and globs in each root pattern and expand just tildes in each non-root pattern. + The idea is that non-root patterns may be regular expressions or other pattern styles containing + "*" that borgmatic should not expand as a shell glob. + + Return all the resulting patterns as a tuple. If a set of paths are given to skip, then don't expand any patterns matching them. ''' @@ -153,7 +156,15 @@ def expand_patterns(patterns, working_directory=None, skip_paths=None): ) if pattern.type == borgmatic.borg.pattern.Pattern_type.ROOT and pattern.path not in (skip_paths or ()) - else (pattern,) + else ( + borgmatic.borg.pattern.Pattern( + os.path.expanduser(pattern.path), + pattern.type, + pattern.style, + pattern.device, + pattern.source, + ), + ) ) for pattern in patterns ) diff --git a/tests/unit/actions/test_create.py b/tests/unit/actions/test_create.py index 1e93557d..1f6ca7dc 100644 --- a/tests/unit/actions/test_create.py +++ b/tests/unit/actions/test_create.py @@ -225,15 +225,24 @@ def test_expand_patterns_considers_none_as_no_patterns(): assert module.expand_patterns(None) == () -def test_expand_patterns_only_considers_root_patterns(): - flexmock(module).should_receive('expand_directory').with_args('~/foo', None).and_return( - ['/root/foo'] +def test_expand_patterns_expands_tildes_and_globs_in_root_patterns(): + flexmock(module.os.path).should_receive('expanduser').never() + flexmock(module).should_receive('expand_directory').and_return( + ['/root/foo/one', '/root/foo/two'] ) - flexmock(module).should_receive('expand_directory').with_args('bar*', None).never() - paths = module.expand_patterns((Pattern('~/foo'), Pattern('bar*', Pattern_type.INCLUDE))) + paths = module.expand_patterns((Pattern('~/foo/*'),)) - assert paths == (Pattern('/root/foo'), Pattern('bar*', Pattern_type.INCLUDE)) + assert paths == (Pattern('/root/foo/one'), Pattern('/root/foo/two')) + + +def test_expand_patterns_expands_only_tildes_in_non_root_patterns(): + flexmock(module).should_receive('expand_directory').never() + flexmock(module.os.path).should_receive('expanduser').and_return('/root/bar/*') + + paths = module.expand_patterns((Pattern('~/bar/*', Pattern_type.INCLUDE),)) + + assert paths == (Pattern('/root/bar/*', Pattern_type.INCLUDE),) def test_device_map_patterns_gives_device_id_per_path():