##// END OF EJS Templates
fileset: copied takes no arguments
Mads Kiilerich -
r14718:0c819486 stable
parent child Browse files
Show More
@@ -1,424 +1,425 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 """``hgignore()``
231 """``hgignore()``
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
248
249 def _sizetoint(s):
249 def _sizetoint(s):
250 try:
250 try:
251 s = s.strip()
251 s = s.strip()
252 for k, v in _units.items():
252 for k, v in _units.items():
253 if s.endswith(k):
253 if s.endswith(k):
254 return int(float(s[:-len(k)]) * v)
254 return int(float(s[:-len(k)]) * v)
255 return int(s)
255 return int(s)
256 except ValueError:
256 except ValueError:
257 raise error.ParseError(_("couldn't parse size: %s") % s)
257 raise error.ParseError(_("couldn't parse size: %s") % s)
258
258
259 def _sizetomax(s):
259 def _sizetomax(s):
260 try:
260 try:
261 s = s.strip()
261 s = s.strip()
262 for k, v in _units.items():
262 for k, v in _units.items():
263 if s.endswith(k):
263 if s.endswith(k):
264 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
264 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
265 n = s[:-len(k)]
265 n = s[:-len(k)]
266 inc = 1.0
266 inc = 1.0
267 if "." in n:
267 if "." in n:
268 inc /= 10 ** len(n.split(".")[1])
268 inc /= 10 ** len(n.split(".")[1])
269 return int((float(n) + inc) * v) - 1
269 return int((float(n) + inc) * v) - 1
270 # no extension, this is a precise value
270 # no extension, this is a precise value
271 return int(s)
271 return int(s)
272 except ValueError:
272 except ValueError:
273 raise error.ParseError(_("couldn't parse size: %s") % s)
273 raise error.ParseError(_("couldn't parse size: %s") % s)
274
274
275 def size(mctx, x):
275 def size(mctx, x):
276 """``size(expression)``
276 """``size(expression)``
277 File size matches the given expression. Examples:
277 File size matches the given expression. Examples:
278
278
279 - 1k (files from 1024 to 2047 bytes)
279 - 1k (files from 1024 to 2047 bytes)
280 - < 20k (files less than 20480 bytes)
280 - < 20k (files less than 20480 bytes)
281 - >= .5MB (files at least 524288 bytes)
281 - >= .5MB (files at least 524288 bytes)
282 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
282 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
283 """
283 """
284
284
285 expr = getstring(x, _("size requires an expression")).strip()
285 expr = getstring(x, _("size requires an expression")).strip()
286 if '-' in expr: # do we have a range?
286 if '-' in expr: # do we have a range?
287 a, b = expr.split('-', 1)
287 a, b = expr.split('-', 1)
288 a = _sizetoint(a)
288 a = _sizetoint(a)
289 b = _sizetoint(b)
289 b = _sizetoint(b)
290 m = lambda x: x >= a and x <= b
290 m = lambda x: x >= a and x <= b
291 elif expr.startswith("<="):
291 elif expr.startswith("<="):
292 a = _sizetoint(expr[2:])
292 a = _sizetoint(expr[2:])
293 m = lambda x: x <= a
293 m = lambda x: x <= a
294 elif expr.startswith("<"):
294 elif expr.startswith("<"):
295 a = _sizetoint(expr[1:])
295 a = _sizetoint(expr[1:])
296 m = lambda x: x < a
296 m = lambda x: x < a
297 elif expr.startswith(">="):
297 elif expr.startswith(">="):
298 a = _sizetoint(expr[2:])
298 a = _sizetoint(expr[2:])
299 m = lambda x: x >= a
299 m = lambda x: x >= a
300 elif expr.startswith(">"):
300 elif expr.startswith(">"):
301 a = _sizetoint(expr[1:])
301 a = _sizetoint(expr[1:])
302 m = lambda x: x > a
302 m = lambda x: x > a
303 elif expr[0].isdigit or expr[0] == '.':
303 elif expr[0].isdigit or expr[0] == '.':
304 a = _sizetoint(expr)
304 a = _sizetoint(expr)
305 b = _sizetomax(expr)
305 b = _sizetomax(expr)
306 m = lambda x: x >= a and x <= b
306 m = lambda x: x >= a and x <= b
307 else:
307 else:
308 raise error.ParseError(_("couldn't parse size: %s") % expr)
308 raise error.ParseError(_("couldn't parse size: %s") % expr)
309
309
310 return [f for f in mctx.subset if m(mctx.ctx[f].size())]
310 return [f for f in mctx.subset if m(mctx.ctx[f].size())]
311
311
312 def encoding(mctx, x):
312 def encoding(mctx, x):
313 """``encoding(name)``
313 """``encoding(name)``
314 File can be successfully decoded with the given character
314 File can be successfully decoded with the given character
315 encoding. May not be useful for encodings other than ASCII and
315 encoding. May not be useful for encodings other than ASCII and
316 UTF-8.
316 UTF-8.
317 """
317 """
318
318
319 enc = getstring(x, _("encoding requires an encoding name"))
319 enc = getstring(x, _("encoding requires an encoding name"))
320
320
321 s = []
321 s = []
322 for f in mctx.subset:
322 for f in mctx.subset:
323 d = mctx.ctx[f].data()
323 d = mctx.ctx[f].data()
324 try:
324 try:
325 d.decode(enc)
325 d.decode(enc)
326 except LookupError:
326 except LookupError:
327 raise util.Abort(_("unknown encoding '%s'") % enc)
327 raise util.Abort(_("unknown encoding '%s'") % enc)
328 except UnicodeDecodeError:
328 except UnicodeDecodeError:
329 continue
329 continue
330 s.append(f)
330 s.append(f)
331
331
332 return s
332 return s
333
333
334 def copied(mctx, x):
334 def copied(mctx, x):
335 """``copied()``
335 """``copied()``
336 File that is recorded as being copied.
336 File that is recorded as being copied.
337 """
337 """
338 getargs(x, 0, 0, _("copied takes no arguments"))
338 s = []
339 s = []
339 for f in mctx.subset:
340 for f in mctx.subset:
340 p = mctx.ctx[f].parents()
341 p = mctx.ctx[f].parents()
341 if p and p[0].path() != f:
342 if p and p[0].path() != f:
342 s.append(f)
343 s.append(f)
343 return s
344 return s
344
345
345 symbols = {
346 symbols = {
346 'added': added,
347 'added': added,
347 'binary': binary,
348 'binary': binary,
348 'clean': clean,
349 'clean': clean,
349 'copied': copied,
350 'copied': copied,
350 'deleted': deleted,
351 'deleted': deleted,
351 'encoding': encoding,
352 'encoding': encoding,
352 'exec': exec_,
353 'exec': exec_,
353 'grep': grep,
354 'grep': grep,
354 'ignored': ignored,
355 'ignored': ignored,
355 'hgignore': hgignore,
356 'hgignore': hgignore,
356 'modified': modified,
357 'modified': modified,
357 'removed': removed,
358 'removed': removed,
358 'resolved': resolved,
359 'resolved': resolved,
359 'size': size,
360 'size': size,
360 'symlink': symlink,
361 'symlink': symlink,
361 'unknown': unknown,
362 'unknown': unknown,
362 'unresolved': unresolved,
363 'unresolved': unresolved,
363 }
364 }
364
365
365 methods = {
366 methods = {
366 'string': stringset,
367 'string': stringset,
367 'symbol': stringset,
368 'symbol': stringset,
368 'and': andset,
369 'and': andset,
369 'or': orset,
370 'or': orset,
370 'list': listset,
371 'list': listset,
371 'group': getset,
372 'group': getset,
372 'not': notset,
373 'not': notset,
373 'func': func,
374 'func': func,
374 }
375 }
375
376
376 class matchctx(object):
377 class matchctx(object):
377 def __init__(self, ctx, subset=None, status=None):
378 def __init__(self, ctx, subset=None, status=None):
378 self.ctx = ctx
379 self.ctx = ctx
379 self.subset = subset
380 self.subset = subset
380 self._status = status
381 self._status = status
381 def status(self):
382 def status(self):
382 return self._status
383 return self._status
383 def matcher(self, patterns):
384 def matcher(self, patterns):
384 return self.ctx.match(patterns)
385 return self.ctx.match(patterns)
385 def filter(self, files):
386 def filter(self, files):
386 return [f for f in files if f in self.subset]
387 return [f for f in files if f in self.subset]
387 def narrow(self, files):
388 def narrow(self, files):
388 return matchctx(self.ctx, self.filter(files), self._status)
389 return matchctx(self.ctx, self.filter(files), self._status)
389
390
390 def _intree(funcs, tree):
391 def _intree(funcs, tree):
391 if isinstance(tree, tuple):
392 if isinstance(tree, tuple):
392 if tree[0] == 'func' and tree[1][0] == 'symbol':
393 if tree[0] == 'func' and tree[1][0] == 'symbol':
393 if tree[1][1] in funcs:
394 if tree[1][1] in funcs:
394 return True
395 return True
395 for s in tree[1:]:
396 for s in tree[1:]:
396 if _intree(funcs, s):
397 if _intree(funcs, s):
397 return True
398 return True
398 return False
399 return False
399
400
400 def getfileset(ctx, expr):
401 def getfileset(ctx, expr):
401 tree, pos = parse(expr)
402 tree, pos = parse(expr)
402 if (pos != len(expr)):
403 if (pos != len(expr)):
403 raise error.ParseError(_("invalid token"), pos)
404 raise error.ParseError(_("invalid token"), pos)
404
405
405 # do we need status info?
406 # do we need status info?
406 if _intree(['modified', 'added', 'removed', 'deleted',
407 if _intree(['modified', 'added', 'removed', 'deleted',
407 'unknown', 'ignored', 'clean'], tree):
408 'unknown', 'ignored', 'clean'], tree):
408 unknown = _intree(['unknown'], tree)
409 unknown = _intree(['unknown'], tree)
409 ignored = _intree(['ignored'], tree)
410 ignored = _intree(['ignored'], tree)
410
411
411 r = ctx._repo
412 r = ctx._repo
412 status = r.status(ctx.p1(), ctx,
413 status = r.status(ctx.p1(), ctx,
413 unknown=unknown, ignored=ignored, clean=True)
414 unknown=unknown, ignored=ignored, clean=True)
414 subset = []
415 subset = []
415 for c in status:
416 for c in status:
416 subset.extend(c)
417 subset.extend(c)
417 else:
418 else:
418 status = None
419 status = None
419 subset = ctx.walk(ctx.match([]))
420 subset = ctx.walk(ctx.match([]))
420
421
421 return getset(matchctx(ctx, subset, status), tree)
422 return getset(matchctx(ctx, subset, status), tree)
422
423
423 # tell hggettext to extract docstrings from these functions:
424 # tell hggettext to extract docstrings from these functions:
424 i18nfunctions = symbols.values()
425 i18nfunctions = symbols.values()
General Comments 0
You need to be logged in to leave comments. Login now