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