root / lib / qlang.py @ 8ee9a4f0
History | View | Annotate | Download (9.6 kB)
1 | a123dc19 | Michael Hanselmann | #
|
---|---|---|---|
2 | a123dc19 | Michael Hanselmann | #
|
3 | a123dc19 | Michael Hanselmann | |
4 | 2cfbc784 | Iustin Pop | # Copyright (C) 2010, 2011, 2012 Google Inc.
|
5 | a123dc19 | Michael Hanselmann | #
|
6 | a123dc19 | Michael Hanselmann | # This program is free software; you can redistribute it and/or modify
|
7 | a123dc19 | Michael Hanselmann | # it under the terms of the GNU General Public License as published by
|
8 | a123dc19 | Michael Hanselmann | # the Free Software Foundation; either version 2 of the License, or
|
9 | a123dc19 | Michael Hanselmann | # (at your option) any later version.
|
10 | a123dc19 | Michael Hanselmann | #
|
11 | a123dc19 | Michael Hanselmann | # This program is distributed in the hope that it will be useful, but
|
12 | a123dc19 | Michael Hanselmann | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | a123dc19 | Michael Hanselmann | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | a123dc19 | Michael Hanselmann | # General Public License for more details.
|
15 | a123dc19 | Michael Hanselmann | #
|
16 | a123dc19 | Michael Hanselmann | # You should have received a copy of the GNU General Public License
|
17 | a123dc19 | Michael Hanselmann | # along with this program; if not, write to the Free Software
|
18 | a123dc19 | Michael Hanselmann | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | a123dc19 | Michael Hanselmann | # 02110-1301, USA.
|
20 | a123dc19 | Michael Hanselmann | |
21 | a123dc19 | Michael Hanselmann | |
22 | 341ff8e9 | Michael Hanselmann | """Module for a simple query language
|
23 | 341ff8e9 | Michael Hanselmann |
|
24 | 341ff8e9 | Michael Hanselmann | A query filter is always a list. The first item in the list is the operator
|
25 | 341ff8e9 | Michael Hanselmann | (e.g. C{[OP_AND, ...]}), while the other items depend on the operator. For
|
26 | 341ff8e9 | Michael Hanselmann | logic operators (e.g. L{OP_AND}, L{OP_OR}), they are subfilters whose results
|
27 | 341ff8e9 | Michael Hanselmann | are combined. Unary operators take exactly one other item (e.g. a subfilter for
|
28 | 341ff8e9 | Michael Hanselmann | L{OP_NOT} and a field name for L{OP_TRUE}). Binary operators take exactly two
|
29 | 341ff8e9 | Michael Hanselmann | operands, usually a field name and a value to compare against. Filters are
|
30 | 341ff8e9 | Michael Hanselmann | converted to callable functions by L{query._CompileFilter}.
|
31 | 341ff8e9 | Michael Hanselmann |
|
32 | 341ff8e9 | Michael Hanselmann | """
|
33 | a123dc19 | Michael Hanselmann | |
34 | 7578ab0a | Michael Hanselmann | import re |
35 | b459a848 | Andrea Spadaccini | import string # pylint: disable=W0402 |
36 | f8638e28 | Michael Hanselmann | import logging |
37 | 7578ab0a | Michael Hanselmann | |
38 | 7578ab0a | Michael Hanselmann | import pyparsing as pyp |
39 | 7578ab0a | Michael Hanselmann | |
40 | 7578ab0a | Michael Hanselmann | from ganeti import errors |
41 | 16629d10 | Michael Hanselmann | from ganeti import utils |
42 | f8638e28 | Michael Hanselmann | from ganeti import compat |
43 | 7578ab0a | Michael Hanselmann | |
44 | 7578ab0a | Michael Hanselmann | |
45 | 341ff8e9 | Michael Hanselmann | # Logic operators with one or more operands, each of which is a filter on its
|
46 | 341ff8e9 | Michael Hanselmann | # own
|
47 | a123dc19 | Michael Hanselmann | OP_OR = "|"
|
48 | 88076fd1 | Michael Hanselmann | OP_AND = "&"
|
49 | 88076fd1 | Michael Hanselmann | |
50 | 88076fd1 | Michael Hanselmann | |
51 | 341ff8e9 | Michael Hanselmann | # Unary operators with exactly one operand
|
52 | 88076fd1 | Michael Hanselmann | OP_NOT = "!"
|
53 | 3b877f08 | Michael Hanselmann | OP_TRUE = "?"
|
54 | 88076fd1 | Michael Hanselmann | |
55 | 88076fd1 | Michael Hanselmann | |
56 | 341ff8e9 | Michael Hanselmann | # Binary operators with exactly two operands, the field name and an
|
57 | 341ff8e9 | Michael Hanselmann | # operator-specific value
|
58 | a123dc19 | Michael Hanselmann | OP_EQUAL = "="
|
59 | 88076fd1 | Michael Hanselmann | OP_NOT_EQUAL = "!="
|
60 | ad48eacc | Michael Hanselmann | OP_LT = "<"
|
61 | ad48eacc | Michael Hanselmann | OP_LE = "<="
|
62 | ad48eacc | Michael Hanselmann | OP_GT = ">"
|
63 | ad48eacc | Michael Hanselmann | OP_GE = ">="
|
64 | 88076fd1 | Michael Hanselmann | OP_REGEXP = "=~"
|
65 | 88076fd1 | Michael Hanselmann | OP_CONTAINS = "=[]"
|
66 | a123dc19 | Michael Hanselmann | |
67 | a123dc19 | Michael Hanselmann | |
68 | 0b0ca0c0 | Michael Hanselmann | #: Characters used for detecting user-written filters (see L{_CheckFilter})
|
69 | ad48eacc | Michael Hanselmann | FILTER_DETECTION_CHARS = frozenset("()=/!~'\"\\<>" + string.whitespace) |
70 | f8638e28 | Michael Hanselmann | |
71 | 0b0ca0c0 | Michael Hanselmann | #: Characters used to detect globbing filters (see L{_CheckGlobbing})
|
72 | f8638e28 | Michael Hanselmann | GLOB_DETECTION_CHARS = frozenset("*?") |
73 | 3f2f55bb | Michael Hanselmann | |
74 | 3f2f55bb | Michael Hanselmann | |
75 | 60cba7f8 | Michael Hanselmann | def MakeSimpleFilter(namefield, values): |
76 | 31554d0a | Michael Hanselmann | """Builds simple a filter.
|
77 | 60cba7f8 | Michael Hanselmann |
|
78 | 60cba7f8 | Michael Hanselmann | @param namefield: Name of field containing item name
|
79 | 60cba7f8 | Michael Hanselmann | @param values: List of names
|
80 | 60cba7f8 | Michael Hanselmann |
|
81 | 60cba7f8 | Michael Hanselmann | """
|
82 | 60cba7f8 | Michael Hanselmann | if values:
|
83 | 60cba7f8 | Michael Hanselmann | return [OP_OR] + [[OP_EQUAL, namefield, i] for i in values] |
84 | 60cba7f8 | Michael Hanselmann | |
85 | 60cba7f8 | Michael Hanselmann | return None |
86 | 7578ab0a | Michael Hanselmann | |
87 | 7578ab0a | Michael Hanselmann | |
88 | 7578ab0a | Michael Hanselmann | def _ConvertLogicOp(op): |
89 | 7578ab0a | Michael Hanselmann | """Creates parsing action function for logic operator.
|
90 | 7578ab0a | Michael Hanselmann |
|
91 | 7578ab0a | Michael Hanselmann | @type op: string
|
92 | 7578ab0a | Michael Hanselmann | @param op: Operator for data structure, e.g. L{OP_AND}
|
93 | 7578ab0a | Michael Hanselmann |
|
94 | 7578ab0a | Michael Hanselmann | """
|
95 | 7578ab0a | Michael Hanselmann | def fn(toks): |
96 | 7578ab0a | Michael Hanselmann | """Converts parser tokens to query operator structure.
|
97 | 7578ab0a | Michael Hanselmann |
|
98 | 7578ab0a | Michael Hanselmann | @rtype: list
|
99 | 7578ab0a | Michael Hanselmann | @return: Query operator structure, e.g. C{[OP_AND, ["=", "foo", "bar"]]}
|
100 | 7578ab0a | Michael Hanselmann |
|
101 | 7578ab0a | Michael Hanselmann | """
|
102 | 7578ab0a | Michael Hanselmann | operands = toks[0]
|
103 | 7578ab0a | Michael Hanselmann | |
104 | 7578ab0a | Michael Hanselmann | if len(operands) == 1: |
105 | 7578ab0a | Michael Hanselmann | return operands[0] |
106 | 7578ab0a | Michael Hanselmann | |
107 | 7578ab0a | Michael Hanselmann | # Build query operator structure
|
108 | 7578ab0a | Michael Hanselmann | return [[op] + operands.asList()]
|
109 | 7578ab0a | Michael Hanselmann | |
110 | 7578ab0a | Michael Hanselmann | return fn
|
111 | 7578ab0a | Michael Hanselmann | |
112 | 7578ab0a | Michael Hanselmann | |
113 | 7578ab0a | Michael Hanselmann | _KNOWN_REGEXP_DELIM = "/#^|"
|
114 | 7578ab0a | Michael Hanselmann | _KNOWN_REGEXP_FLAGS = frozenset("si") |
115 | 7578ab0a | Michael Hanselmann | |
116 | 7578ab0a | Michael Hanselmann | |
117 | 7578ab0a | Michael Hanselmann | def _ConvertRegexpValue(_, loc, toks): |
118 | 7578ab0a | Michael Hanselmann | """Regular expression value for condition.
|
119 | 7578ab0a | Michael Hanselmann |
|
120 | 7578ab0a | Michael Hanselmann | """
|
121 | 7578ab0a | Michael Hanselmann | (regexp, flags) = toks[0]
|
122 | 7578ab0a | Michael Hanselmann | |
123 | 7578ab0a | Michael Hanselmann | # Ensure only whitelisted flags are used
|
124 | 7578ab0a | Michael Hanselmann | unknown_flags = (frozenset(flags) - _KNOWN_REGEXP_FLAGS)
|
125 | 7578ab0a | Michael Hanselmann | if unknown_flags:
|
126 | 7578ab0a | Michael Hanselmann | raise pyp.ParseFatalException("Unknown regular expression flags: '%s'" % |
127 | 7578ab0a | Michael Hanselmann | "".join(unknown_flags), loc)
|
128 | 7578ab0a | Michael Hanselmann | |
129 | 7578ab0a | Michael Hanselmann | if flags:
|
130 | 7578ab0a | Michael Hanselmann | re_flags = "(?%s)" % "".join(sorted(flags)) |
131 | 7578ab0a | Michael Hanselmann | else:
|
132 | 7578ab0a | Michael Hanselmann | re_flags = ""
|
133 | 7578ab0a | Michael Hanselmann | |
134 | 7578ab0a | Michael Hanselmann | re_cond = re_flags + regexp |
135 | 7578ab0a | Michael Hanselmann | |
136 | 7578ab0a | Michael Hanselmann | # Test if valid
|
137 | 7578ab0a | Michael Hanselmann | try:
|
138 | 7578ab0a | Michael Hanselmann | re.compile(re_cond) |
139 | 7578ab0a | Michael Hanselmann | except re.error, err:
|
140 | 7578ab0a | Michael Hanselmann | raise pyp.ParseFatalException("Invalid regular expression (%s)" % err, loc) |
141 | 7578ab0a | Michael Hanselmann | |
142 | 7578ab0a | Michael Hanselmann | return [re_cond]
|
143 | 7578ab0a | Michael Hanselmann | |
144 | 7578ab0a | Michael Hanselmann | |
145 | 7578ab0a | Michael Hanselmann | def BuildFilterParser(): |
146 | 7578ab0a | Michael Hanselmann | """Builds a parser for query filter strings.
|
147 | 7578ab0a | Michael Hanselmann |
|
148 | 7578ab0a | Michael Hanselmann | @rtype: pyparsing.ParserElement
|
149 | 7578ab0a | Michael Hanselmann |
|
150 | 7578ab0a | Michael Hanselmann | """
|
151 | 7578ab0a | Michael Hanselmann | field_name = pyp.Word(pyp.alphas, pyp.alphanums + "_/.")
|
152 | 7578ab0a | Michael Hanselmann | |
153 | 7578ab0a | Michael Hanselmann | # Integer
|
154 | 7578ab0a | Michael Hanselmann | num_sign = pyp.Word("-+", exact=1) |
155 | 7578ab0a | Michael Hanselmann | number = pyp.Combine(pyp.Optional(num_sign) + pyp.Word(pyp.nums)) |
156 | 7578ab0a | Michael Hanselmann | number.setParseAction(lambda toks: int(toks[0])) |
157 | 7578ab0a | Michael Hanselmann | |
158 | 16629d10 | Michael Hanselmann | quoted_string = pyp.quotedString.copy().setParseAction(pyp.removeQuotes) |
159 | 16629d10 | Michael Hanselmann | |
160 | 7578ab0a | Michael Hanselmann | # Right-hand-side value
|
161 | 16629d10 | Michael Hanselmann | rval = (number | quoted_string) |
162 | 7578ab0a | Michael Hanselmann | |
163 | 7578ab0a | Michael Hanselmann | # Boolean condition
|
164 | 7578ab0a | Michael Hanselmann | bool_cond = field_name.copy() |
165 | 7578ab0a | Michael Hanselmann | bool_cond.setParseAction(lambda (fname, ): [[OP_TRUE, fname]])
|
166 | 7578ab0a | Michael Hanselmann | |
167 | 7578ab0a | Michael Hanselmann | # Simple binary conditions
|
168 | 7578ab0a | Michael Hanselmann | binopstbl = { |
169 | 7578ab0a | Michael Hanselmann | "==": OP_EQUAL,
|
170 | 7578ab0a | Michael Hanselmann | "!=": OP_NOT_EQUAL,
|
171 | ad48eacc | Michael Hanselmann | "<": OP_LT,
|
172 | ad48eacc | Michael Hanselmann | "<=": OP_LE,
|
173 | ad48eacc | Michael Hanselmann | ">": OP_GT,
|
174 | ad48eacc | Michael Hanselmann | ">=": OP_GE,
|
175 | 7578ab0a | Michael Hanselmann | } |
176 | 7578ab0a | Michael Hanselmann | |
177 | 7578ab0a | Michael Hanselmann | binary_cond = (field_name + pyp.oneOf(binopstbl.keys()) + rval) |
178 | 7578ab0a | Michael Hanselmann | binary_cond.setParseAction(lambda (lhs, op, rhs): [[binopstbl[op], lhs, rhs]])
|
179 | 7578ab0a | Michael Hanselmann | |
180 | 7578ab0a | Michael Hanselmann | # "in" condition
|
181 | 7578ab0a | Michael Hanselmann | in_cond = (rval + pyp.Suppress("in") + field_name)
|
182 | 7578ab0a | Michael Hanselmann | in_cond.setParseAction(lambda (value, field): [[OP_CONTAINS, field, value]])
|
183 | 7578ab0a | Michael Hanselmann | |
184 | 7578ab0a | Michael Hanselmann | # "not in" condition
|
185 | 7578ab0a | Michael Hanselmann | not_in_cond = (rval + pyp.Suppress("not") + pyp.Suppress("in") + field_name) |
186 | 7578ab0a | Michael Hanselmann | not_in_cond.setParseAction(lambda (value, field): [[OP_NOT, [OP_CONTAINS,
|
187 | 7578ab0a | Michael Hanselmann | field, value]]]) |
188 | 7578ab0a | Michael Hanselmann | |
189 | 7578ab0a | Michael Hanselmann | # Regular expression, e.g. m/foobar/i
|
190 | 7578ab0a | Michael Hanselmann | regexp_val = pyp.Group(pyp.Optional("m").suppress() +
|
191 | 7578ab0a | Michael Hanselmann | pyp.MatchFirst([pyp.QuotedString(i, escChar="\\")
|
192 | 7578ab0a | Michael Hanselmann | for i in _KNOWN_REGEXP_DELIM]) + |
193 | 7578ab0a | Michael Hanselmann | pyp.Optional(pyp.Word(pyp.alphas), default=""))
|
194 | 7578ab0a | Michael Hanselmann | regexp_val.setParseAction(_ConvertRegexpValue) |
195 | 7578ab0a | Michael Hanselmann | regexp_cond = (field_name + pyp.Suppress("=~") + regexp_val)
|
196 | 7578ab0a | Michael Hanselmann | regexp_cond.setParseAction(lambda (field, value): [[OP_REGEXP, field, value]])
|
197 | 7578ab0a | Michael Hanselmann | |
198 | 7578ab0a | Michael Hanselmann | not_regexp_cond = (field_name + pyp.Suppress("!~") + regexp_val)
|
199 | 7578ab0a | Michael Hanselmann | not_regexp_cond.setParseAction(lambda (field, value):
|
200 | 7578ab0a | Michael Hanselmann | [[OP_NOT, [OP_REGEXP, field, value]]]) |
201 | 7578ab0a | Michael Hanselmann | |
202 | 16629d10 | Michael Hanselmann | # Globbing, e.g. name =* "*.site"
|
203 | 16629d10 | Michael Hanselmann | glob_cond = (field_name + pyp.Suppress("=*") + quoted_string)
|
204 | 16629d10 | Michael Hanselmann | glob_cond.setParseAction(lambda (field, value):
|
205 | 16629d10 | Michael Hanselmann | [[OP_REGEXP, field, |
206 | 16629d10 | Michael Hanselmann | utils.DnsNameGlobPattern(value)]]) |
207 | 16629d10 | Michael Hanselmann | |
208 | 16629d10 | Michael Hanselmann | not_glob_cond = (field_name + pyp.Suppress("!*") + quoted_string)
|
209 | 16629d10 | Michael Hanselmann | not_glob_cond.setParseAction(lambda (field, value):
|
210 | 16629d10 | Michael Hanselmann | [[OP_NOT, [OP_REGEXP, field, |
211 | 16629d10 | Michael Hanselmann | utils.DnsNameGlobPattern(value)]]]) |
212 | 16629d10 | Michael Hanselmann | |
213 | 7578ab0a | Michael Hanselmann | # All possible conditions
|
214 | 7578ab0a | Michael Hanselmann | condition = (binary_cond ^ bool_cond ^ |
215 | 7578ab0a | Michael Hanselmann | in_cond ^ not_in_cond ^ |
216 | 16629d10 | Michael Hanselmann | regexp_cond ^ not_regexp_cond ^ |
217 | 16629d10 | Michael Hanselmann | glob_cond ^ not_glob_cond) |
218 | 7578ab0a | Michael Hanselmann | |
219 | 7578ab0a | Michael Hanselmann | # Associativity operators
|
220 | 7578ab0a | Michael Hanselmann | filter_expr = pyp.operatorPrecedence(condition, [ |
221 | 7578ab0a | Michael Hanselmann | (pyp.Keyword("not").suppress(), 1, pyp.opAssoc.RIGHT, |
222 | 7578ab0a | Michael Hanselmann | lambda toks: [[OP_NOT, toks[0][0]]]), |
223 | 7578ab0a | Michael Hanselmann | (pyp.Keyword("and").suppress(), 2, pyp.opAssoc.LEFT, |
224 | 7578ab0a | Michael Hanselmann | _ConvertLogicOp(OP_AND)), |
225 | 7578ab0a | Michael Hanselmann | (pyp.Keyword("or").suppress(), 2, pyp.opAssoc.LEFT, |
226 | 7578ab0a | Michael Hanselmann | _ConvertLogicOp(OP_OR)), |
227 | 7578ab0a | Michael Hanselmann | ]) |
228 | 7578ab0a | Michael Hanselmann | |
229 | 7578ab0a | Michael Hanselmann | parser = pyp.StringStart() + filter_expr + pyp.StringEnd() |
230 | 7578ab0a | Michael Hanselmann | parser.parseWithTabs() |
231 | 7578ab0a | Michael Hanselmann | |
232 | 7578ab0a | Michael Hanselmann | # Originally C{parser.validate} was called here, but there seems to be some
|
233 | 7578ab0a | Michael Hanselmann | # issue causing it to fail whenever the "not" operator is included above.
|
234 | 7578ab0a | Michael Hanselmann | |
235 | 7578ab0a | Michael Hanselmann | return parser
|
236 | 7578ab0a | Michael Hanselmann | |
237 | 7578ab0a | Michael Hanselmann | |
238 | 7578ab0a | Michael Hanselmann | def ParseFilter(text, parser=None): |
239 | 7578ab0a | Michael Hanselmann | """Parses a query filter.
|
240 | 7578ab0a | Michael Hanselmann |
|
241 | 7578ab0a | Michael Hanselmann | @type text: string
|
242 | 7578ab0a | Michael Hanselmann | @param text: Query filter
|
243 | 7578ab0a | Michael Hanselmann | @type parser: pyparsing.ParserElement
|
244 | 7578ab0a | Michael Hanselmann | @param parser: Pyparsing object
|
245 | 7578ab0a | Michael Hanselmann | @rtype: list
|
246 | 7578ab0a | Michael Hanselmann |
|
247 | 7578ab0a | Michael Hanselmann | """
|
248 | f8638e28 | Michael Hanselmann | logging.debug("Parsing as query filter: %s", text)
|
249 | f8638e28 | Michael Hanselmann | |
250 | 7578ab0a | Michael Hanselmann | if parser is None: |
251 | 7578ab0a | Michael Hanselmann | parser = BuildFilterParser() |
252 | 7578ab0a | Michael Hanselmann | |
253 | 7578ab0a | Michael Hanselmann | try:
|
254 | 7578ab0a | Michael Hanselmann | return parser.parseString(text)[0] |
255 | 7578ab0a | Michael Hanselmann | except pyp.ParseBaseException, err:
|
256 | 7578ab0a | Michael Hanselmann | raise errors.QueryFilterParseError("Failed to parse query filter" |
257 | 7578ab0a | Michael Hanselmann | " '%s': %s" % (text, err), err)
|
258 | 3f2f55bb | Michael Hanselmann | |
259 | 3f2f55bb | Michael Hanselmann | |
260 | f8638e28 | Michael Hanselmann | def _CheckFilter(text): |
261 | f8638e28 | Michael Hanselmann | """CHecks if a string could be a filter.
|
262 | f8638e28 | Michael Hanselmann |
|
263 | f8638e28 | Michael Hanselmann | @rtype: bool
|
264 | f8638e28 | Michael Hanselmann |
|
265 | f8638e28 | Michael Hanselmann | """
|
266 | f8638e28 | Michael Hanselmann | return bool(frozenset(text) & FILTER_DETECTION_CHARS) |
267 | f8638e28 | Michael Hanselmann | |
268 | f8638e28 | Michael Hanselmann | |
269 | f8638e28 | Michael Hanselmann | def _CheckGlobbing(text): |
270 | f8638e28 | Michael Hanselmann | """Checks if a string could be a globbing pattern.
|
271 | f8638e28 | Michael Hanselmann |
|
272 | f8638e28 | Michael Hanselmann | @rtype: bool
|
273 | f8638e28 | Michael Hanselmann |
|
274 | f8638e28 | Michael Hanselmann | """
|
275 | f8638e28 | Michael Hanselmann | return bool(frozenset(text) & GLOB_DETECTION_CHARS) |
276 | f8638e28 | Michael Hanselmann | |
277 | f8638e28 | Michael Hanselmann | |
278 | 6f287cf3 | Iustin Pop | def _MakeFilterPart(namefield, text, isnumeric=False): |
279 | f8638e28 | Michael Hanselmann | """Generates filter for one argument.
|
280 | f8638e28 | Michael Hanselmann |
|
281 | f8638e28 | Michael Hanselmann | """
|
282 | 6f287cf3 | Iustin Pop | if isnumeric:
|
283 | 6f287cf3 | Iustin Pop | try:
|
284 | 6f287cf3 | Iustin Pop | number = int(text)
|
285 | 6f287cf3 | Iustin Pop | except (TypeError, ValueError), err: |
286 | 76b62028 | Iustin Pop | raise errors.OpPrereqError("Invalid job ID passed: %s" % str(err), |
287 | 6f287cf3 | Iustin Pop | errors.ECODE_INVAL) |
288 | 6f287cf3 | Iustin Pop | return [OP_EQUAL, namefield, number]
|
289 | 6f287cf3 | Iustin Pop | elif _CheckGlobbing(text):
|
290 | f8638e28 | Michael Hanselmann | return [OP_REGEXP, namefield, utils.DnsNameGlobPattern(text)]
|
291 | f8638e28 | Michael Hanselmann | else:
|
292 | f8638e28 | Michael Hanselmann | return [OP_EQUAL, namefield, text]
|
293 | f8638e28 | Michael Hanselmann | |
294 | f8638e28 | Michael Hanselmann | |
295 | 6f287cf3 | Iustin Pop | def MakeFilter(args, force_filter, namefield=None, isnumeric=False): |
296 | f8638e28 | Michael Hanselmann | """Try to make a filter from arguments to a command.
|
297 | f8638e28 | Michael Hanselmann |
|
298 | f8638e28 | Michael Hanselmann | If the name could be a filter it is parsed as such. If it's just a globbing
|
299 | f8638e28 | Michael Hanselmann | pattern, e.g. "*.site", such a filter is constructed. As a last resort the
|
300 | f8638e28 | Michael Hanselmann | names are treated just as a plain name filter.
|
301 | f8638e28 | Michael Hanselmann |
|
302 | f8638e28 | Michael Hanselmann | @type args: list of string
|
303 | f8638e28 | Michael Hanselmann | @param args: Arguments to command
|
304 | f8638e28 | Michael Hanselmann | @type force_filter: bool
|
305 | f8638e28 | Michael Hanselmann | @param force_filter: Whether to force treatment as a full-fledged filter
|
306 | 03ec545a | Michael Hanselmann | @type namefield: string
|
307 | 03ec545a | Michael Hanselmann | @param namefield: Name of field to use for simple filters (use L{None} for
|
308 | 03ec545a | Michael Hanselmann | a default of "name")
|
309 | 6f287cf3 | Iustin Pop | @type isnumeric: bool
|
310 | 6f287cf3 | Iustin Pop | @param isnumeric: Whether the namefield type is numeric, as opposed to
|
311 | 6f287cf3 | Iustin Pop | the default string type; this influences how the filter is built
|
312 | f8638e28 | Michael Hanselmann | @rtype: list
|
313 | f8638e28 | Michael Hanselmann | @return: Query filter
|
314 | f8638e28 | Michael Hanselmann |
|
315 | f8638e28 | Michael Hanselmann | """
|
316 | 03ec545a | Michael Hanselmann | if namefield is None: |
317 | 03ec545a | Michael Hanselmann | namefield = "name"
|
318 | 03ec545a | Michael Hanselmann | |
319 | f8638e28 | Michael Hanselmann | if (force_filter or |
320 | f8638e28 | Michael Hanselmann | (args and len(args) == 1 and _CheckFilter(args[0]))): |
321 | f8638e28 | Michael Hanselmann | try:
|
322 | f8638e28 | Michael Hanselmann | (filter_text, ) = args |
323 | f8638e28 | Michael Hanselmann | except (TypeError, ValueError): |
324 | f8638e28 | Michael Hanselmann | raise errors.OpPrereqError("Exactly one argument must be given as a" |
325 | 2cfbc784 | Iustin Pop | " filter", errors.ECODE_INVAL)
|
326 | f8638e28 | Michael Hanselmann | |
327 | f8638e28 | Michael Hanselmann | result = ParseFilter(filter_text) |
328 | f8638e28 | Michael Hanselmann | elif args:
|
329 | 6f287cf3 | Iustin Pop | result = [OP_OR] + map(compat.partial(_MakeFilterPart, namefield,
|
330 | 6f287cf3 | Iustin Pop | isnumeric=isnumeric), args) |
331 | f8638e28 | Michael Hanselmann | else:
|
332 | f8638e28 | Michael Hanselmann | result = None
|
333 | f8638e28 | Michael Hanselmann | |
334 | f8638e28 | Michael Hanselmann | return result |