diff --git a/borg/helpers.py b/borg/helpers.py index ce344e3f5..39aad5532 100644 --- a/borg/helpers.py +++ b/borg/helpers.py @@ -274,6 +274,27 @@ def exclude_path(path, patterns): return False +class PatternMatcher: + def __init__(self, fallback=None): + self._items = [] + + # Value to return from match function when none of the patterns match. + self.fallback = fallback + + def add(self, patterns, value): + """Add list of patterns to internal list. The given value is returned from the match function when one of the + given patterns matches. + """ + self._items.extend((i, value) for i in patterns) + + def match(self, path): + for (pattern, value) in self._items: + if pattern.match(path): + return value + + return self.fallback + + def normalized(func): """ Decorator for the Pattern match methods, returning a wrapper that normalizes OSX paths to match the normalized pattern on OSX, and diff --git a/borg/testsuite/helpers.py b/borg/testsuite/helpers.py index 725dba9b2..ee8a9e91d 100644 --- a/borg/testsuite/helpers.py +++ b/borg/testsuite/helpers.py @@ -12,7 +12,7 @@ import msgpack.fallback from ..helpers import exclude_path, Location, format_file_size, format_timedelta, PathPrefixPattern, FnmatchPattern, make_path_safe, \ prune_within, prune_split, get_cache_dir, Statistics, is_slow_msgpack, yes, RegexPattern, \ StableDict, int_to_bigint, bigint_to_int, parse_timestamp, CompressionSpec, ChunkerParams, \ - ProgressIndicatorPercent, ProgressIndicatorEndless, load_excludes, parse_pattern + ProgressIndicatorPercent, ProgressIndicatorEndless, load_excludes, parse_pattern, PatternMatcher from . import BaseTestCase, environment_variable, FakeInputs @@ -374,6 +374,29 @@ def test_parse_pattern_error(pattern): parse_pattern(pattern) +def test_pattern_matcher(): + pm = PatternMatcher() + + assert pm.fallback is None + + for i in ["", "foo", "bar"]: + assert pm.match(i) is None + + pm.add([RegexPattern("^a")], "A") + pm.add([RegexPattern("^b"), RegexPattern("^z")], "B") + pm.add([RegexPattern("^$")], "Empty") + pm.fallback = "FileNotFound" + + assert pm.match("") == "Empty" + assert pm.match("aaa") == "A" + assert pm.match("bbb") == "B" + assert pm.match("ccc") == "FileNotFound" + assert pm.match("xyz") == "FileNotFound" + assert pm.match("z") == "B" + + assert PatternMatcher(fallback="hey!").fallback == "hey!" + + def test_compression_specs(): with pytest.raises(ValueError): CompressionSpec('')