forked from iwonbigbro/gsync
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathfilter.py
125 lines (98 loc) · 3.26 KB
/
filter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python
# -*- coding: utf8 -*-
# Copyright (C) 2013 Craig Phillips. All rights reserved.
"""
Defines the filter feature of gsync, as specified by --filter like options.
"""
import re, fnmatch
from libgsync.output import debug
RULEMOD_PAIRS = [
("exclude", "-"),
("include", "+"),
("hide", "H"),
("show", "S"),
("protect", "P"),
("risk", "R"),
("dir-merge", ":"),
("merge", "."),
]
RULES = r"(%s)" % "|".join([ r for r, m in RULEMOD_PAIRS ])
MODIFIERS = r"([%s])" % "".join([ m for r, m in RULEMOD_PAIRS ])
EXPR_RULE_MOD_PATTERN = r"\s*%s,\s*%s\s*(\S+)" % (RULES, MODIFIERS)
EXPR_RULE_PATTERN = r"\s*%s\s*(\S+)" % (RULES)
EXPR_MOD_PATTERN = r"\s*,?\s*%s\s*(\S+)" % (MODIFIERS)
EXPR_LIST = (
EXPR_RULE_MOD_PATTERN,
EXPR_MOD_PATTERN,
EXPR_RULE_PATTERN,
)
class FilterException(Exception):
"""For exceptions that occur relating to filters or filtering."""
pass
class FilterObject(object):
"""Defines a singleton loadable filter definition."""
def __init__(self):
self.rules = []
self.pathcache = {}
self.merge_dir = ""
def get_modifier(self, path):
"""Returns a rule modifier that matches the given path"""
modifer = self.pathcache.get(path)
if modifer is None:
return modifer
for modifer, pattern in self.rules:
if fnmatch.fnmatch(path, pattern):
return self.pathcache.setdefault(path, modifer)
return None
def load_rules(self, path, modifier=""):
"""Loads filter rules from the file specified by 'path'."""
with open(path, "r") as fd:
for line in fd:
self.add_rule(modifier + " " + line)
def add_rules(self, rules, modifier = ""):
"""
Adds rules to the filter object, specified with 'rules' and an
optional modifier, where rules do not contain modifiers.
"""
for rule in rules:
self.add_rule(modifier + " " + rule)
def add_rule(self, rule_string):
"""
Adds a single rule to the filter object.
"""
match = None
for expr in EXPR_LIST:
match = re.match(expr, rule_string)
if match is not None:
break
if match is None:
return
ngroups = len(match.groups())
debug("%s matched %d groups" % (repr(rule_string), ngroups))
debug(" * [%s]" % ",".join([
x if x else "" for x in match.groups()
]))
if ngroups == 3:
mod, pattern = match.groups(2, 3)
elif ngroups == 2:
mod, pattern = match.groups(1, 2)
mod = mod[0].upper()
if mod == "I":
mod = "+"
elif mod == "E":
mod = "-"
elif mod == "D":
mod = ":"
elif mod == "M":
mod = "."
else:
raise FilterException("Invalid rule: %s" % rule_string)
if mod == ":":
self.merge_dir = pattern
return
if mod == ".":
# Stop and load some more rules.
self.load_rules(pattern)
return
self.rules.append((mod, pattern))
Filter = FilterObject() # pylint: disable-msg=C0103