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