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