##// END OF EJS Templates
revset: remove unnecessary debug statement
Patrick Mezard -
r12936:bdb766e6 default
parent child Browse files
Show More
@@ -1,814 +1,813
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 matchmod
11 11 from i18n import _, gettext
12 12
13 13 elements = {
14 14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 15 "-": (5, ("negate", 19), ("minus", 5)),
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 '"\'' or c == 'r' and
52 52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 53 if c == 'r':
54 54 pos += 1
55 55 c = program[pos]
56 56 decode = lambda x: x
57 57 else:
58 58 decode = lambda x: x.decode('string-escape')
59 59 pos += 1
60 60 s = pos
61 61 while pos < l: # find closing quote
62 62 d = program[pos]
63 63 if d == '\\': # skip over escaped characters
64 64 pos += 2
65 65 continue
66 66 if d == c:
67 67 yield ('string', decode(program[s:pos]), s)
68 68 break
69 69 pos += 1
70 70 else:
71 71 raise error.ParseError(_("unterminated string"), s)
72 72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
73 73 s = pos
74 74 pos += 1
75 75 while pos < l: # find end of symbol
76 76 d = program[pos]
77 77 if not (d.isalnum() or d in "._" or ord(d) > 127):
78 78 break
79 79 if d == '.' and program[pos - 1] == '.': # special case for ..
80 80 pos -= 1
81 81 break
82 82 pos += 1
83 83 sym = program[s:pos]
84 84 if sym in keywords: # operator keywords
85 85 yield (sym, None, s)
86 86 else:
87 87 yield ('symbol', sym, s)
88 88 pos -= 1
89 89 else:
90 90 raise error.ParseError(_("syntax error"), pos)
91 91 pos += 1
92 92 yield ('end', None, pos)
93 93
94 94 # helpers
95 95
96 96 def getstring(x, err):
97 97 if x and (x[0] == 'string' or x[0] == 'symbol'):
98 98 return x[1]
99 99 raise error.ParseError(err)
100 100
101 101 def getlist(x):
102 102 if not x:
103 103 return []
104 104 if x[0] == 'list':
105 105 return getlist(x[1]) + [x[2]]
106 106 return [x]
107 107
108 108 def getargs(x, min, max, err):
109 109 l = getlist(x)
110 110 if len(l) < min or len(l) > max:
111 111 raise error.ParseError(err)
112 112 return l
113 113
114 114 def getset(repo, subset, x):
115 115 if not x:
116 116 raise error.ParseError(_("missing argument"))
117 117 return methods[x[0]](repo, subset, *x[1:])
118 118
119 119 # operator methods
120 120
121 121 def stringset(repo, subset, x):
122 122 x = repo[x].rev()
123 123 if x == -1 and len(subset) == len(repo):
124 124 return [-1]
125 125 if x in subset:
126 126 return [x]
127 127 return []
128 128
129 129 def symbolset(repo, subset, x):
130 130 if x in symbols:
131 131 raise error.ParseError(_("can't use %s here") % x)
132 132 return stringset(repo, subset, x)
133 133
134 134 def rangeset(repo, subset, x, y):
135 135 m = getset(repo, subset, x)
136 136 if not m:
137 137 m = getset(repo, range(len(repo)), x)
138 138
139 139 n = getset(repo, subset, y)
140 140 if not n:
141 141 n = getset(repo, range(len(repo)), y)
142 142
143 143 if not m or not n:
144 144 return []
145 145 m, n = m[0], n[-1]
146 146
147 147 if m < n:
148 148 r = range(m, n + 1)
149 149 else:
150 150 r = range(m, n - 1, -1)
151 151 s = set(subset)
152 152 return [x for x in r if x in s]
153 153
154 154 def andset(repo, subset, x, y):
155 155 return getset(repo, getset(repo, subset, x), y)
156 156
157 157 def orset(repo, subset, x, y):
158 158 s = set(getset(repo, subset, x))
159 159 s |= set(getset(repo, [r for r in subset if r not in s], y))
160 160 return [r for r in subset if r in s]
161 161
162 162 def notset(repo, subset, x):
163 163 s = set(getset(repo, subset, x))
164 164 return [r for r in subset if r not in s]
165 165
166 166 def listset(repo, subset, a, b):
167 167 raise error.ParseError(_("can't use a list in this context"))
168 168
169 169 def func(repo, subset, a, b):
170 170 if a[0] == 'symbol' and a[1] in symbols:
171 171 return symbols[a[1]](repo, subset, b)
172 172 raise error.ParseError(_("not a function: %s") % a[1])
173 173
174 174 # functions
175 175
176 176 def node(repo, subset, x):
177 177 """``id(string)``
178 178 Revision non-ambiguously specified by the given hex string prefix.
179 179 """
180 180 # i18n: "id" is a keyword
181 181 l = getargs(x, 1, 1, _("id requires one argument"))
182 182 # i18n: "id" is a keyword
183 183 n = getstring(l[0], _("id requires a string"))
184 184 if len(n) == 40:
185 185 rn = repo[n].rev()
186 186 else:
187 187 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
188 188 return [r for r in subset if r == rn]
189 189
190 190 def rev(repo, subset, x):
191 191 """``rev(number)``
192 192 Revision with the given numeric identifier.
193 193 """
194 194 # i18n: "rev" is a keyword
195 195 l = getargs(x, 1, 1, _("rev requires one argument"))
196 196 try:
197 197 # i18n: "rev" is a keyword
198 198 l = int(getstring(l[0], _("rev requires a number")))
199 199 except ValueError:
200 200 # i18n: "rev" is a keyword
201 201 raise error.ParseError(_("rev expects a number"))
202 202 return [r for r in subset if r == l]
203 203
204 204 def p1(repo, subset, x):
205 205 """``p1([set])``
206 206 First parent of changesets in set, or the working directory.
207 207 """
208 208 if x is None:
209 209 p = repo[x].parents()[0].rev()
210 210 return [r for r in subset if r == p]
211 211
212 212 ps = set()
213 213 cl = repo.changelog
214 214 for r in getset(repo, range(len(repo)), x):
215 215 ps.add(cl.parentrevs(r)[0])
216 216 return [r for r in subset if r in ps]
217 217
218 218 def p2(repo, subset, x):
219 219 """``p2([set])``
220 220 Second parent of changesets in set, or the working directory.
221 221 """
222 222 if x is None:
223 223 ps = repo[x].parents()
224 224 try:
225 225 p = ps[1].rev()
226 226 return [r for r in subset if r == p]
227 227 except IndexError:
228 228 return []
229 229
230 230 ps = set()
231 231 cl = repo.changelog
232 232 for r in getset(repo, range(len(repo)), x):
233 233 ps.add(cl.parentrevs(r)[1])
234 234 return [r for r in subset if r in ps]
235 235
236 236 def parents(repo, subset, x):
237 237 """``parents([set])``
238 238 The set of all parents for all changesets in set, or the working directory.
239 239 """
240 repo.ui.debug(repr(x), '\n')
241 240 if x is None:
242 241 ps = tuple(p.rev() for p in repo[x].parents())
243 242 return [r for r in subset if r in ps]
244 243
245 244 ps = set()
246 245 cl = repo.changelog
247 246 for r in getset(repo, range(len(repo)), x):
248 247 ps.update(cl.parentrevs(r))
249 248 return [r for r in subset if r in ps]
250 249
251 250 def maxrev(repo, subset, x):
252 251 """``max(set)``
253 252 Changeset with highest revision number in set.
254 253 """
255 254 s = getset(repo, subset, x)
256 255 if s:
257 256 m = max(s)
258 257 if m in subset:
259 258 return [m]
260 259 return []
261 260
262 261 def minrev(repo, subset, x):
263 262 """``min(set)``
264 263 Changeset with lowest revision number in set.
265 264 """
266 265 s = getset(repo, subset, x)
267 266 if s:
268 267 m = min(s)
269 268 if m in subset:
270 269 return [m]
271 270 return []
272 271
273 272 def limit(repo, subset, x):
274 273 """``limit(set, n)``
275 274 First n members of set.
276 275 """
277 276 # i18n: "limit" is a keyword
278 277 l = getargs(x, 2, 2, _("limit requires two arguments"))
279 278 try:
280 279 # i18n: "limit" is a keyword
281 280 lim = int(getstring(l[1], _("limit requires a number")))
282 281 except ValueError:
283 282 # i18n: "limit" is a keyword
284 283 raise error.ParseError(_("limit expects a number"))
285 284 return getset(repo, subset, l[0])[:lim]
286 285
287 286 def children(repo, subset, x):
288 287 """``children(set)``
289 288 Child changesets of changesets in set.
290 289 """
291 290 cs = set()
292 291 cl = repo.changelog
293 292 s = set(getset(repo, range(len(repo)), x))
294 293 for r in xrange(0, len(repo)):
295 294 for p in cl.parentrevs(r):
296 295 if p in s:
297 296 cs.add(r)
298 297 return [r for r in subset if r in cs]
299 298
300 299 def branch(repo, subset, x):
301 300 """``branch(set)``
302 301 All changesets belonging to the branches of changesets in set.
303 302 """
304 303 s = getset(repo, range(len(repo)), x)
305 304 b = set()
306 305 for r in s:
307 306 b.add(repo[r].branch())
308 307 s = set(s)
309 308 return [r for r in subset if r in s or repo[r].branch() in b]
310 309
311 310 def ancestor(repo, subset, x):
312 311 """``ancestor(single, single)``
313 312 Greatest common ancestor of the two changesets.
314 313 """
315 314 # i18n: "ancestor" is a keyword
316 315 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
317 316 r = range(len(repo))
318 317 a = getset(repo, r, l[0])
319 318 b = getset(repo, r, l[1])
320 319 if len(a) != 1 or len(b) != 1:
321 320 # i18n: "ancestor" is a keyword
322 321 raise error.ParseError(_("ancestor arguments must be single revisions"))
323 322 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
324 323
325 324 return [r for r in an if r in subset]
326 325
327 326 def ancestors(repo, subset, x):
328 327 """``ancestors(set)``
329 328 Changesets that are ancestors of a changeset in set.
330 329 """
331 330 args = getset(repo, range(len(repo)), x)
332 331 if not args:
333 332 return []
334 333 s = set(repo.changelog.ancestors(*args)) | set(args)
335 334 return [r for r in subset if r in s]
336 335
337 336 def descendants(repo, subset, x):
338 337 """``descendants(set)``
339 338 Changesets which are descendants of changesets in set.
340 339 """
341 340 args = getset(repo, range(len(repo)), x)
342 341 if not args:
343 342 return []
344 343 s = set(repo.changelog.descendants(*args)) | set(args)
345 344 return [r for r in subset if r in s]
346 345
347 346 def follow(repo, subset, x):
348 347 """``follow()``
349 348 An alias for ``::.`` (ancestors of the working copy's first parent).
350 349 """
351 350 # i18n: "follow" is a keyword
352 351 getargs(x, 0, 0, _("follow takes no arguments"))
353 352 p = repo['.'].rev()
354 353 s = set(repo.changelog.ancestors(p)) | set([p])
355 354 return [r for r in subset if r in s]
356 355
357 356 def date(repo, subset, x):
358 357 """``date(interval)``
359 358 Changesets within the interval, see :hg:`help dates`.
360 359 """
361 360 # i18n: "date" is a keyword
362 361 ds = getstring(x, _("date requires a string"))
363 362 dm = util.matchdate(ds)
364 363 return [r for r in subset if dm(repo[r].date()[0])]
365 364
366 365 def keyword(repo, subset, x):
367 366 """``keyword(string)``
368 367 Search commit message, user name, and names of changed files for
369 368 string.
370 369 """
371 370 # i18n: "keyword" is a keyword
372 371 kw = getstring(x, _("keyword requires a string")).lower()
373 372 l = []
374 373 for r in subset:
375 374 c = repo[r]
376 375 t = " ".join(c.files() + [c.user(), c.description()])
377 376 if kw in t.lower():
378 377 l.append(r)
379 378 return l
380 379
381 380 def grep(repo, subset, x):
382 381 """``grep(regex)``
383 382 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
384 383 to ensure special escape characters are handled correctly.
385 384 """
386 385 try:
387 386 # i18n: "grep" is a keyword
388 387 gr = re.compile(getstring(x, _("grep requires a string")))
389 388 except re.error, e:
390 389 raise error.ParseError(_('invalid match pattern: %s') % e)
391 390 l = []
392 391 for r in subset:
393 392 c = repo[r]
394 393 for e in c.files() + [c.user(), c.description()]:
395 394 if gr.search(e):
396 395 l.append(r)
397 396 continue
398 397 return l
399 398
400 399 def author(repo, subset, x):
401 400 """``author(string)``
402 401 Alias for ``user(string)``.
403 402 """
404 403 # i18n: "author" is a keyword
405 404 n = getstring(x, _("author requires a string")).lower()
406 405 return [r for r in subset if n in repo[r].user().lower()]
407 406
408 407 def user(repo, subset, x):
409 408 """``user(string)``
410 409 User name is string.
411 410 """
412 411 return author(repo, subset, x)
413 412
414 413 def hasfile(repo, subset, x):
415 414 """``file(pattern)``
416 415 Changesets affecting files matched by pattern.
417 416 """
418 417 # i18n: "file" is a keyword
419 418 pat = getstring(x, _("file requires a pattern"))
420 419 m = matchmod.match(repo.root, repo.getcwd(), [pat])
421 420 s = []
422 421 for r in subset:
423 422 for f in repo[r].files():
424 423 if m(f):
425 424 s.append(r)
426 425 continue
427 426 return s
428 427
429 428 def contains(repo, subset, x):
430 429 """``contains(pattern)``
431 430 Revision contains pattern.
432 431 """
433 432 # i18n: "contains" is a keyword
434 433 pat = getstring(x, _("contains requires a pattern"))
435 434 m = matchmod.match(repo.root, repo.getcwd(), [pat])
436 435 s = []
437 436 if m.files() == [pat]:
438 437 for r in subset:
439 438 if pat in repo[r]:
440 439 s.append(r)
441 440 continue
442 441 else:
443 442 for r in subset:
444 443 for f in repo[r].manifest():
445 444 if m(f):
446 445 s.append(r)
447 446 continue
448 447 return s
449 448
450 449 def checkstatus(repo, subset, pat, field):
451 450 m = matchmod.match(repo.root, repo.getcwd(), [pat])
452 451 s = []
453 452 fast = (m.files() == [pat])
454 453 for r in subset:
455 454 c = repo[r]
456 455 if fast:
457 456 if pat not in c.files():
458 457 continue
459 458 else:
460 459 for f in c.files():
461 460 if m(f):
462 461 break
463 462 else:
464 463 continue
465 464 files = repo.status(c.p1().node(), c.node())[field]
466 465 if fast:
467 466 if pat in files:
468 467 s.append(r)
469 468 continue
470 469 else:
471 470 for f in files:
472 471 if m(f):
473 472 s.append(r)
474 473 continue
475 474 return s
476 475
477 476 def modifies(repo, subset, x):
478 477 """``modifies(pattern)``
479 478 Changesets modifying files matched by pattern.
480 479 """
481 480 # i18n: "modifies" is a keyword
482 481 pat = getstring(x, _("modifies requires a pattern"))
483 482 return checkstatus(repo, subset, pat, 0)
484 483
485 484 def adds(repo, subset, x):
486 485 """``adds(pattern)``
487 486 Changesets that add a file matching pattern.
488 487 """
489 488 # i18n: "adds" is a keyword
490 489 pat = getstring(x, _("adds requires a pattern"))
491 490 return checkstatus(repo, subset, pat, 1)
492 491
493 492 def removes(repo, subset, x):
494 493 """``removes(pattern)``
495 494 Changesets which remove files matching pattern.
496 495 """
497 496 # i18n: "removes" is a keyword
498 497 pat = getstring(x, _("removes requires a pattern"))
499 498 return checkstatus(repo, subset, pat, 2)
500 499
501 500 def merge(repo, subset, x):
502 501 """``merge()``
503 502 Changeset is a merge changeset.
504 503 """
505 504 # i18n: "merge" is a keyword
506 505 getargs(x, 0, 0, _("merge takes no arguments"))
507 506 cl = repo.changelog
508 507 return [r for r in subset if cl.parentrevs(r)[1] != -1]
509 508
510 509 def closed(repo, subset, x):
511 510 """``closed()``
512 511 Changeset is closed.
513 512 """
514 513 # i18n: "closed" is a keyword
515 514 getargs(x, 0, 0, _("closed takes no arguments"))
516 515 return [r for r in subset if repo[r].extra().get('close')]
517 516
518 517 def head(repo, subset, x):
519 518 """``head()``
520 519 Changeset is a named branch head.
521 520 """
522 521 # i18n: "head" is a keyword
523 522 getargs(x, 0, 0, _("head takes no arguments"))
524 523 hs = set()
525 524 for b, ls in repo.branchmap().iteritems():
526 525 hs.update(repo[h].rev() for h in ls)
527 526 return [r for r in subset if r in hs]
528 527
529 528 def reverse(repo, subset, x):
530 529 """``reverse(set)``
531 530 Reverse order of set.
532 531 """
533 532 l = getset(repo, subset, x)
534 533 l.reverse()
535 534 return l
536 535
537 536 def present(repo, subset, x):
538 537 """``present(set)``
539 538 An empty set, if any revision in set isn't found; otherwise,
540 539 all revisions in set.
541 540 """
542 541 try:
543 542 return getset(repo, subset, x)
544 543 except error.RepoLookupError:
545 544 return []
546 545
547 546 def sort(repo, subset, x):
548 547 """``sort(set[, [-]key...])``
549 548 Sort set by keys. The default sort order is ascending, specify a key
550 549 as ``-key`` to sort in descending order.
551 550
552 551 The keys can be:
553 552
554 553 - ``rev`` for the revision number,
555 554 - ``branch`` for the branch name,
556 555 - ``desc`` for the commit message (description),
557 556 - ``user`` for user name (``author`` can be used as an alias),
558 557 - ``date`` for the commit date
559 558 """
560 559 # i18n: "sort" is a keyword
561 560 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
562 561 keys = "rev"
563 562 if len(l) == 2:
564 563 keys = getstring(l[1], _("sort spec must be a string"))
565 564
566 565 s = l[0]
567 566 keys = keys.split()
568 567 l = []
569 568 def invert(s):
570 569 return "".join(chr(255 - ord(c)) for c in s)
571 570 for r in getset(repo, subset, s):
572 571 c = repo[r]
573 572 e = []
574 573 for k in keys:
575 574 if k == 'rev':
576 575 e.append(r)
577 576 elif k == '-rev':
578 577 e.append(-r)
579 578 elif k == 'branch':
580 579 e.append(c.branch())
581 580 elif k == '-branch':
582 581 e.append(invert(c.branch()))
583 582 elif k == 'desc':
584 583 e.append(c.description())
585 584 elif k == '-desc':
586 585 e.append(invert(c.description()))
587 586 elif k in 'user author':
588 587 e.append(c.user())
589 588 elif k in '-user -author':
590 589 e.append(invert(c.user()))
591 590 elif k == 'date':
592 591 e.append(c.date()[0])
593 592 elif k == '-date':
594 593 e.append(-c.date()[0])
595 594 else:
596 595 raise error.ParseError(_("unknown sort key %r") % k)
597 596 e.append(r)
598 597 l.append(e)
599 598 l.sort()
600 599 return [e[-1] for e in l]
601 600
602 601 def getall(repo, subset, x):
603 602 """``all()``
604 603 All changesets, the same as ``0:tip``.
605 604 """
606 605 # i18n: "all" is a keyword
607 606 getargs(x, 0, 0, _("all takes no arguments"))
608 607 return subset
609 608
610 609 def heads(repo, subset, x):
611 610 """``heads(set)``
612 611 Members of set with no children in set.
613 612 """
614 613 s = getset(repo, subset, x)
615 614 ps = set(parents(repo, subset, x))
616 615 return [r for r in s if r not in ps]
617 616
618 617 def roots(repo, subset, x):
619 618 """``roots(set)``
620 619 Changesets with no parent changeset in set.
621 620 """
622 621 s = getset(repo, subset, x)
623 622 cs = set(children(repo, subset, x))
624 623 return [r for r in s if r not in cs]
625 624
626 625 def outgoing(repo, subset, x):
627 626 """``outgoing([path])``
628 627 Changesets not found in the specified destination repository, or the
629 628 default push location.
630 629 """
631 630 import hg # avoid start-up nasties
632 631 # i18n: "outgoing" is a keyword
633 632 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
634 633 # i18n: "outgoing" is a keyword
635 634 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
636 635 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
637 636 dest, branches = hg.parseurl(dest)
638 637 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
639 638 if revs:
640 639 revs = [repo.lookup(rev) for rev in revs]
641 640 other = hg.repository(hg.remoteui(repo, {}), dest)
642 641 repo.ui.pushbuffer()
643 642 o = discovery.findoutgoing(repo, other)
644 643 repo.ui.popbuffer()
645 644 cl = repo.changelog
646 645 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
647 646 return [r for r in subset if r in o]
648 647
649 648 def tag(repo, subset, x):
650 649 """``tag(name)``
651 650 The specified tag by name, or all tagged revisions if no name is given.
652 651 """
653 652 # i18n: "tag" is a keyword
654 653 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
655 654 cl = repo.changelog
656 655 if args:
657 656 tn = getstring(args[0],
658 657 # i18n: "tag" is a keyword
659 658 _('the argument to tag must be a string'))
660 659 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
661 660 else:
662 661 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
663 662 return [r for r in subset if r in s]
664 663
665 664 def tagged(repo, subset, x):
666 665 return tag(repo, subset, x)
667 666
668 667 symbols = {
669 668 "adds": adds,
670 669 "all": getall,
671 670 "ancestor": ancestor,
672 671 "ancestors": ancestors,
673 672 "author": author,
674 673 "branch": branch,
675 674 "children": children,
676 675 "closed": closed,
677 676 "contains": contains,
678 677 "date": date,
679 678 "descendants": descendants,
680 679 "file": hasfile,
681 680 "follow": follow,
682 681 "grep": grep,
683 682 "head": head,
684 683 "heads": heads,
685 684 "keyword": keyword,
686 685 "limit": limit,
687 686 "max": maxrev,
688 687 "min": minrev,
689 688 "merge": merge,
690 689 "modifies": modifies,
691 690 "id": node,
692 691 "outgoing": outgoing,
693 692 "p1": p1,
694 693 "p2": p2,
695 694 "parents": parents,
696 695 "present": present,
697 696 "removes": removes,
698 697 "reverse": reverse,
699 698 "rev": rev,
700 699 "roots": roots,
701 700 "sort": sort,
702 701 "tag": tag,
703 702 "tagged": tagged,
704 703 "user": user,
705 704 }
706 705
707 706 methods = {
708 707 "range": rangeset,
709 708 "string": stringset,
710 709 "symbol": symbolset,
711 710 "and": andset,
712 711 "or": orset,
713 712 "not": notset,
714 713 "list": listset,
715 714 "func": func,
716 715 }
717 716
718 717 def optimize(x, small):
719 718 if x == None:
720 719 return 0, x
721 720
722 721 smallbonus = 1
723 722 if small:
724 723 smallbonus = .5
725 724
726 725 op = x[0]
727 726 if op == 'minus':
728 727 return optimize(('and', x[1], ('not', x[2])), small)
729 728 elif op == 'dagrange':
730 729 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
731 730 ('func', ('symbol', 'ancestors'), x[2])), small)
732 731 elif op == 'dagrangepre':
733 732 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
734 733 elif op == 'dagrangepost':
735 734 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
736 735 elif op == 'rangepre':
737 736 return optimize(('range', ('string', '0'), x[1]), small)
738 737 elif op == 'rangepost':
739 738 return optimize(('range', x[1], ('string', 'tip')), small)
740 739 elif op == 'negate':
741 740 return optimize(('string',
742 741 '-' + getstring(x[1], _("can't negate that"))), small)
743 742 elif op in 'string symbol negate':
744 743 return smallbonus, x # single revisions are small
745 744 elif op == 'and' or op == 'dagrange':
746 745 wa, ta = optimize(x[1], True)
747 746 wb, tb = optimize(x[2], True)
748 747 w = min(wa, wb)
749 748 if wa > wb:
750 749 return w, (op, tb, ta)
751 750 return w, (op, ta, tb)
752 751 elif op == 'or':
753 752 wa, ta = optimize(x[1], False)
754 753 wb, tb = optimize(x[2], False)
755 754 if wb < wa:
756 755 wb, wa = wa, wb
757 756 return max(wa, wb), (op, ta, tb)
758 757 elif op == 'not':
759 758 o = optimize(x[1], not small)
760 759 return o[0], (op, o[1])
761 760 elif op == 'group':
762 761 return optimize(x[1], small)
763 762 elif op in 'range list':
764 763 wa, ta = optimize(x[1], small)
765 764 wb, tb = optimize(x[2], small)
766 765 return wa + wb, (op, ta, tb)
767 766 elif op == 'func':
768 767 f = getstring(x[1], _("not a symbol"))
769 768 wa, ta = optimize(x[2], small)
770 769 if f in "grep date user author keyword branch file outgoing":
771 770 w = 10 # slow
772 771 elif f in "modifies adds removes":
773 772 w = 30 # slower
774 773 elif f == "contains":
775 774 w = 100 # very slow
776 775 elif f == "ancestor":
777 776 w = 1 * smallbonus
778 777 elif f == "reverse limit":
779 778 w = 0
780 779 elif f in "sort":
781 780 w = 10 # assume most sorts look at changelog
782 781 else:
783 782 w = 1
784 783 return w + wa, (op, x[1], ta)
785 784 return 1, x
786 785
787 786 parse = parser.parser(tokenize, elements).parse
788 787
789 788 def match(spec):
790 789 if not spec:
791 790 raise error.ParseError(_("empty query"))
792 791 tree = parse(spec)
793 792 weight, tree = optimize(tree, True)
794 793 def mfunc(repo, subset):
795 794 return getset(repo, subset, tree)
796 795 return mfunc
797 796
798 797 def makedoc(topic, doc):
799 798 """Generate and include predicates help in revsets topic."""
800 799 predicates = []
801 800 for name in sorted(symbols):
802 801 text = symbols[name].__doc__
803 802 if not text:
804 803 continue
805 804 text = gettext(text.rstrip())
806 805 lines = text.splitlines()
807 806 lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
808 807 predicates.append('\n'.join(lines))
809 808 predicates = '\n\n'.join(predicates)
810 809 doc = doc.replace('.. predicatesmarker', predicates)
811 810 return doc
812 811
813 812 # tell hggettext to extract docstrings from these functions:
814 813 i18nfunctions = symbols.values()
@@ -1,53 +1,52
1 1 $ HGENCODING=utf-8
2 2 $ export HGENCODING
3 3
4 4 $ try() {
5 5 > hg debugrevspec --debug $@
6 6 > }
7 7
8 8 $ log() {
9 9 > hg log --template '{rev}\n' -r "$1"
10 10 > }
11 11
12 12 $ hg init repo
13 13 $ cd repo
14 14
15 15 $ try 'p1()'
16 16 ('func', ('symbol', 'p1'), None)
17 17 $ try 'p2()'
18 18 ('func', ('symbol', 'p2'), None)
19 19 $ try 'parents()'
20 20 ('func', ('symbol', 'parents'), None)
21 None
22 21
23 22 null revision
24 23 $ log 'p1()'
25 24 $ log 'p2()'
26 25 $ log 'parents()'
27 26
28 27 working dir with a single parent
29 28 $ echo a > a
30 29 $ hg ci -Aqm0
31 30 $ log 'p1()'
32 31 0
33 32 $ log 'tag() and p1()'
34 33 $ log 'p2()'
35 34 $ log 'parents()'
36 35 0
37 36 $ log 'tag() and parents()'
38 37
39 38 merge in progress
40 39 $ echo b > b
41 40 $ hg ci -Aqm1
42 41 $ hg up -q 0
43 42 $ echo c > c
44 43 $ hg ci -Aqm2
45 44 $ hg merge -q
46 45 $ log 'p1()'
47 46 2
48 47 $ log 'p2()'
49 48 1
50 49 $ log 'tag() and p2()'
51 50 $ log 'parents()'
52 51 1
53 52 2
General Comments 0
You need to be logged in to leave comments. Login now