##// END OF EJS Templates
fileset: drop backwards SI size units...
Matt Mackall -
r14689:25e4d2f3 stable
parent child Browse files
Show More
@@ -1,428 +1,426 b''
1 # fileset.py - file set queries for mercurial
1 # fileset.py - file set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import parser, error, util, merge, re
8 import parser, error, util, merge, re
9 from i18n import _
9 from i18n import _
10
10
11 elements = {
11 elements = {
12 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
12 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
13 "-": (5, ("negate", 19), ("minus", 5)),
13 "-": (5, ("negate", 19), ("minus", 5)),
14 "not": (10, ("not", 10)),
14 "not": (10, ("not", 10)),
15 "!": (10, ("not", 10)),
15 "!": (10, ("not", 10)),
16 "and": (5, None, ("and", 5)),
16 "and": (5, None, ("and", 5)),
17 "&": (5, None, ("and", 5)),
17 "&": (5, None, ("and", 5)),
18 "or": (4, None, ("or", 4)),
18 "or": (4, None, ("or", 4)),
19 "|": (4, None, ("or", 4)),
19 "|": (4, None, ("or", 4)),
20 "+": (4, None, ("or", 4)),
20 "+": (4, None, ("or", 4)),
21 ",": (2, None, ("list", 2)),
21 ",": (2, None, ("list", 2)),
22 ")": (0, None, None),
22 ")": (0, None, None),
23 "symbol": (0, ("symbol",), None),
23 "symbol": (0, ("symbol",), None),
24 "string": (0, ("string",), None),
24 "string": (0, ("string",), None),
25 "end": (0, None, None),
25 "end": (0, None, None),
26 }
26 }
27
27
28 keywords = set(['and', 'or', 'not'])
28 keywords = set(['and', 'or', 'not'])
29
29
30 globchars = ".*{}[]?/\\"
30 globchars = ".*{}[]?/\\"
31
31
32 def tokenize(program):
32 def tokenize(program):
33 pos, l = 0, len(program)
33 pos, l = 0, len(program)
34 while pos < l:
34 while pos < l:
35 c = program[pos]
35 c = program[pos]
36 if c.isspace(): # skip inter-token whitespace
36 if c.isspace(): # skip inter-token whitespace
37 pass
37 pass
38 elif c in "(),-|&+!": # handle simple operators
38 elif c in "(),-|&+!": # handle simple operators
39 yield (c, None, pos)
39 yield (c, None, pos)
40 elif (c in '"\'' or c == 'r' and
40 elif (c in '"\'' or c == 'r' and
41 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
41 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
42 if c == 'r':
42 if c == 'r':
43 pos += 1
43 pos += 1
44 c = program[pos]
44 c = program[pos]
45 decode = lambda x: x
45 decode = lambda x: x
46 else:
46 else:
47 decode = lambda x: x.decode('string-escape')
47 decode = lambda x: x.decode('string-escape')
48 pos += 1
48 pos += 1
49 s = pos
49 s = pos
50 while pos < l: # find closing quote
50 while pos < l: # find closing quote
51 d = program[pos]
51 d = program[pos]
52 if d == '\\': # skip over escaped characters
52 if d == '\\': # skip over escaped characters
53 pos += 2
53 pos += 2
54 continue
54 continue
55 if d == c:
55 if d == c:
56 yield ('string', decode(program[s:pos]), s)
56 yield ('string', decode(program[s:pos]), s)
57 break
57 break
58 pos += 1
58 pos += 1
59 else:
59 else:
60 raise error.ParseError(_("unterminated string"), s)
60 raise error.ParseError(_("unterminated string"), s)
61 elif c.isalnum() or c in globchars or ord(c) > 127:
61 elif c.isalnum() or c in globchars or ord(c) > 127:
62 # gather up a symbol/keyword
62 # gather up a symbol/keyword
63 s = pos
63 s = pos
64 pos += 1
64 pos += 1
65 while pos < l: # find end of symbol
65 while pos < l: # find end of symbol
66 d = program[pos]
66 d = program[pos]
67 if not (d.isalnum() or d in globchars or ord(d) > 127):
67 if not (d.isalnum() or d in globchars or ord(d) > 127):
68 break
68 break
69 pos += 1
69 pos += 1
70 sym = program[s:pos]
70 sym = program[s:pos]
71 if sym in keywords: # operator keywords
71 if sym in keywords: # operator keywords
72 yield (sym, None, s)
72 yield (sym, None, s)
73 else:
73 else:
74 yield ('symbol', sym, s)
74 yield ('symbol', sym, s)
75 pos -= 1
75 pos -= 1
76 else:
76 else:
77 raise error.ParseError(_("syntax error"), pos)
77 raise error.ParseError(_("syntax error"), pos)
78 pos += 1
78 pos += 1
79 yield ('end', None, pos)
79 yield ('end', None, pos)
80
80
81 parse = parser.parser(tokenize, elements).parse
81 parse = parser.parser(tokenize, elements).parse
82
82
83 def getstring(x, err):
83 def getstring(x, err):
84 if x and (x[0] == 'string' or x[0] == 'symbol'):
84 if x and (x[0] == 'string' or x[0] == 'symbol'):
85 return x[1]
85 return x[1]
86 raise error.ParseError(err)
86 raise error.ParseError(err)
87
87
88 def getset(mctx, x):
88 def getset(mctx, x):
89 if not x:
89 if not x:
90 raise error.ParseError(_("missing argument"))
90 raise error.ParseError(_("missing argument"))
91 return methods[x[0]](mctx, *x[1:])
91 return methods[x[0]](mctx, *x[1:])
92
92
93 def stringset(mctx, x):
93 def stringset(mctx, x):
94 m = mctx.matcher([x])
94 m = mctx.matcher([x])
95 return [f for f in mctx.subset if m(f)]
95 return [f for f in mctx.subset if m(f)]
96
96
97 def andset(mctx, x, y):
97 def andset(mctx, x, y):
98 return getset(mctx.narrow(getset(mctx, x)), y)
98 return getset(mctx.narrow(getset(mctx, x)), y)
99
99
100 def orset(mctx, x, y):
100 def orset(mctx, x, y):
101 # needs optimizing
101 # needs optimizing
102 xl = getset(mctx, x)
102 xl = getset(mctx, x)
103 yl = getset(mctx, y)
103 yl = getset(mctx, y)
104 return xl + [f for f in yl if f not in xl]
104 return xl + [f for f in yl if f not in xl]
105
105
106 def notset(mctx, x):
106 def notset(mctx, x):
107 s = set(getset(mctx, x))
107 s = set(getset(mctx, x))
108 return [r for r in mctx.subset if r not in s]
108 return [r for r in mctx.subset if r not in s]
109
109
110 def listset(mctx, a, b):
110 def listset(mctx, a, b):
111 raise error.ParseError(_("can't use a list in this context"))
111 raise error.ParseError(_("can't use a list in this context"))
112
112
113 def modified(mctx, x):
113 def modified(mctx, x):
114 """``modified()``
114 """``modified()``
115 File that is modified according to status.
115 File that is modified according to status.
116 """
116 """
117 getargs(x, 0, 0, _("modified takes no arguments"))
117 getargs(x, 0, 0, _("modified takes no arguments"))
118 s = mctx.status()[0]
118 s = mctx.status()[0]
119 return [f for f in mctx.subset if f in s]
119 return [f for f in mctx.subset if f in s]
120
120
121 def added(mctx, x):
121 def added(mctx, x):
122 """``added()``
122 """``added()``
123 File that is added according to status.
123 File that is added according to status.
124 """
124 """
125 getargs(x, 0, 0, _("added takes no arguments"))
125 getargs(x, 0, 0, _("added takes no arguments"))
126 s = mctx.status()[1]
126 s = mctx.status()[1]
127 return [f for f in mctx.subset if f in s]
127 return [f for f in mctx.subset if f in s]
128
128
129 def removed(mctx, x):
129 def removed(mctx, x):
130 """``removed()``
130 """``removed()``
131 File that is removed according to status.
131 File that is removed according to status.
132 """
132 """
133 getargs(x, 0, 0, _("removed takes no arguments"))
133 getargs(x, 0, 0, _("removed takes no arguments"))
134 s = mctx.status()[2]
134 s = mctx.status()[2]
135 return [f for f in mctx.subset if f in s]
135 return [f for f in mctx.subset if f in s]
136
136
137 def deleted(mctx, x):
137 def deleted(mctx, x):
138 """``deleted()``
138 """``deleted()``
139 File that is deleted according to status.
139 File that is deleted according to status.
140 """
140 """
141 getargs(x, 0, 0, _("deleted takes no arguments"))
141 getargs(x, 0, 0, _("deleted takes no arguments"))
142 s = mctx.status()[3]
142 s = mctx.status()[3]
143 return [f for f in mctx.subset if f in s]
143 return [f for f in mctx.subset if f in s]
144
144
145 def unknown(mctx, x):
145 def unknown(mctx, x):
146 """``unknown()``
146 """``unknown()``
147 File that is unknown according to status. These files will only be
147 File that is unknown according to status. These files will only be
148 considered if this predicate is used.
148 considered if this predicate is used.
149 """
149 """
150 getargs(x, 0, 0, _("unknown takes no arguments"))
150 getargs(x, 0, 0, _("unknown takes no arguments"))
151 s = mctx.status()[4]
151 s = mctx.status()[4]
152 return [f for f in mctx.subset if f in s]
152 return [f for f in mctx.subset if f in s]
153
153
154 def ignored(mctx, x):
154 def ignored(mctx, x):
155 """``ignored()``
155 """``ignored()``
156 File that is ignored according to status. These files will only be
156 File that is ignored according to status. These files will only be
157 considered if this predicate is used.
157 considered if this predicate is used.
158 """
158 """
159 getargs(x, 0, 0, _("ignored takes no arguments"))
159 getargs(x, 0, 0, _("ignored takes no arguments"))
160 s = mctx.status()[5]
160 s = mctx.status()[5]
161 return [f for f in mctx.subset if f in s]
161 return [f for f in mctx.subset if f in s]
162
162
163 def clean(mctx, x):
163 def clean(mctx, x):
164 """``clean()``
164 """``clean()``
165 File that is clean according to status.
165 File that is clean according to status.
166 """
166 """
167 getargs(x, 0, 0, _("clean takes no arguments"))
167 getargs(x, 0, 0, _("clean takes no arguments"))
168 s = mctx.status()[6]
168 s = mctx.status()[6]
169 return [f for f in mctx.subset if f in s]
169 return [f for f in mctx.subset if f in s]
170
170
171 def func(mctx, a, b):
171 def func(mctx, a, b):
172 if a[0] == 'symbol' and a[1] in symbols:
172 if a[0] == 'symbol' and a[1] in symbols:
173 return symbols[a[1]](mctx, b)
173 return symbols[a[1]](mctx, b)
174 raise error.ParseError(_("not a function: %s") % a[1])
174 raise error.ParseError(_("not a function: %s") % a[1])
175
175
176 def getlist(x):
176 def getlist(x):
177 if not x:
177 if not x:
178 return []
178 return []
179 if x[0] == 'list':
179 if x[0] == 'list':
180 return getlist(x[1]) + [x[2]]
180 return getlist(x[1]) + [x[2]]
181 return [x]
181 return [x]
182
182
183 def getargs(x, min, max, err):
183 def getargs(x, min, max, err):
184 l = getlist(x)
184 l = getlist(x)
185 if len(l) < min or len(l) > max:
185 if len(l) < min or len(l) > max:
186 raise error.ParseError(err)
186 raise error.ParseError(err)
187 return l
187 return l
188
188
189 def binary(mctx, x):
189 def binary(mctx, x):
190 """``binary()``
190 """``binary()``
191 File that appears to be binary (contails NUL bytes).
191 File that appears to be binary (contails NUL bytes).
192 """
192 """
193 getargs(x, 0, 0, _("binary takes no arguments"))
193 getargs(x, 0, 0, _("binary takes no arguments"))
194 return [f for f in mctx.subset if util.binary(mctx.ctx[f].data())]
194 return [f for f in mctx.subset if util.binary(mctx.ctx[f].data())]
195
195
196 def exec_(mctx, x):
196 def exec_(mctx, x):
197 """``exec()``
197 """``exec()``
198 File that is marked as executable.
198 File that is marked as executable.
199 """
199 """
200 getargs(x, 0, 0, _("exec takes no arguments"))
200 getargs(x, 0, 0, _("exec takes no arguments"))
201 return [f for f in mctx.subset if mctx.ctx.flags(f) == 'x']
201 return [f for f in mctx.subset if mctx.ctx.flags(f) == 'x']
202
202
203 def symlink(mctx, x):
203 def symlink(mctx, x):
204 """``symlink()``
204 """``symlink()``
205 File that is marked as a symlink.
205 File that is marked as a symlink.
206 """
206 """
207 getargs(x, 0, 0, _("symlink takes no arguments"))
207 getargs(x, 0, 0, _("symlink takes no arguments"))
208 return [f for f in mctx.subset if mctx.ctx.flags(f) == 'l']
208 return [f for f in mctx.subset if mctx.ctx.flags(f) == 'l']
209
209
210 def resolved(mctx, x):
210 def resolved(mctx, x):
211 """``resolved()``
211 """``resolved()``
212 File that is marked resolved according to the resolve state.
212 File that is marked resolved according to the resolve state.
213 """
213 """
214 getargs(x, 0, 0, _("resolved takes no arguments"))
214 getargs(x, 0, 0, _("resolved takes no arguments"))
215 if mctx.ctx.rev() is not None:
215 if mctx.ctx.rev() is not None:
216 return []
216 return []
217 ms = merge.mergestate(mctx.ctx._repo)
217 ms = merge.mergestate(mctx.ctx._repo)
218 return [f for f in mctx.subset if f in ms and ms[f] == 'r']
218 return [f for f in mctx.subset if f in ms and ms[f] == 'r']
219
219
220 def unresolved(mctx, x):
220 def unresolved(mctx, x):
221 """``unresolved()``
221 """``unresolved()``
222 File that is marked unresolved according to the resolve state.
222 File that is marked unresolved according to the resolve state.
223 """
223 """
224 getargs(x, 0, 0, _("unresolved takes no arguments"))
224 getargs(x, 0, 0, _("unresolved takes no arguments"))
225 if mctx.ctx.rev() is not None:
225 if mctx.ctx.rev() is not None:
226 return []
226 return []
227 ms = merge.mergestate(mctx.ctx._repo)
227 ms = merge.mergestate(mctx.ctx._repo)
228 return [f for f in mctx.subset if f in ms and ms[f] == 'u']
228 return [f for f in mctx.subset if f in ms and ms[f] == 'u']
229
229
230 def hgignore(mctx, x):
230 def hgignore(mctx, x):
231 """``resolved()``
231 """``resolved()``
232 File that matches the active .hgignore pattern.
232 File that matches the active .hgignore pattern.
233 """
233 """
234 getargs(x, 0, 0, _("hgignore takes no arguments"))
234 getargs(x, 0, 0, _("hgignore takes no arguments"))
235 ignore = mctx.ctx._repo.dirstate._ignore
235 ignore = mctx.ctx._repo.dirstate._ignore
236 return [f for f in mctx.subset if ignore(f)]
236 return [f for f in mctx.subset if ignore(f)]
237
237
238 def grep(mctx, x):
238 def grep(mctx, x):
239 """``grep(regex)``
239 """``grep(regex)``
240 File contains the given regular expression.
240 File contains the given regular expression.
241 """
241 """
242 pat = getstring(x, _("grep requires a pattern"))
242 pat = getstring(x, _("grep requires a pattern"))
243 r = re.compile(pat)
243 r = re.compile(pat)
244 return [f for f in mctx.subset if r.search(mctx.ctx[f].data())]
244 return [f for f in mctx.subset if r.search(mctx.ctx[f].data())]
245
245
246 _units = dict(k=2**10, K=2**10, kB=2**10, KB=2**10,
246 _units = dict(k=2**10, K=2**10, kB=2**10, KB=2**10,
247 M=2**20, MB=2**20, G=2**30, GB=2**30,
247 M=2**20, MB=2**20, G=2**30, GB=2**30)
248 kiB=10**3, MiB=10**6, GiB=10**9)
249
248
250 def _sizetoint(s):
249 def _sizetoint(s):
251 try:
250 try:
252 s = s.strip()
251 s = s.strip()
253 for k, v in _units.items():
252 for k, v in _units.items():
254 if s.endswith(k):
253 if s.endswith(k):
255 return int(float(s[:-len(k)]) * v)
254 return int(float(s[:-len(k)]) * v)
256 return int(s)
255 return int(s)
257 except ValueError:
256 except ValueError:
258 raise
257 raise
259 raise error.ParseError(_("couldn't parse size"), s)
258 raise error.ParseError(_("couldn't parse size"), s)
260
259
261 def _sizetomax(s):
260 def _sizetomax(s):
262 try:
261 try:
263 s = s.strip()
262 s = s.strip()
264 for k, v in _units.items():
263 for k, v in _units.items():
265 if s.endswith(k):
264 if s.endswith(k):
266 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
265 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
267 n = s[:-len(k)]
266 n = s[:-len(k)]
268 inc = 1.0
267 inc = 1.0
269 if "." in n:
268 if "." in n:
270 inc /= 10 ** len(n.split(".")[1])
269 inc /= 10 ** len(n.split(".")[1])
271 return int((float(n) + inc) * v) - 1
270 return int((float(n) + inc) * v) - 1
272 # no extension, this is a precise value
271 # no extension, this is a precise value
273 return int(s)
272 return int(s)
274 except ValueError:
273 except ValueError:
275 raise
274 raise
276 raise error.ParseError(_("couldn't parse size"), s)
275 raise error.ParseError(_("couldn't parse size"), s)
277
276
278 def size(mctx, x):
277 def size(mctx, x):
279 """``size(expression)``
278 """``size(expression)``
280 File size matches the given expression. Examples:
279 File size matches the given expression. Examples:
281
280
282 - 1k (files from 1024 to 2047 bytes)
281 - 1k (files from 1024 to 2047 bytes)
283 - 1.0kiB (files from 1000 to 1100 bytes)
284 - < 20k (files less than 20480 bytes)
282 - < 20k (files less than 20480 bytes)
285 - >= .5MiB (files at least 500000 bytes)
283 - >= .5MB (files at least 524288 bytes)
286 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
284 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
287 """
285 """
288
286
289 expr = getstring(x, _("grep requires a pattern")).strip()
287 expr = getstring(x, _("grep requires a pattern")).strip()
290 if '-' in expr: # do we have a range?
288 if '-' in expr: # do we have a range?
291 a, b = expr.split('-', 1)
289 a, b = expr.split('-', 1)
292 a = _sizetoint(a)
290 a = _sizetoint(a)
293 b = _sizetoint(b)
291 b = _sizetoint(b)
294 m = lambda x: x >= a and x <= b
292 m = lambda x: x >= a and x <= b
295 elif expr.startswith("<="):
293 elif expr.startswith("<="):
296 a = _sizetoint(expr[2:])
294 a = _sizetoint(expr[2:])
297 m = lambda x: x <= a
295 m = lambda x: x <= a
298 elif expr.startswith("<"):
296 elif expr.startswith("<"):
299 a = _sizetoint(expr[1:])
297 a = _sizetoint(expr[1:])
300 m = lambda x: x < a
298 m = lambda x: x < a
301 elif expr.startswith(">="):
299 elif expr.startswith(">="):
302 a = _sizetoint(expr[2:])
300 a = _sizetoint(expr[2:])
303 m = lambda x: x >= a
301 m = lambda x: x >= a
304 elif expr.startswith(">"):
302 elif expr.startswith(">"):
305 a = _sizetoint(expr[1:])
303 a = _sizetoint(expr[1:])
306 m = lambda x: x > a
304 m = lambda x: x > a
307 elif expr[0].isdigit or expr[0] == '.':
305 elif expr[0].isdigit or expr[0] == '.':
308 a = _sizetoint(expr)
306 a = _sizetoint(expr)
309 b = _sizetomax(expr)
307 b = _sizetomax(expr)
310 m = lambda x: x >=a and x <= b
308 m = lambda x: x >=a and x <= b
311 else:
309 else:
312 raise error.ParseError(_("couldn't parse size"), expr)
310 raise error.ParseError(_("couldn't parse size"), expr)
313
311
314 return [f for f in mctx.subset if m(mctx.ctx[f].size())]
312 return [f for f in mctx.subset if m(mctx.ctx[f].size())]
315
313
316 def encoding(mctx, x):
314 def encoding(mctx, x):
317 """``encoding(name)``
315 """``encoding(name)``
318 File can be successfully decoded with the given character
316 File can be successfully decoded with the given character
319 encoding. May not be useful for encodings other than ASCII and
317 encoding. May not be useful for encodings other than ASCII and
320 UTF-8.
318 UTF-8.
321 """
319 """
322
320
323 enc = getstring(x, _("encoding requires an encoding name"))
321 enc = getstring(x, _("encoding requires an encoding name"))
324
322
325 s = []
323 s = []
326 for f in mctx.subset:
324 for f in mctx.subset:
327 d = mctx.ctx[f].data()
325 d = mctx.ctx[f].data()
328 try:
326 try:
329 d.decode(enc)
327 d.decode(enc)
330 except LookupError:
328 except LookupError:
331 raise util.Abort(_("unknown encoding '%s'") % enc)
329 raise util.Abort(_("unknown encoding '%s'") % enc)
332 except UnicodeDecodeError:
330 except UnicodeDecodeError:
333 continue
331 continue
334 s.append(f)
332 s.append(f)
335
333
336 return s
334 return s
337
335
338 def copied(mctx, x):
336 def copied(mctx, x):
339 """``copied()``
337 """``copied()``
340 File that is recorded as being copied.
338 File that is recorded as being copied.
341 """
339 """
342 s = []
340 s = []
343 for f in mctx.subset:
341 for f in mctx.subset:
344 p = mctx.ctx[f].parents()
342 p = mctx.ctx[f].parents()
345 if p and p[0].path() != f:
343 if p and p[0].path() != f:
346 s.append(f)
344 s.append(f)
347 return s
345 return s
348
346
349 symbols = {
347 symbols = {
350 'added': added,
348 'added': added,
351 'binary': binary,
349 'binary': binary,
352 'clean': clean,
350 'clean': clean,
353 'copied': copied,
351 'copied': copied,
354 'deleted': deleted,
352 'deleted': deleted,
355 'encoding': encoding,
353 'encoding': encoding,
356 'exec': exec_,
354 'exec': exec_,
357 'grep': grep,
355 'grep': grep,
358 'ignored': ignored,
356 'ignored': ignored,
359 'hgignore': hgignore,
357 'hgignore': hgignore,
360 'modified': modified,
358 'modified': modified,
361 'removed': removed,
359 'removed': removed,
362 'resolved': resolved,
360 'resolved': resolved,
363 'size': size,
361 'size': size,
364 'symlink': symlink,
362 'symlink': symlink,
365 'unknown': unknown,
363 'unknown': unknown,
366 'unresolved': unresolved,
364 'unresolved': unresolved,
367 }
365 }
368
366
369 methods = {
367 methods = {
370 'string': stringset,
368 'string': stringset,
371 'symbol': stringset,
369 'symbol': stringset,
372 'and': andset,
370 'and': andset,
373 'or': orset,
371 'or': orset,
374 'list': listset,
372 'list': listset,
375 'group': getset,
373 'group': getset,
376 'not': notset,
374 'not': notset,
377 'func': func,
375 'func': func,
378 }
376 }
379
377
380 class matchctx(object):
378 class matchctx(object):
381 def __init__(self, ctx, subset=None, status=None):
379 def __init__(self, ctx, subset=None, status=None):
382 self.ctx = ctx
380 self.ctx = ctx
383 self.subset = subset
381 self.subset = subset
384 self._status = status
382 self._status = status
385 def status(self):
383 def status(self):
386 return self._status
384 return self._status
387 def matcher(self, patterns):
385 def matcher(self, patterns):
388 return self.ctx.match(patterns)
386 return self.ctx.match(patterns)
389 def filter(self, files):
387 def filter(self, files):
390 return [f for f in files if f in self.subset]
388 return [f for f in files if f in self.subset]
391 def narrow(self, files):
389 def narrow(self, files):
392 return matchctx(self.ctx, self.filter(files), self._status)
390 return matchctx(self.ctx, self.filter(files), self._status)
393
391
394 def _intree(funcs, tree):
392 def _intree(funcs, tree):
395 if isinstance(tree, tuple):
393 if isinstance(tree, tuple):
396 if tree[0] == 'func' and tree[1][0] == 'symbol':
394 if tree[0] == 'func' and tree[1][0] == 'symbol':
397 if tree[1][1] in funcs:
395 if tree[1][1] in funcs:
398 return True
396 return True
399 for s in tree[1:]:
397 for s in tree[1:]:
400 if _intree(funcs, s):
398 if _intree(funcs, s):
401 return True
399 return True
402 return False
400 return False
403
401
404 def getfileset(ctx, expr):
402 def getfileset(ctx, expr):
405 tree, pos = parse(expr)
403 tree, pos = parse(expr)
406 if (pos != len(expr)):
404 if (pos != len(expr)):
407 raise error.ParseError("invalid token", pos)
405 raise error.ParseError("invalid token", pos)
408
406
409 # do we need status info?
407 # do we need status info?
410 if _intree(['modified', 'added', 'removed', 'deleted',
408 if _intree(['modified', 'added', 'removed', 'deleted',
411 'unknown', 'ignored', 'clean'], tree):
409 'unknown', 'ignored', 'clean'], tree):
412 unknown = _intree(['unknown'], tree)
410 unknown = _intree(['unknown'], tree)
413 ignored = _intree(['ignored'], tree)
411 ignored = _intree(['ignored'], tree)
414
412
415 r = ctx._repo
413 r = ctx._repo
416 status = r.status(ctx.p1(), ctx,
414 status = r.status(ctx.p1(), ctx,
417 unknown=unknown, ignored=ignored, clean=True)
415 unknown=unknown, ignored=ignored, clean=True)
418 subset = []
416 subset = []
419 for c in status:
417 for c in status:
420 subset.extend(c)
418 subset.extend(c)
421 else:
419 else:
422 status = None
420 status = None
423 subset = ctx.walk(ctx.match([]))
421 subset = ctx.walk(ctx.match([]))
424
422
425 return getset(matchctx(ctx, subset, status), tree)
423 return getset(matchctx(ctx, subset, status), tree)
426
424
427 # tell hggettext to extract docstrings from these functions:
425 # tell hggettext to extract docstrings from these functions:
428 i18nfunctions = symbols.values()
426 i18nfunctions = symbols.values()
General Comments 0
You need to be logged in to leave comments. Login now