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