##// END OF EJS Templates
revset: add translator comments to i18n strings
Martin Geisler -
r12815:079a618e stable
parent child Browse files
Show More
@@ -1,626 +1,655 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision 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 re
8 import re
9 import parser, util, error, discovery
9 import parser, util, error, discovery
10 import match as matchmod
10 import match as matchmod
11 from i18n import _
11 from i18n import _
12
12
13 elements = {
13 elements = {
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "-": (5, ("negate", 19), ("minus", 5)),
15 "-": (5, ("negate", 19), ("minus", 5)),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
17 ("dagrangepost", 17)),
17 ("dagrangepost", 17)),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
19 ("dagrangepost", 17)),
19 ("dagrangepost", 17)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
21 "not": (10, ("not", 10)),
21 "not": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
23 "and": (5, None, ("and", 5)),
23 "and": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
25 "or": (4, None, ("or", 4)),
25 "or": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
28 ",": (2, None, ("list", 2)),
28 ",": (2, None, ("list", 2)),
29 ")": (0, None, None),
29 ")": (0, None, None),
30 "symbol": (0, ("symbol",), None),
30 "symbol": (0, ("symbol",), None),
31 "string": (0, ("string",), None),
31 "string": (0, ("string",), None),
32 "end": (0, None, None),
32 "end": (0, None, None),
33 }
33 }
34
34
35 keywords = set(['and', 'or', 'not'])
35 keywords = set(['and', 'or', 'not'])
36
36
37 def tokenize(program):
37 def tokenize(program):
38 pos, l = 0, len(program)
38 pos, l = 0, len(program)
39 while pos < l:
39 while pos < l:
40 c = program[pos]
40 c = program[pos]
41 if c.isspace(): # skip inter-token whitespace
41 if c.isspace(): # skip inter-token whitespace
42 pass
42 pass
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
44 yield ('::', None, pos)
44 yield ('::', None, pos)
45 pos += 1 # skip ahead
45 pos += 1 # skip ahead
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
47 yield ('..', None, pos)
47 yield ('..', None, pos)
48 pos += 1 # skip ahead
48 pos += 1 # skip ahead
49 elif c in "():,-|&+!": # handle simple operators
49 elif c in "():,-|&+!": # handle simple operators
50 yield (c, None, pos)
50 yield (c, None, pos)
51 elif (c in '"\'' or c == 'r' and
51 elif (c in '"\'' or c == 'r' and
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 if c == 'r':
53 if c == 'r':
54 pos += 1
54 pos += 1
55 c = program[pos]
55 c = program[pos]
56 decode = lambda x: x
56 decode = lambda x: x
57 else:
57 else:
58 decode = lambda x: x.decode('string-escape')
58 decode = lambda x: x.decode('string-escape')
59 pos += 1
59 pos += 1
60 s = pos
60 s = pos
61 while pos < l: # find closing quote
61 while pos < l: # find closing quote
62 d = program[pos]
62 d = program[pos]
63 if d == '\\': # skip over escaped characters
63 if d == '\\': # skip over escaped characters
64 pos += 2
64 pos += 2
65 continue
65 continue
66 if d == c:
66 if d == c:
67 yield ('string', decode(program[s:pos]), s)
67 yield ('string', decode(program[s:pos]), s)
68 break
68 break
69 pos += 1
69 pos += 1
70 else:
70 else:
71 raise error.ParseError(_("unterminated string"), s)
71 raise error.ParseError(_("unterminated string"), s)
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
73 s = pos
73 s = pos
74 pos += 1
74 pos += 1
75 while pos < l: # find end of symbol
75 while pos < l: # find end of symbol
76 d = program[pos]
76 d = program[pos]
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
78 break
78 break
79 if d == '.' and program[pos - 1] == '.': # special case for ..
79 if d == '.' and program[pos - 1] == '.': # special case for ..
80 pos -= 1
80 pos -= 1
81 break
81 break
82 pos += 1
82 pos += 1
83 sym = program[s:pos]
83 sym = program[s:pos]
84 if sym in keywords: # operator keywords
84 if sym in keywords: # operator keywords
85 yield (sym, None, s)
85 yield (sym, None, s)
86 else:
86 else:
87 yield ('symbol', sym, s)
87 yield ('symbol', sym, s)
88 pos -= 1
88 pos -= 1
89 else:
89 else:
90 raise error.ParseError(_("syntax error"), pos)
90 raise error.ParseError(_("syntax error"), pos)
91 pos += 1
91 pos += 1
92 yield ('end', None, pos)
92 yield ('end', None, pos)
93
93
94 # helpers
94 # helpers
95
95
96 def getstring(x, err):
96 def getstring(x, err):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
98 return x[1]
98 return x[1]
99 raise error.ParseError(err)
99 raise error.ParseError(err)
100
100
101 def getlist(x):
101 def getlist(x):
102 if not x:
102 if not x:
103 return []
103 return []
104 if x[0] == 'list':
104 if x[0] == 'list':
105 return getlist(x[1]) + [x[2]]
105 return getlist(x[1]) + [x[2]]
106 return [x]
106 return [x]
107
107
108 def getargs(x, min, max, err):
108 def getargs(x, min, max, err):
109 l = getlist(x)
109 l = getlist(x)
110 if len(l) < min or len(l) > max:
110 if len(l) < min or len(l) > max:
111 raise error.ParseError(err)
111 raise error.ParseError(err)
112 return l
112 return l
113
113
114 def getset(repo, subset, x):
114 def getset(repo, subset, x):
115 if not x:
115 if not x:
116 raise error.ParseError(_("missing argument"))
116 raise error.ParseError(_("missing argument"))
117 return methods[x[0]](repo, subset, *x[1:])
117 return methods[x[0]](repo, subset, *x[1:])
118
118
119 # operator methods
119 # operator methods
120
120
121 def stringset(repo, subset, x):
121 def stringset(repo, subset, x):
122 x = repo[x].rev()
122 x = repo[x].rev()
123 if x == -1 and len(subset) == len(repo):
123 if x == -1 and len(subset) == len(repo):
124 return [-1]
124 return [-1]
125 if x in subset:
125 if x in subset:
126 return [x]
126 return [x]
127 return []
127 return []
128
128
129 def symbolset(repo, subset, x):
129 def symbolset(repo, subset, x):
130 if x in symbols:
130 if x in symbols:
131 raise error.ParseError(_("can't use %s here") % x)
131 raise error.ParseError(_("can't use %s here") % x)
132 return stringset(repo, subset, x)
132 return stringset(repo, subset, x)
133
133
134 def rangeset(repo, subset, x, y):
134 def rangeset(repo, subset, x, y):
135 m = getset(repo, subset, x)
135 m = getset(repo, subset, x)
136 if not m:
136 if not m:
137 m = getset(repo, range(len(repo)), x)
137 m = getset(repo, range(len(repo)), x)
138
138
139 n = getset(repo, subset, y)
139 n = getset(repo, subset, y)
140 if not n:
140 if not n:
141 n = getset(repo, range(len(repo)), y)
141 n = getset(repo, range(len(repo)), y)
142
142
143 if not m or not n:
143 if not m or not n:
144 return []
144 return []
145 m, n = m[0], n[-1]
145 m, n = m[0], n[-1]
146
146
147 if m < n:
147 if m < n:
148 r = range(m, n + 1)
148 r = range(m, n + 1)
149 else:
149 else:
150 r = range(m, n - 1, -1)
150 r = range(m, n - 1, -1)
151 s = set(subset)
151 s = set(subset)
152 return [x for x in r if x in s]
152 return [x for x in r if x in s]
153
153
154 def andset(repo, subset, x, y):
154 def andset(repo, subset, x, y):
155 return getset(repo, getset(repo, subset, x), y)
155 return getset(repo, getset(repo, subset, x), y)
156
156
157 def orset(repo, subset, x, y):
157 def orset(repo, subset, x, y):
158 s = set(getset(repo, subset, x))
158 s = set(getset(repo, subset, x))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
160 return [r for r in subset if r in s]
160 return [r for r in subset if r in s]
161
161
162 def notset(repo, subset, x):
162 def notset(repo, subset, x):
163 s = set(getset(repo, subset, x))
163 s = set(getset(repo, subset, x))
164 return [r for r in subset if r not in s]
164 return [r for r in subset if r not in s]
165
165
166 def listset(repo, subset, a, b):
166 def listset(repo, subset, a, b):
167 raise error.ParseError(_("can't use a list in this context"))
167 raise error.ParseError(_("can't use a list in this context"))
168
168
169 def func(repo, subset, a, b):
169 def func(repo, subset, a, b):
170 if a[0] == 'symbol' and a[1] in symbols:
170 if a[0] == 'symbol' and a[1] in symbols:
171 return symbols[a[1]](repo, subset, b)
171 return symbols[a[1]](repo, subset, b)
172 raise error.ParseError(_("not a function: %s") % a[1])
172 raise error.ParseError(_("not a function: %s") % a[1])
173
173
174 # functions
174 # functions
175
175
176 def node(repo, subset, x):
176 def node(repo, subset, x):
177 # i18n: "id" is a keyword
177 l = getargs(x, 1, 1, _("id requires one argument"))
178 l = getargs(x, 1, 1, _("id requires one argument"))
179 # i18n: "id" is a keyword
178 n = getstring(l[0], _("id requires a string"))
180 n = getstring(l[0], _("id requires a string"))
179 if len(n) == 40:
181 if len(n) == 40:
180 rn = repo[n].rev()
182 rn = repo[n].rev()
181 else:
183 else:
182 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
184 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
183 return [r for r in subset if r == rn]
185 return [r for r in subset if r == rn]
184
186
185 def rev(repo, subset, x):
187 def rev(repo, subset, x):
188 # i18n: "rev" is a keyword
186 l = getargs(x, 1, 1, _("rev requires one argument"))
189 l = getargs(x, 1, 1, _("rev requires one argument"))
187 try:
190 try:
191 # i18n: "rev" is a keyword
188 l = int(getstring(l[0], _("rev requires a number")))
192 l = int(getstring(l[0], _("rev requires a number")))
189 except ValueError:
193 except ValueError:
194 # i18n: "rev" is a keyword
190 raise error.ParseError(_("rev expects a number"))
195 raise error.ParseError(_("rev expects a number"))
191 return [r for r in subset if r == l]
196 return [r for r in subset if r == l]
192
197
193 def p1(repo, subset, x):
198 def p1(repo, subset, x):
194 ps = set()
199 ps = set()
195 cl = repo.changelog
200 cl = repo.changelog
196 for r in getset(repo, range(len(repo)), x):
201 for r in getset(repo, range(len(repo)), x):
197 ps.add(cl.parentrevs(r)[0])
202 ps.add(cl.parentrevs(r)[0])
198 return [r for r in subset if r in ps]
203 return [r for r in subset if r in ps]
199
204
200 def p2(repo, subset, x):
205 def p2(repo, subset, x):
201 ps = set()
206 ps = set()
202 cl = repo.changelog
207 cl = repo.changelog
203 for r in getset(repo, range(len(repo)), x):
208 for r in getset(repo, range(len(repo)), x):
204 ps.add(cl.parentrevs(r)[1])
209 ps.add(cl.parentrevs(r)[1])
205 return [r for r in subset if r in ps]
210 return [r for r in subset if r in ps]
206
211
207 def parents(repo, subset, x):
212 def parents(repo, subset, x):
208 ps = set()
213 ps = set()
209 cl = repo.changelog
214 cl = repo.changelog
210 for r in getset(repo, range(len(repo)), x):
215 for r in getset(repo, range(len(repo)), x):
211 ps.update(cl.parentrevs(r))
216 ps.update(cl.parentrevs(r))
212 return [r for r in subset if r in ps]
217 return [r for r in subset if r in ps]
213
218
214 def maxrev(repo, subset, x):
219 def maxrev(repo, subset, x):
215 s = getset(repo, subset, x)
220 s = getset(repo, subset, x)
216 if s:
221 if s:
217 m = max(s)
222 m = max(s)
218 if m in subset:
223 if m in subset:
219 return [m]
224 return [m]
220 return []
225 return []
221
226
222 def minrev(repo, subset, x):
227 def minrev(repo, subset, x):
223 s = getset(repo, subset, x)
228 s = getset(repo, subset, x)
224 if s:
229 if s:
225 m = min(s)
230 m = min(s)
226 if m in subset:
231 if m in subset:
227 return [m]
232 return [m]
228 return []
233 return []
229
234
230 def limit(repo, subset, x):
235 def limit(repo, subset, x):
236 # i18n: "limit" is a keyword
231 l = getargs(x, 2, 2, _("limit requires two arguments"))
237 l = getargs(x, 2, 2, _("limit requires two arguments"))
232 try:
238 try:
239 # i18n: "limit" is a keyword
233 lim = int(getstring(l[1], _("limit requires a number")))
240 lim = int(getstring(l[1], _("limit requires a number")))
234 except ValueError:
241 except ValueError:
242 # i18n: "limit" is a keyword
235 raise error.ParseError(_("limit expects a number"))
243 raise error.ParseError(_("limit expects a number"))
236 return getset(repo, subset, l[0])[:lim]
244 return getset(repo, subset, l[0])[:lim]
237
245
238 def children(repo, subset, x):
246 def children(repo, subset, x):
239 cs = set()
247 cs = set()
240 cl = repo.changelog
248 cl = repo.changelog
241 s = set(getset(repo, range(len(repo)), x))
249 s = set(getset(repo, range(len(repo)), x))
242 for r in xrange(0, len(repo)):
250 for r in xrange(0, len(repo)):
243 for p in cl.parentrevs(r):
251 for p in cl.parentrevs(r):
244 if p in s:
252 if p in s:
245 cs.add(r)
253 cs.add(r)
246 return [r for r in subset if r in cs]
254 return [r for r in subset if r in cs]
247
255
248 def branch(repo, subset, x):
256 def branch(repo, subset, x):
249 s = getset(repo, range(len(repo)), x)
257 s = getset(repo, range(len(repo)), x)
250 b = set()
258 b = set()
251 for r in s:
259 for r in s:
252 b.add(repo[r].branch())
260 b.add(repo[r].branch())
253 s = set(s)
261 s = set(s)
254 return [r for r in subset if r in s or repo[r].branch() in b]
262 return [r for r in subset if r in s or repo[r].branch() in b]
255
263
256 def ancestor(repo, subset, x):
264 def ancestor(repo, subset, x):
265 # i18n: "ancestor" is a keyword
257 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
266 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
258 r = range(len(repo))
267 r = range(len(repo))
259 a = getset(repo, r, l[0])
268 a = getset(repo, r, l[0])
260 b = getset(repo, r, l[1])
269 b = getset(repo, r, l[1])
261 if len(a) != 1 or len(b) != 1:
270 if len(a) != 1 or len(b) != 1:
271 # i18n: "ancestor" is a keyword
262 raise error.ParseError(_("ancestor arguments must be single revisions"))
272 raise error.ParseError(_("ancestor arguments must be single revisions"))
263 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
273 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
264
274
265 return [r for r in an if r in subset]
275 return [r for r in an if r in subset]
266
276
267 def ancestors(repo, subset, x):
277 def ancestors(repo, subset, x):
268 args = getset(repo, range(len(repo)), x)
278 args = getset(repo, range(len(repo)), x)
269 if not args:
279 if not args:
270 return []
280 return []
271 s = set(repo.changelog.ancestors(*args)) | set(args)
281 s = set(repo.changelog.ancestors(*args)) | set(args)
272 return [r for r in subset if r in s]
282 return [r for r in subset if r in s]
273
283
274 def descendants(repo, subset, x):
284 def descendants(repo, subset, x):
275 args = getset(repo, range(len(repo)), x)
285 args = getset(repo, range(len(repo)), x)
276 if not args:
286 if not args:
277 return []
287 return []
278 s = set(repo.changelog.descendants(*args)) | set(args)
288 s = set(repo.changelog.descendants(*args)) | set(args)
279 return [r for r in subset if r in s]
289 return [r for r in subset if r in s]
280
290
281 def follow(repo, subset, x):
291 def follow(repo, subset, x):
292 # i18n: "follow" is a keyword
282 getargs(x, 0, 0, _("follow takes no arguments"))
293 getargs(x, 0, 0, _("follow takes no arguments"))
283 p = repo['.'].rev()
294 p = repo['.'].rev()
284 s = set(repo.changelog.ancestors(p)) | set([p])
295 s = set(repo.changelog.ancestors(p)) | set([p])
285 return [r for r in subset if r in s]
296 return [r for r in subset if r in s]
286
297
287 def date(repo, subset, x):
298 def date(repo, subset, x):
299 # i18n: "date" is a keyword
288 ds = getstring(x, _("date requires a string"))
300 ds = getstring(x, _("date requires a string"))
289 dm = util.matchdate(ds)
301 dm = util.matchdate(ds)
290 return [r for r in subset if dm(repo[r].date()[0])]
302 return [r for r in subset if dm(repo[r].date()[0])]
291
303
292 def keyword(repo, subset, x):
304 def keyword(repo, subset, x):
305 # i18n: "keyword" is a keyword
293 kw = getstring(x, _("keyword requires a string")).lower()
306 kw = getstring(x, _("keyword requires a string")).lower()
294 l = []
307 l = []
295 for r in subset:
308 for r in subset:
296 c = repo[r]
309 c = repo[r]
297 t = " ".join(c.files() + [c.user(), c.description()])
310 t = " ".join(c.files() + [c.user(), c.description()])
298 if kw in t.lower():
311 if kw in t.lower():
299 l.append(r)
312 l.append(r)
300 return l
313 return l
301
314
302 def grep(repo, subset, x):
315 def grep(repo, subset, x):
303 try:
316 try:
317 # i18n: "grep" is a keyword
304 gr = re.compile(getstring(x, _("grep requires a string")))
318 gr = re.compile(getstring(x, _("grep requires a string")))
305 except re.error, e:
319 except re.error, e:
306 raise error.ParseError(_('invalid match pattern: %s') % e)
320 raise error.ParseError(_('invalid match pattern: %s') % e)
307 l = []
321 l = []
308 for r in subset:
322 for r in subset:
309 c = repo[r]
323 c = repo[r]
310 for e in c.files() + [c.user(), c.description()]:
324 for e in c.files() + [c.user(), c.description()]:
311 if gr.search(e):
325 if gr.search(e):
312 l.append(r)
326 l.append(r)
313 continue
327 continue
314 return l
328 return l
315
329
316 def author(repo, subset, x):
330 def author(repo, subset, x):
331 # i18n: "author" is a keyword
317 n = getstring(x, _("author requires a string")).lower()
332 n = getstring(x, _("author requires a string")).lower()
318 return [r for r in subset if n in repo[r].user().lower()]
333 return [r for r in subset if n in repo[r].user().lower()]
319
334
320 def hasfile(repo, subset, x):
335 def hasfile(repo, subset, x):
336 # i18n: "file" is a keyword
321 pat = getstring(x, _("file requires a pattern"))
337 pat = getstring(x, _("file requires a pattern"))
322 m = matchmod.match(repo.root, repo.getcwd(), [pat])
338 m = matchmod.match(repo.root, repo.getcwd(), [pat])
323 s = []
339 s = []
324 for r in subset:
340 for r in subset:
325 for f in repo[r].files():
341 for f in repo[r].files():
326 if m(f):
342 if m(f):
327 s.append(r)
343 s.append(r)
328 continue
344 continue
329 return s
345 return s
330
346
331 def contains(repo, subset, x):
347 def contains(repo, subset, x):
348 # i18n: "contains" is a keyword
332 pat = getstring(x, _("contains requires a pattern"))
349 pat = getstring(x, _("contains requires a pattern"))
333 m = matchmod.match(repo.root, repo.getcwd(), [pat])
350 m = matchmod.match(repo.root, repo.getcwd(), [pat])
334 s = []
351 s = []
335 if m.files() == [pat]:
352 if m.files() == [pat]:
336 for r in subset:
353 for r in subset:
337 if pat in repo[r]:
354 if pat in repo[r]:
338 s.append(r)
355 s.append(r)
339 continue
356 continue
340 else:
357 else:
341 for r in subset:
358 for r in subset:
342 for f in repo[r].manifest():
359 for f in repo[r].manifest():
343 if m(f):
360 if m(f):
344 s.append(r)
361 s.append(r)
345 continue
362 continue
346 return s
363 return s
347
364
348 def checkstatus(repo, subset, pat, field):
365 def checkstatus(repo, subset, pat, field):
349 m = matchmod.match(repo.root, repo.getcwd(), [pat])
366 m = matchmod.match(repo.root, repo.getcwd(), [pat])
350 s = []
367 s = []
351 fast = (m.files() == [pat])
368 fast = (m.files() == [pat])
352 for r in subset:
369 for r in subset:
353 c = repo[r]
370 c = repo[r]
354 if fast:
371 if fast:
355 if pat not in c.files():
372 if pat not in c.files():
356 continue
373 continue
357 else:
374 else:
358 for f in c.files():
375 for f in c.files():
359 if m(f):
376 if m(f):
360 break
377 break
361 else:
378 else:
362 continue
379 continue
363 files = repo.status(c.p1().node(), c.node())[field]
380 files = repo.status(c.p1().node(), c.node())[field]
364 if fast:
381 if fast:
365 if pat in files:
382 if pat in files:
366 s.append(r)
383 s.append(r)
367 continue
384 continue
368 else:
385 else:
369 for f in files:
386 for f in files:
370 if m(f):
387 if m(f):
371 s.append(r)
388 s.append(r)
372 continue
389 continue
373 return s
390 return s
374
391
375 def modifies(repo, subset, x):
392 def modifies(repo, subset, x):
393 # i18n: "modifies" is a keyword
376 pat = getstring(x, _("modifies requires a pattern"))
394 pat = getstring(x, _("modifies requires a pattern"))
377 return checkstatus(repo, subset, pat, 0)
395 return checkstatus(repo, subset, pat, 0)
378
396
379 def adds(repo, subset, x):
397 def adds(repo, subset, x):
398 # i18n: "adds" is a keyword
380 pat = getstring(x, _("adds requires a pattern"))
399 pat = getstring(x, _("adds requires a pattern"))
381 return checkstatus(repo, subset, pat, 1)
400 return checkstatus(repo, subset, pat, 1)
382
401
383 def removes(repo, subset, x):
402 def removes(repo, subset, x):
403 # i18n: "removes" is a keyword
384 pat = getstring(x, _("removes requires a pattern"))
404 pat = getstring(x, _("removes requires a pattern"))
385 return checkstatus(repo, subset, pat, 2)
405 return checkstatus(repo, subset, pat, 2)
386
406
387 def merge(repo, subset, x):
407 def merge(repo, subset, x):
408 # i18n: "merge" is a keyword
388 getargs(x, 0, 0, _("merge takes no arguments"))
409 getargs(x, 0, 0, _("merge takes no arguments"))
389 cl = repo.changelog
410 cl = repo.changelog
390 return [r for r in subset if cl.parentrevs(r)[1] != -1]
411 return [r for r in subset if cl.parentrevs(r)[1] != -1]
391
412
392 def closed(repo, subset, x):
413 def closed(repo, subset, x):
414 # i18n: "closed" is a keyword
393 getargs(x, 0, 0, _("closed takes no arguments"))
415 getargs(x, 0, 0, _("closed takes no arguments"))
394 return [r for r in subset if repo[r].extra().get('close')]
416 return [r for r in subset if repo[r].extra().get('close')]
395
417
396 def head(repo, subset, x):
418 def head(repo, subset, x):
419 # i18n: "head" is a keyword
397 getargs(x, 0, 0, _("head takes no arguments"))
420 getargs(x, 0, 0, _("head takes no arguments"))
398 hs = set()
421 hs = set()
399 for b, ls in repo.branchmap().iteritems():
422 for b, ls in repo.branchmap().iteritems():
400 hs.update(repo[h].rev() for h in ls)
423 hs.update(repo[h].rev() for h in ls)
401 return [r for r in subset if r in hs]
424 return [r for r in subset if r in hs]
402
425
403 def reverse(repo, subset, x):
426 def reverse(repo, subset, x):
404 l = getset(repo, subset, x)
427 l = getset(repo, subset, x)
405 l.reverse()
428 l.reverse()
406 return l
429 return l
407
430
408 def present(repo, subset, x):
431 def present(repo, subset, x):
409 try:
432 try:
410 return getset(repo, subset, x)
433 return getset(repo, subset, x)
411 except error.RepoLookupError:
434 except error.RepoLookupError:
412 return []
435 return []
413
436
414 def sort(repo, subset, x):
437 def sort(repo, subset, x):
438 # i18n: "sort" is a keyword
415 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
439 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
416 keys = "rev"
440 keys = "rev"
417 if len(l) == 2:
441 if len(l) == 2:
418 keys = getstring(l[1], _("sort spec must be a string"))
442 keys = getstring(l[1], _("sort spec must be a string"))
419
443
420 s = l[0]
444 s = l[0]
421 keys = keys.split()
445 keys = keys.split()
422 l = []
446 l = []
423 def invert(s):
447 def invert(s):
424 return "".join(chr(255 - ord(c)) for c in s)
448 return "".join(chr(255 - ord(c)) for c in s)
425 for r in getset(repo, subset, s):
449 for r in getset(repo, subset, s):
426 c = repo[r]
450 c = repo[r]
427 e = []
451 e = []
428 for k in keys:
452 for k in keys:
429 if k == 'rev':
453 if k == 'rev':
430 e.append(r)
454 e.append(r)
431 elif k == '-rev':
455 elif k == '-rev':
432 e.append(-r)
456 e.append(-r)
433 elif k == 'branch':
457 elif k == 'branch':
434 e.append(c.branch())
458 e.append(c.branch())
435 elif k == '-branch':
459 elif k == '-branch':
436 e.append(invert(c.branch()))
460 e.append(invert(c.branch()))
437 elif k == 'desc':
461 elif k == 'desc':
438 e.append(c.description())
462 e.append(c.description())
439 elif k == '-desc':
463 elif k == '-desc':
440 e.append(invert(c.description()))
464 e.append(invert(c.description()))
441 elif k in 'user author':
465 elif k in 'user author':
442 e.append(c.user())
466 e.append(c.user())
443 elif k in '-user -author':
467 elif k in '-user -author':
444 e.append(invert(c.user()))
468 e.append(invert(c.user()))
445 elif k == 'date':
469 elif k == 'date':
446 e.append(c.date()[0])
470 e.append(c.date()[0])
447 elif k == '-date':
471 elif k == '-date':
448 e.append(-c.date()[0])
472 e.append(-c.date()[0])
449 else:
473 else:
450 raise error.ParseError(_("unknown sort key %r") % k)
474 raise error.ParseError(_("unknown sort key %r") % k)
451 e.append(r)
475 e.append(r)
452 l.append(e)
476 l.append(e)
453 l.sort()
477 l.sort()
454 return [e[-1] for e in l]
478 return [e[-1] for e in l]
455
479
456 def getall(repo, subset, x):
480 def getall(repo, subset, x):
481 # i18n: "all" is a keyword
457 getargs(x, 0, 0, _("all takes no arguments"))
482 getargs(x, 0, 0, _("all takes no arguments"))
458 return subset
483 return subset
459
484
460 def heads(repo, subset, x):
485 def heads(repo, subset, x):
461 s = getset(repo, subset, x)
486 s = getset(repo, subset, x)
462 ps = set(parents(repo, subset, x))
487 ps = set(parents(repo, subset, x))
463 return [r for r in s if r not in ps]
488 return [r for r in s if r not in ps]
464
489
465 def roots(repo, subset, x):
490 def roots(repo, subset, x):
466 s = getset(repo, subset, x)
491 s = getset(repo, subset, x)
467 cs = set(children(repo, subset, x))
492 cs = set(children(repo, subset, x))
468 return [r for r in s if r not in cs]
493 return [r for r in s if r not in cs]
469
494
470 def outgoing(repo, subset, x):
495 def outgoing(repo, subset, x):
471 import hg # avoid start-up nasties
496 import hg # avoid start-up nasties
497 # i18n: "outgoing" is a keyword
472 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
498 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
499 # i18n: "outgoing" is a keyword
473 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
500 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
474 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
501 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
475 dest, branches = hg.parseurl(dest)
502 dest, branches = hg.parseurl(dest)
476 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
503 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
477 if revs:
504 if revs:
478 revs = [repo.lookup(rev) for rev in revs]
505 revs = [repo.lookup(rev) for rev in revs]
479 other = hg.repository(hg.remoteui(repo, {}), dest)
506 other = hg.repository(hg.remoteui(repo, {}), dest)
480 repo.ui.pushbuffer()
507 repo.ui.pushbuffer()
481 o = discovery.findoutgoing(repo, other)
508 o = discovery.findoutgoing(repo, other)
482 repo.ui.popbuffer()
509 repo.ui.popbuffer()
483 cl = repo.changelog
510 cl = repo.changelog
484 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
511 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
485 return [r for r in subset if r in o]
512 return [r for r in subset if r in o]
486
513
487 def tag(repo, subset, x):
514 def tag(repo, subset, x):
515 # i18n: "tag" is a keyword
488 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
516 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
489 cl = repo.changelog
517 cl = repo.changelog
490 if args:
518 if args:
491 tn = getstring(args[0],
519 tn = getstring(args[0],
520 # i18n: "tag" is a keyword
492 _('the argument to tag must be a string'))
521 _('the argument to tag must be a string'))
493 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
522 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
494 else:
523 else:
495 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
524 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
496 return [r for r in subset if r in s]
525 return [r for r in subset if r in s]
497
526
498 symbols = {
527 symbols = {
499 "adds": adds,
528 "adds": adds,
500 "all": getall,
529 "all": getall,
501 "ancestor": ancestor,
530 "ancestor": ancestor,
502 "ancestors": ancestors,
531 "ancestors": ancestors,
503 "author": author,
532 "author": author,
504 "branch": branch,
533 "branch": branch,
505 "children": children,
534 "children": children,
506 "closed": closed,
535 "closed": closed,
507 "contains": contains,
536 "contains": contains,
508 "date": date,
537 "date": date,
509 "descendants": descendants,
538 "descendants": descendants,
510 "file": hasfile,
539 "file": hasfile,
511 "follow": follow,
540 "follow": follow,
512 "grep": grep,
541 "grep": grep,
513 "head": head,
542 "head": head,
514 "heads": heads,
543 "heads": heads,
515 "keyword": keyword,
544 "keyword": keyword,
516 "limit": limit,
545 "limit": limit,
517 "max": maxrev,
546 "max": maxrev,
518 "min": minrev,
547 "min": minrev,
519 "merge": merge,
548 "merge": merge,
520 "modifies": modifies,
549 "modifies": modifies,
521 "id": node,
550 "id": node,
522 "outgoing": outgoing,
551 "outgoing": outgoing,
523 "p1": p1,
552 "p1": p1,
524 "p2": p2,
553 "p2": p2,
525 "parents": parents,
554 "parents": parents,
526 "present": present,
555 "present": present,
527 "removes": removes,
556 "removes": removes,
528 "reverse": reverse,
557 "reverse": reverse,
529 "rev": rev,
558 "rev": rev,
530 "roots": roots,
559 "roots": roots,
531 "sort": sort,
560 "sort": sort,
532 "tag": tag,
561 "tag": tag,
533 "tagged": tag,
562 "tagged": tag,
534 "user": author,
563 "user": author,
535 }
564 }
536
565
537 methods = {
566 methods = {
538 "range": rangeset,
567 "range": rangeset,
539 "string": stringset,
568 "string": stringset,
540 "symbol": symbolset,
569 "symbol": symbolset,
541 "and": andset,
570 "and": andset,
542 "or": orset,
571 "or": orset,
543 "not": notset,
572 "not": notset,
544 "list": listset,
573 "list": listset,
545 "func": func,
574 "func": func,
546 }
575 }
547
576
548 def optimize(x, small):
577 def optimize(x, small):
549 if x == None:
578 if x == None:
550 return 0, x
579 return 0, x
551
580
552 smallbonus = 1
581 smallbonus = 1
553 if small:
582 if small:
554 smallbonus = .5
583 smallbonus = .5
555
584
556 op = x[0]
585 op = x[0]
557 if op == 'minus':
586 if op == 'minus':
558 return optimize(('and', x[1], ('not', x[2])), small)
587 return optimize(('and', x[1], ('not', x[2])), small)
559 elif op == 'dagrange':
588 elif op == 'dagrange':
560 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
589 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
561 ('func', ('symbol', 'ancestors'), x[2])), small)
590 ('func', ('symbol', 'ancestors'), x[2])), small)
562 elif op == 'dagrangepre':
591 elif op == 'dagrangepre':
563 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
592 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
564 elif op == 'dagrangepost':
593 elif op == 'dagrangepost':
565 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
594 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
566 elif op == 'rangepre':
595 elif op == 'rangepre':
567 return optimize(('range', ('string', '0'), x[1]), small)
596 return optimize(('range', ('string', '0'), x[1]), small)
568 elif op == 'rangepost':
597 elif op == 'rangepost':
569 return optimize(('range', x[1], ('string', 'tip')), small)
598 return optimize(('range', x[1], ('string', 'tip')), small)
570 elif op == 'negate':
599 elif op == 'negate':
571 return optimize(('string',
600 return optimize(('string',
572 '-' + getstring(x[1], _("can't negate that"))), small)
601 '-' + getstring(x[1], _("can't negate that"))), small)
573 elif op in 'string symbol negate':
602 elif op in 'string symbol negate':
574 return smallbonus, x # single revisions are small
603 return smallbonus, x # single revisions are small
575 elif op == 'and' or op == 'dagrange':
604 elif op == 'and' or op == 'dagrange':
576 wa, ta = optimize(x[1], True)
605 wa, ta = optimize(x[1], True)
577 wb, tb = optimize(x[2], True)
606 wb, tb = optimize(x[2], True)
578 w = min(wa, wb)
607 w = min(wa, wb)
579 if wa > wb:
608 if wa > wb:
580 return w, (op, tb, ta)
609 return w, (op, tb, ta)
581 return w, (op, ta, tb)
610 return w, (op, ta, tb)
582 elif op == 'or':
611 elif op == 'or':
583 wa, ta = optimize(x[1], False)
612 wa, ta = optimize(x[1], False)
584 wb, tb = optimize(x[2], False)
613 wb, tb = optimize(x[2], False)
585 if wb < wa:
614 if wb < wa:
586 wb, wa = wa, wb
615 wb, wa = wa, wb
587 return max(wa, wb), (op, ta, tb)
616 return max(wa, wb), (op, ta, tb)
588 elif op == 'not':
617 elif op == 'not':
589 o = optimize(x[1], not small)
618 o = optimize(x[1], not small)
590 return o[0], (op, o[1])
619 return o[0], (op, o[1])
591 elif op == 'group':
620 elif op == 'group':
592 return optimize(x[1], small)
621 return optimize(x[1], small)
593 elif op in 'range list':
622 elif op in 'range list':
594 wa, ta = optimize(x[1], small)
623 wa, ta = optimize(x[1], small)
595 wb, tb = optimize(x[2], small)
624 wb, tb = optimize(x[2], small)
596 return wa + wb, (op, ta, tb)
625 return wa + wb, (op, ta, tb)
597 elif op == 'func':
626 elif op == 'func':
598 f = getstring(x[1], _("not a symbol"))
627 f = getstring(x[1], _("not a symbol"))
599 wa, ta = optimize(x[2], small)
628 wa, ta = optimize(x[2], small)
600 if f in "grep date user author keyword branch file outgoing":
629 if f in "grep date user author keyword branch file outgoing":
601 w = 10 # slow
630 w = 10 # slow
602 elif f in "modifies adds removes":
631 elif f in "modifies adds removes":
603 w = 30 # slower
632 w = 30 # slower
604 elif f == "contains":
633 elif f == "contains":
605 w = 100 # very slow
634 w = 100 # very slow
606 elif f == "ancestor":
635 elif f == "ancestor":
607 w = 1 * smallbonus
636 w = 1 * smallbonus
608 elif f == "reverse limit":
637 elif f == "reverse limit":
609 w = 0
638 w = 0
610 elif f in "sort":
639 elif f in "sort":
611 w = 10 # assume most sorts look at changelog
640 w = 10 # assume most sorts look at changelog
612 else:
641 else:
613 w = 1
642 w = 1
614 return w + wa, (op, x[1], ta)
643 return w + wa, (op, x[1], ta)
615 return 1, x
644 return 1, x
616
645
617 parse = parser.parser(tokenize, elements).parse
646 parse = parser.parser(tokenize, elements).parse
618
647
619 def match(spec):
648 def match(spec):
620 if not spec:
649 if not spec:
621 raise error.ParseError(_("empty query"))
650 raise error.ParseError(_("empty query"))
622 tree = parse(spec)
651 tree = parse(spec)
623 weight, tree = optimize(tree, True)
652 weight, tree = optimize(tree, True)
624 def mfunc(repo, subset):
653 def mfunc(repo, subset):
625 return getset(repo, subset, tree)
654 return getset(repo, subset, tree)
626 return mfunc
655 return mfunc
General Comments 0
You need to be logged in to leave comments. Login now