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