##// END OF EJS Templates
revsetlang: check arguments passed to ancestors() before optimizing to only()...
Yuya Nishihara -
r32913:3292c0df default
parent child Browse files
Show More
@@ -1,718 +1,723
1 1 # revsetlang.py - parser, tokenizer and utility for revision set language
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 from __future__ import absolute_import
9 9
10 10 import string
11 11
12 12 from .i18n import _
13 13 from . import (
14 14 error,
15 15 node,
16 16 parser,
17 17 pycompat,
18 18 util,
19 19 )
20 20
21 21 elements = {
22 22 # token-type: binding-strength, primary, prefix, infix, suffix
23 23 "(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
24 24 "##": (20, None, None, ("_concat", 20), None),
25 25 "~": (18, None, None, ("ancestor", 18), None),
26 26 "^": (18, None, None, ("parent", 18), "parentpost"),
27 27 "-": (5, None, ("negate", 19), ("minus", 5), None),
28 28 "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
29 29 "..": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
30 30 ":": (15, "rangeall", ("rangepre", 15), ("range", 15), "rangepost"),
31 31 "not": (10, None, ("not", 10), None, None),
32 32 "!": (10, None, ("not", 10), None, None),
33 33 "and": (5, None, None, ("and", 5), None),
34 34 "&": (5, None, None, ("and", 5), None),
35 35 "%": (5, None, None, ("only", 5), "onlypost"),
36 36 "or": (4, None, None, ("or", 4), None),
37 37 "|": (4, None, None, ("or", 4), None),
38 38 "+": (4, None, None, ("or", 4), None),
39 39 "=": (3, None, None, ("keyvalue", 3), None),
40 40 ",": (2, None, None, ("list", 2), None),
41 41 ")": (0, None, None, None, None),
42 42 "symbol": (0, "symbol", None, None, None),
43 43 "string": (0, "string", None, None, None),
44 44 "end": (0, None, None, None, None),
45 45 }
46 46
47 47 keywords = {'and', 'or', 'not'}
48 48
49 49 _quoteletters = {'"', "'"}
50 50 _simpleopletters = set(pycompat.iterbytestr("():=,-|&+!~^%"))
51 51
52 52 # default set of valid characters for the initial letter of symbols
53 53 _syminitletters = set(pycompat.iterbytestr(
54 54 string.ascii_letters.encode('ascii') +
55 55 string.digits.encode('ascii') +
56 56 '._@')) | set(map(pycompat.bytechr, xrange(128, 256)))
57 57
58 58 # default set of valid characters for non-initial letters of symbols
59 59 _symletters = _syminitletters | set(pycompat.iterbytestr('-/'))
60 60
61 61 def tokenize(program, lookup=None, syminitletters=None, symletters=None):
62 62 '''
63 63 Parse a revset statement into a stream of tokens
64 64
65 65 ``syminitletters`` is the set of valid characters for the initial
66 66 letter of symbols.
67 67
68 68 By default, character ``c`` is recognized as valid for initial
69 69 letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
70 70
71 71 ``symletters`` is the set of valid characters for non-initial
72 72 letters of symbols.
73 73
74 74 By default, character ``c`` is recognized as valid for non-initial
75 75 letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
76 76
77 77 Check that @ is a valid unquoted token character (issue3686):
78 78 >>> list(tokenize("@::"))
79 79 [('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
80 80
81 81 '''
82 82 program = pycompat.bytestr(program)
83 83 if syminitletters is None:
84 84 syminitletters = _syminitletters
85 85 if symletters is None:
86 86 symletters = _symletters
87 87
88 88 if program and lookup:
89 89 # attempt to parse old-style ranges first to deal with
90 90 # things like old-tag which contain query metacharacters
91 91 parts = program.split(':', 1)
92 92 if all(lookup(sym) for sym in parts if sym):
93 93 if parts[0]:
94 94 yield ('symbol', parts[0], 0)
95 95 if len(parts) > 1:
96 96 s = len(parts[0])
97 97 yield (':', None, s)
98 98 if parts[1]:
99 99 yield ('symbol', parts[1], s + 1)
100 100 yield ('end', None, len(program))
101 101 return
102 102
103 103 pos, l = 0, len(program)
104 104 while pos < l:
105 105 c = program[pos]
106 106 if c.isspace(): # skip inter-token whitespace
107 107 pass
108 108 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
109 109 yield ('::', None, pos)
110 110 pos += 1 # skip ahead
111 111 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
112 112 yield ('..', None, pos)
113 113 pos += 1 # skip ahead
114 114 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
115 115 yield ('##', None, pos)
116 116 pos += 1 # skip ahead
117 117 elif c in _simpleopletters: # handle simple operators
118 118 yield (c, None, pos)
119 119 elif (c in _quoteletters or c == 'r' and
120 120 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
121 121 if c == 'r':
122 122 pos += 1
123 123 c = program[pos]
124 124 decode = lambda x: x
125 125 else:
126 126 decode = parser.unescapestr
127 127 pos += 1
128 128 s = pos
129 129 while pos < l: # find closing quote
130 130 d = program[pos]
131 131 if d == '\\': # skip over escaped characters
132 132 pos += 2
133 133 continue
134 134 if d == c:
135 135 yield ('string', decode(program[s:pos]), s)
136 136 break
137 137 pos += 1
138 138 else:
139 139 raise error.ParseError(_("unterminated string"), s)
140 140 # gather up a symbol/keyword
141 141 elif c in syminitletters:
142 142 s = pos
143 143 pos += 1
144 144 while pos < l: # find end of symbol
145 145 d = program[pos]
146 146 if d not in symletters:
147 147 break
148 148 if d == '.' and program[pos - 1] == '.': # special case for ..
149 149 pos -= 1
150 150 break
151 151 pos += 1
152 152 sym = program[s:pos]
153 153 if sym in keywords: # operator keywords
154 154 yield (sym, None, s)
155 155 elif '-' in sym:
156 156 # some jerk gave us foo-bar-baz, try to check if it's a symbol
157 157 if lookup and lookup(sym):
158 158 # looks like a real symbol
159 159 yield ('symbol', sym, s)
160 160 else:
161 161 # looks like an expression
162 162 parts = sym.split('-')
163 163 for p in parts[:-1]:
164 164 if p: # possible consecutive -
165 165 yield ('symbol', p, s)
166 166 s += len(p)
167 167 yield ('-', None, pos)
168 168 s += 1
169 169 if parts[-1]: # possible trailing -
170 170 yield ('symbol', parts[-1], s)
171 171 else:
172 172 yield ('symbol', sym, s)
173 173 pos -= 1
174 174 else:
175 175 raise error.ParseError(_("syntax error in revset '%s'") %
176 176 program, pos)
177 177 pos += 1
178 178 yield ('end', None, pos)
179 179
180 180 # helpers
181 181
182 182 _notset = object()
183 183
184 184 def getsymbol(x):
185 185 if x and x[0] == 'symbol':
186 186 return x[1]
187 187 raise error.ParseError(_('not a symbol'))
188 188
189 189 def getstring(x, err):
190 190 if x and (x[0] == 'string' or x[0] == 'symbol'):
191 191 return x[1]
192 192 raise error.ParseError(err)
193 193
194 194 def getinteger(x, err, default=_notset):
195 195 if not x and default is not _notset:
196 196 return default
197 197 try:
198 198 return int(getstring(x, err))
199 199 except ValueError:
200 200 raise error.ParseError(err)
201 201
202 202 def getboolean(x, err):
203 203 value = util.parsebool(getsymbol(x))
204 204 if value is not None:
205 205 return value
206 206 raise error.ParseError(err)
207 207
208 208 def getlist(x):
209 209 if not x:
210 210 return []
211 211 if x[0] == 'list':
212 212 return list(x[1:])
213 213 return [x]
214 214
215 215 def getrange(x, err):
216 216 if not x:
217 217 raise error.ParseError(err)
218 218 op = x[0]
219 219 if op == 'range':
220 220 return x[1], x[2]
221 221 elif op == 'rangepre':
222 222 return None, x[1]
223 223 elif op == 'rangepost':
224 224 return x[1], None
225 225 elif op == 'rangeall':
226 226 return None, None
227 227 raise error.ParseError(err)
228 228
229 229 def getargs(x, min, max, err):
230 230 l = getlist(x)
231 231 if len(l) < min or (max >= 0 and len(l) > max):
232 232 raise error.ParseError(err)
233 233 return l
234 234
235 235 def getargsdict(x, funcname, keys):
236 236 return parser.buildargsdict(getlist(x), funcname, parser.splitargspec(keys),
237 237 keyvaluenode='keyvalue', keynode='symbol')
238 238
239 239 def _isnamedfunc(x, funcname):
240 240 """Check if given tree matches named function"""
241 241 return x and x[0] == 'func' and getsymbol(x[1]) == funcname
242 242
243 def _isposargs(x, n):
244 """Check if given tree is n-length list of positional arguments"""
245 l = getlist(x)
246 return len(l) == n and all(y and y[0] != 'keyvalue' for y in l)
247
243 248 def _matchnamedfunc(x, funcname):
244 249 """Return args tree if given tree matches named function; otherwise None
245 250
246 251 This can't be used for testing a nullary function since its args tree
247 252 is also None. Use _isnamedfunc() instead.
248 253 """
249 254 if not _isnamedfunc(x, funcname):
250 255 return
251 256 return x[2]
252 257
253 258 # Constants for ordering requirement, used in _analyze():
254 259 #
255 260 # If 'define', any nested functions and operations can change the ordering of
256 261 # the entries in the set. If 'follow', any nested functions and operations
257 262 # should take the ordering specified by the first operand to the '&' operator.
258 263 #
259 264 # For instance,
260 265 #
261 266 # X & (Y | Z)
262 267 # ^ ^^^^^^^
263 268 # | follow
264 269 # define
265 270 #
266 271 # will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
267 272 # of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
268 273 #
269 274 # 'any' means the order doesn't matter. For instance,
270 275 #
271 276 # X & !Y
272 277 # ^
273 278 # any
274 279 #
275 280 # 'y()' can either enforce its ordering requirement or take the ordering
276 281 # specified by 'x()' because 'not()' doesn't care the order.
277 282 #
278 283 # Transition of ordering requirement:
279 284 #
280 285 # 1. starts with 'define'
281 286 # 2. shifts to 'follow' by 'x & y'
282 287 # 3. changes back to 'define' on function call 'f(x)' or function-like
283 288 # operation 'x (f) y' because 'f' may have its own ordering requirement
284 289 # for 'x' and 'y' (e.g. 'first(x)')
285 290 #
286 291 anyorder = 'any' # don't care the order
287 292 defineorder = 'define' # should define the order
288 293 followorder = 'follow' # must follow the current order
289 294
290 295 # transition table for 'x & y', from the current expression 'x' to 'y'
291 296 _tofolloworder = {
292 297 anyorder: anyorder,
293 298 defineorder: followorder,
294 299 followorder: followorder,
295 300 }
296 301
297 302 def _matchonly(revs, bases):
298 303 """
299 304 >>> f = lambda *args: _matchonly(*map(parse, args))
300 305 >>> f('ancestors(A)', 'not ancestors(B)')
301 306 ('list', ('symbol', 'A'), ('symbol', 'B'))
302 307 """
303 308 ta = _matchnamedfunc(revs, 'ancestors')
304 309 tb = bases and bases[0] == 'not' and _matchnamedfunc(bases[1], 'ancestors')
305 if ta and tb:
310 if _isposargs(ta, 1) and _isposargs(tb, 1):
306 311 return ('list', ta, tb)
307 312
308 313 def _fixops(x):
309 314 """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be
310 315 handled well by our simple top-down parser"""
311 316 if not isinstance(x, tuple):
312 317 return x
313 318
314 319 op = x[0]
315 320 if op == 'parent':
316 321 # x^:y means (x^) : y, not x ^ (:y)
317 322 # x^: means (x^) :, not x ^ (:)
318 323 post = ('parentpost', x[1])
319 324 if x[2][0] == 'dagrangepre':
320 325 return _fixops(('dagrange', post, x[2][1]))
321 326 elif x[2][0] == 'rangepre':
322 327 return _fixops(('range', post, x[2][1]))
323 328 elif x[2][0] == 'rangeall':
324 329 return _fixops(('rangepost', post))
325 330 elif op == 'or':
326 331 # make number of arguments deterministic:
327 332 # x + y + z -> (or x y z) -> (or (list x y z))
328 333 return (op, _fixops(('list',) + x[1:]))
329 334
330 335 return (op,) + tuple(_fixops(y) for y in x[1:])
331 336
332 337 def _analyze(x, order):
333 338 if x is None:
334 339 return x
335 340
336 341 op = x[0]
337 342 if op == 'minus':
338 343 return _analyze(('and', x[1], ('not', x[2])), order)
339 344 elif op == 'only':
340 345 t = ('func', ('symbol', 'only'), ('list', x[1], x[2]))
341 346 return _analyze(t, order)
342 347 elif op == 'onlypost':
343 348 return _analyze(('func', ('symbol', 'only'), x[1]), order)
344 349 elif op == 'dagrangepre':
345 350 return _analyze(('func', ('symbol', 'ancestors'), x[1]), order)
346 351 elif op == 'dagrangepost':
347 352 return _analyze(('func', ('symbol', 'descendants'), x[1]), order)
348 353 elif op == 'negate':
349 354 s = getstring(x[1], _("can't negate that"))
350 355 return _analyze(('string', '-' + s), order)
351 356 elif op in ('string', 'symbol'):
352 357 return x
353 358 elif op == 'and':
354 359 ta = _analyze(x[1], order)
355 360 tb = _analyze(x[2], _tofolloworder[order])
356 361 return (op, ta, tb, order)
357 362 elif op == 'or':
358 363 return (op, _analyze(x[1], order), order)
359 364 elif op == 'not':
360 365 return (op, _analyze(x[1], anyorder), order)
361 366 elif op == 'rangeall':
362 367 return (op, None, order)
363 368 elif op in ('rangepre', 'rangepost', 'parentpost'):
364 369 return (op, _analyze(x[1], defineorder), order)
365 370 elif op == 'group':
366 371 return _analyze(x[1], order)
367 372 elif op in ('dagrange', 'range', 'parent', 'ancestor'):
368 373 ta = _analyze(x[1], defineorder)
369 374 tb = _analyze(x[2], defineorder)
370 375 return (op, ta, tb, order)
371 376 elif op == 'list':
372 377 return (op,) + tuple(_analyze(y, order) for y in x[1:])
373 378 elif op == 'keyvalue':
374 379 return (op, x[1], _analyze(x[2], order))
375 380 elif op == 'func':
376 381 f = getsymbol(x[1])
377 382 d = defineorder
378 383 if f == 'present':
379 384 # 'present(set)' is known to return the argument set with no
380 385 # modification, so forward the current order to its argument
381 386 d = order
382 387 return (op, x[1], _analyze(x[2], d), order)
383 388 raise ValueError('invalid operator %r' % op)
384 389
385 390 def analyze(x, order=defineorder):
386 391 """Transform raw parsed tree to evaluatable tree which can be fed to
387 392 optimize() or getset()
388 393
389 394 All pseudo operations should be mapped to real operations or functions
390 395 defined in methods or symbols table respectively.
391 396
392 397 'order' specifies how the current expression 'x' is ordered (see the
393 398 constants defined above.)
394 399 """
395 400 return _analyze(x, order)
396 401
397 402 def _optimize(x, small):
398 403 if x is None:
399 404 return 0, x
400 405
401 406 smallbonus = 1
402 407 if small:
403 408 smallbonus = .5
404 409
405 410 op = x[0]
406 411 if op in ('string', 'symbol'):
407 412 return smallbonus, x # single revisions are small
408 413 elif op == 'and':
409 414 wa, ta = _optimize(x[1], True)
410 415 wb, tb = _optimize(x[2], True)
411 416 order = x[3]
412 417 w = min(wa, wb)
413 418
414 419 # (::x and not ::y)/(not ::y and ::x) have a fast path
415 420 tm = _matchonly(ta, tb) or _matchonly(tb, ta)
416 421 if tm:
417 422 return w, ('func', ('symbol', 'only'), tm, order)
418 423
419 424 if tb is not None and tb[0] == 'not':
420 425 return wa, ('difference', ta, tb[1], order)
421 426
422 427 if wa > wb:
423 428 return w, (op, tb, ta, order)
424 429 return w, (op, ta, tb, order)
425 430 elif op == 'or':
426 431 # fast path for machine-generated expression, that is likely to have
427 432 # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
428 433 order = x[2]
429 434 ws, ts, ss = [], [], []
430 435 def flushss():
431 436 if not ss:
432 437 return
433 438 if len(ss) == 1:
434 439 w, t = ss[0]
435 440 else:
436 441 s = '\0'.join(t[1] for w, t in ss)
437 442 y = ('func', ('symbol', '_list'), ('string', s), order)
438 443 w, t = _optimize(y, False)
439 444 ws.append(w)
440 445 ts.append(t)
441 446 del ss[:]
442 447 for y in getlist(x[1]):
443 448 w, t = _optimize(y, False)
444 449 if t is not None and (t[0] == 'string' or t[0] == 'symbol'):
445 450 ss.append((w, t))
446 451 continue
447 452 flushss()
448 453 ws.append(w)
449 454 ts.append(t)
450 455 flushss()
451 456 if len(ts) == 1:
452 457 return ws[0], ts[0] # 'or' operation is fully optimized out
453 458 if order != defineorder:
454 459 # reorder by weight only when f(a + b) == f(b + a)
455 460 ts = [wt[1] for wt in sorted(zip(ws, ts), key=lambda wt: wt[0])]
456 461 return max(ws), (op, ('list',) + tuple(ts), order)
457 462 elif op == 'not':
458 463 # Optimize not public() to _notpublic() because we have a fast version
459 464 if x[1][:3] == ('func', ('symbol', 'public'), None):
460 465 order = x[1][3]
461 466 newsym = ('func', ('symbol', '_notpublic'), None, order)
462 467 o = _optimize(newsym, not small)
463 468 return o[0], o[1]
464 469 else:
465 470 o = _optimize(x[1], not small)
466 471 order = x[2]
467 472 return o[0], (op, o[1], order)
468 473 elif op == 'rangeall':
469 474 return smallbonus, x
470 475 elif op in ('rangepre', 'rangepost', 'parentpost'):
471 476 o = _optimize(x[1], small)
472 477 order = x[2]
473 478 return o[0], (op, o[1], order)
474 479 elif op in ('dagrange', 'range', 'parent', 'ancestor'):
475 480 wa, ta = _optimize(x[1], small)
476 481 wb, tb = _optimize(x[2], small)
477 482 order = x[3]
478 483 return wa + wb, (op, ta, tb, order)
479 484 elif op == 'list':
480 485 ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
481 486 return sum(ws), (op,) + ts
482 487 elif op == 'keyvalue':
483 488 w, t = _optimize(x[2], small)
484 489 return w, (op, x[1], t)
485 490 elif op == 'func':
486 491 f = getsymbol(x[1])
487 492 wa, ta = _optimize(x[2], small)
488 493 if f in ('author', 'branch', 'closed', 'date', 'desc', 'file', 'grep',
489 494 'keyword', 'outgoing', 'user', 'destination'):
490 495 w = 10 # slow
491 496 elif f in ('modifies', 'adds', 'removes'):
492 497 w = 30 # slower
493 498 elif f == "contains":
494 499 w = 100 # very slow
495 500 elif f == "ancestor":
496 501 w = 1 * smallbonus
497 502 elif f in ('reverse', 'limit', 'first', 'wdir', '_intlist'):
498 503 w = 0
499 504 elif f == "sort":
500 505 w = 10 # assume most sorts look at changelog
501 506 else:
502 507 w = 1
503 508 order = x[3]
504 509 return w + wa, (op, x[1], ta, order)
505 510 raise ValueError('invalid operator %r' % op)
506 511
507 512 def optimize(tree):
508 513 """Optimize evaluatable tree
509 514
510 515 All pseudo operations should be transformed beforehand.
511 516 """
512 517 _weight, newtree = _optimize(tree, small=True)
513 518 return newtree
514 519
515 520 # the set of valid characters for the initial letter of symbols in
516 521 # alias declarations and definitions
517 522 _aliassyminitletters = _syminitletters | set(pycompat.sysstr('$'))
518 523
519 524 def _parsewith(spec, lookup=None, syminitletters=None):
520 525 """Generate a parse tree of given spec with given tokenizing options
521 526
522 527 >>> _parsewith('foo($1)', syminitletters=_aliassyminitletters)
523 528 ('func', ('symbol', 'foo'), ('symbol', '$1'))
524 529 >>> _parsewith('$1')
525 530 Traceback (most recent call last):
526 531 ...
527 532 ParseError: ("syntax error in revset '$1'", 0)
528 533 >>> _parsewith('foo bar')
529 534 Traceback (most recent call last):
530 535 ...
531 536 ParseError: ('invalid token', 4)
532 537 """
533 538 p = parser.parser(elements)
534 539 tree, pos = p.parse(tokenize(spec, lookup=lookup,
535 540 syminitletters=syminitletters))
536 541 if pos != len(spec):
537 542 raise error.ParseError(_('invalid token'), pos)
538 543 return _fixops(parser.simplifyinfixops(tree, ('list', 'or')))
539 544
540 545 class _aliasrules(parser.basealiasrules):
541 546 """Parsing and expansion rule set of revset aliases"""
542 547 _section = _('revset alias')
543 548
544 549 @staticmethod
545 550 def _parse(spec):
546 551 """Parse alias declaration/definition ``spec``
547 552
548 553 This allows symbol names to use also ``$`` as an initial letter
549 554 (for backward compatibility), and callers of this function should
550 555 examine whether ``$`` is used also for unexpected symbols or not.
551 556 """
552 557 return _parsewith(spec, syminitletters=_aliassyminitletters)
553 558
554 559 @staticmethod
555 560 def _trygetfunc(tree):
556 561 if tree[0] == 'func' and tree[1][0] == 'symbol':
557 562 return tree[1][1], getlist(tree[2])
558 563
559 564 def expandaliases(ui, tree):
560 565 aliases = _aliasrules.buildmap(ui.configitems('revsetalias'))
561 566 tree = _aliasrules.expand(aliases, tree)
562 567 # warn about problematic (but not referred) aliases
563 568 for name, alias in sorted(aliases.iteritems()):
564 569 if alias.error and not alias.warned:
565 570 ui.warn(_('warning: %s\n') % (alias.error))
566 571 alias.warned = True
567 572 return tree
568 573
569 574 def foldconcat(tree):
570 575 """Fold elements to be concatenated by `##`
571 576 """
572 577 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
573 578 return tree
574 579 if tree[0] == '_concat':
575 580 pending = [tree]
576 581 l = []
577 582 while pending:
578 583 e = pending.pop()
579 584 if e[0] == '_concat':
580 585 pending.extend(reversed(e[1:]))
581 586 elif e[0] in ('string', 'symbol'):
582 587 l.append(e[1])
583 588 else:
584 589 msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
585 590 raise error.ParseError(msg)
586 591 return ('string', ''.join(l))
587 592 else:
588 593 return tuple(foldconcat(t) for t in tree)
589 594
590 595 def parse(spec, lookup=None):
591 596 return _parsewith(spec, lookup=lookup)
592 597
593 598 def _quote(s):
594 599 r"""Quote a value in order to make it safe for the revset engine.
595 600
596 601 >>> _quote('asdf')
597 602 "'asdf'"
598 603 >>> _quote("asdf'\"")
599 604 '\'asdf\\\'"\''
600 605 >>> _quote('asdf\'')
601 606 "'asdf\\''"
602 607 >>> _quote(1)
603 608 "'1'"
604 609 """
605 610 return "'%s'" % util.escapestr(pycompat.bytestr(s))
606 611
607 612 def formatspec(expr, *args):
608 613 '''
609 614 This is a convenience function for using revsets internally, and
610 615 escapes arguments appropriately. Aliases are intentionally ignored
611 616 so that intended expression behavior isn't accidentally subverted.
612 617
613 618 Supported arguments:
614 619
615 620 %r = revset expression, parenthesized
616 621 %d = int(arg), no quoting
617 622 %s = string(arg), escaped and single-quoted
618 623 %b = arg.branch(), escaped and single-quoted
619 624 %n = hex(arg), single-quoted
620 625 %% = a literal '%'
621 626
622 627 Prefixing the type with 'l' specifies a parenthesized list of that type.
623 628
624 629 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
625 630 '(10 or 11):: and ((this()) or (that()))'
626 631 >>> formatspec('%d:: and not %d::', 10, 20)
627 632 '10:: and not 20::'
628 633 >>> formatspec('%ld or %ld', [], [1])
629 634 "_list('') or 1"
630 635 >>> formatspec('keyword(%s)', 'foo\\xe9')
631 636 "keyword('foo\\\\xe9')"
632 637 >>> b = lambda: 'default'
633 638 >>> b.branch = b
634 639 >>> formatspec('branch(%b)', b)
635 640 "branch('default')"
636 641 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
637 642 "root(_list('a\\x00b\\x00c\\x00d'))"
638 643 '''
639 644
640 645 def argtype(c, arg):
641 646 if c == 'd':
642 647 return '%d' % int(arg)
643 648 elif c == 's':
644 649 return _quote(arg)
645 650 elif c == 'r':
646 651 parse(arg) # make sure syntax errors are confined
647 652 return '(%s)' % arg
648 653 elif c == 'n':
649 654 return _quote(node.hex(arg))
650 655 elif c == 'b':
651 656 return _quote(arg.branch())
652 657
653 658 def listexp(s, t):
654 659 l = len(s)
655 660 if l == 0:
656 661 return "_list('')"
657 662 elif l == 1:
658 663 return argtype(t, s[0])
659 664 elif t == 'd':
660 665 return "_intlist('%s')" % "\0".join('%d' % int(a) for a in s)
661 666 elif t == 's':
662 667 return "_list('%s')" % "\0".join(s)
663 668 elif t == 'n':
664 669 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
665 670 elif t == 'b':
666 671 return "_list('%s')" % "\0".join(a.branch() for a in s)
667 672
668 673 m = l // 2
669 674 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
670 675
671 676 expr = pycompat.bytestr(expr)
672 677 ret = ''
673 678 pos = 0
674 679 arg = 0
675 680 while pos < len(expr):
676 681 c = expr[pos]
677 682 if c == '%':
678 683 pos += 1
679 684 d = expr[pos]
680 685 if d == '%':
681 686 ret += d
682 687 elif d in 'dsnbr':
683 688 ret += argtype(d, args[arg])
684 689 arg += 1
685 690 elif d == 'l':
686 691 # a list of some type
687 692 pos += 1
688 693 d = expr[pos]
689 694 ret += listexp(list(args[arg]), d)
690 695 arg += 1
691 696 else:
692 697 raise error.Abort(_('unexpected revspec format character %s')
693 698 % d)
694 699 else:
695 700 ret += c
696 701 pos += 1
697 702
698 703 return ret
699 704
700 705 def prettyformat(tree):
701 706 return parser.prettyformat(tree, ('string', 'symbol'))
702 707
703 708 def depth(tree):
704 709 if isinstance(tree, tuple):
705 710 return max(map(depth, tree)) + 1
706 711 else:
707 712 return 0
708 713
709 714 def funcsused(tree):
710 715 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
711 716 return set()
712 717 else:
713 718 funcs = set()
714 719 for s in tree[1:]:
715 720 funcs |= funcsused(s)
716 721 if tree[0] == 'func':
717 722 funcs.add(tree[1][1])
718 723 return funcs
@@ -1,4014 +1,4073
1 1 $ HGENCODING=utf-8
2 2 $ export HGENCODING
3 3 $ cat > testrevset.py << EOF
4 4 > import mercurial.revset
5 5 >
6 6 > baseset = mercurial.revset.baseset
7 7 >
8 8 > def r3232(repo, subset, x):
9 9 > """"simple revset that return [3,2,3,2]
10 10 >
11 11 > revisions duplicated on purpose.
12 12 > """
13 13 > if 3 not in subset:
14 14 > if 2 in subset:
15 15 > return baseset([2,2])
16 16 > return baseset()
17 17 > return baseset([3,3,2,2])
18 18 >
19 19 > mercurial.revset.symbols['r3232'] = r3232
20 20 > EOF
21 21 $ cat >> $HGRCPATH << EOF
22 22 > [extensions]
23 23 > testrevset=$TESTTMP/testrevset.py
24 24 > EOF
25 25
26 26 $ try() {
27 27 > hg debugrevspec --debug "$@"
28 28 > }
29 29
30 30 $ log() {
31 31 > hg log --template '{rev}\n' -r "$1"
32 32 > }
33 33
34 34 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 35 these predicates use '\0' as a separator:
36 36
37 37 $ cat <<EOF > debugrevlistspec.py
38 38 > from __future__ import absolute_import
39 39 > from mercurial import (
40 40 > node as nodemod,
41 41 > registrar,
42 42 > revset,
43 43 > revsetlang,
44 44 > smartset,
45 45 > )
46 46 > cmdtable = {}
47 47 > command = registrar.command(cmdtable)
48 48 > @command('debugrevlistspec',
49 49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
50 50 > ('', 'bin', None, 'unhexlify arguments')])
51 51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
52 52 > if opts['bin']:
53 53 > args = map(nodemod.bin, args)
54 54 > expr = revsetlang.formatspec(fmt, list(args))
55 55 > if ui.verbose:
56 56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
57 57 > ui.note(revsetlang.prettyformat(tree), "\n")
58 58 > if opts["optimize"]:
59 59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
60 60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
61 61 > "\n")
62 62 > func = revset.match(ui, expr, repo)
63 63 > revs = func(repo)
64 64 > if ui.verbose:
65 65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
66 66 > for c in revs:
67 67 > ui.write("%s\n" % c)
68 68 > EOF
69 69 $ cat <<EOF >> $HGRCPATH
70 70 > [extensions]
71 71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
72 72 > EOF
73 73 $ trylist() {
74 74 > hg debugrevlistspec --debug "$@"
75 75 > }
76 76
77 77 $ hg init repo
78 78 $ cd repo
79 79
80 80 $ echo a > a
81 81 $ hg branch a
82 82 marked working directory as branch a
83 83 (branches are permanent and global, did you want a bookmark?)
84 84 $ hg ci -Aqm0
85 85
86 86 $ echo b > b
87 87 $ hg branch b
88 88 marked working directory as branch b
89 89 $ hg ci -Aqm1
90 90
91 91 $ rm a
92 92 $ hg branch a-b-c-
93 93 marked working directory as branch a-b-c-
94 94 $ hg ci -Aqm2 -u Bob
95 95
96 96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
97 97 2
98 98 $ hg log -r "extra('branch')" --template '{rev}\n'
99 99 0
100 100 1
101 101 2
102 102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
103 103 0 a
104 104 2 a-b-c-
105 105
106 106 $ hg co 1
107 107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 108 $ hg branch +a+b+c+
109 109 marked working directory as branch +a+b+c+
110 110 $ hg ci -Aqm3
111 111
112 112 $ hg co 2 # interleave
113 113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 114 $ echo bb > b
115 115 $ hg branch -- -a-b-c-
116 116 marked working directory as branch -a-b-c-
117 117 $ hg ci -Aqm4 -d "May 12 2005"
118 118
119 119 $ hg co 3
120 120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 121 $ hg branch !a/b/c/
122 122 marked working directory as branch !a/b/c/
123 123 $ hg ci -Aqm"5 bug"
124 124
125 125 $ hg merge 4
126 126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 127 (branch merge, don't forget to commit)
128 128 $ hg branch _a_b_c_
129 129 marked working directory as branch _a_b_c_
130 130 $ hg ci -Aqm"6 issue619"
131 131
132 132 $ hg branch .a.b.c.
133 133 marked working directory as branch .a.b.c.
134 134 $ hg ci -Aqm7
135 135
136 136 $ hg branch all
137 137 marked working directory as branch all
138 138
139 139 $ hg co 4
140 140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 141 $ hg branch Γ©
142 142 marked working directory as branch \xc3\xa9 (esc)
143 143 $ hg ci -Aqm9
144 144
145 145 $ hg tag -r6 1.0
146 146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
147 147
148 148 $ hg clone --quiet -U -r 7 . ../remote1
149 149 $ hg clone --quiet -U -r 8 . ../remote2
150 150 $ echo "[paths]" >> .hg/hgrc
151 151 $ echo "default = ../remote1" >> .hg/hgrc
152 152
153 153 trivial
154 154
155 155 $ try 0:1
156 156 (range
157 157 ('symbol', '0')
158 158 ('symbol', '1'))
159 159 * set:
160 160 <spanset+ 0:2>
161 161 0
162 162 1
163 163 $ try --optimize :
164 164 (rangeall
165 165 None)
166 166 * optimized:
167 167 (rangeall
168 168 None
169 169 define)
170 170 * set:
171 171 <spanset+ 0:10>
172 172 0
173 173 1
174 174 2
175 175 3
176 176 4
177 177 5
178 178 6
179 179 7
180 180 8
181 181 9
182 182 $ try 3::6
183 183 (dagrange
184 184 ('symbol', '3')
185 185 ('symbol', '6'))
186 186 * set:
187 187 <baseset+ [3, 5, 6]>
188 188 3
189 189 5
190 190 6
191 191 $ try '0|1|2'
192 192 (or
193 193 (list
194 194 ('symbol', '0')
195 195 ('symbol', '1')
196 196 ('symbol', '2')))
197 197 * set:
198 198 <baseset [0, 1, 2]>
199 199 0
200 200 1
201 201 2
202 202
203 203 names that should work without quoting
204 204
205 205 $ try a
206 206 ('symbol', 'a')
207 207 * set:
208 208 <baseset [0]>
209 209 0
210 210 $ try b-a
211 211 (minus
212 212 ('symbol', 'b')
213 213 ('symbol', 'a'))
214 214 * set:
215 215 <filteredset
216 216 <baseset [1]>,
217 217 <not
218 218 <baseset [0]>>>
219 219 1
220 220 $ try _a_b_c_
221 221 ('symbol', '_a_b_c_')
222 222 * set:
223 223 <baseset [6]>
224 224 6
225 225 $ try _a_b_c_-a
226 226 (minus
227 227 ('symbol', '_a_b_c_')
228 228 ('symbol', 'a'))
229 229 * set:
230 230 <filteredset
231 231 <baseset [6]>,
232 232 <not
233 233 <baseset [0]>>>
234 234 6
235 235 $ try .a.b.c.
236 236 ('symbol', '.a.b.c.')
237 237 * set:
238 238 <baseset [7]>
239 239 7
240 240 $ try .a.b.c.-a
241 241 (minus
242 242 ('symbol', '.a.b.c.')
243 243 ('symbol', 'a'))
244 244 * set:
245 245 <filteredset
246 246 <baseset [7]>,
247 247 <not
248 248 <baseset [0]>>>
249 249 7
250 250
251 251 names that should be caught by fallback mechanism
252 252
253 253 $ try -- '-a-b-c-'
254 254 ('symbol', '-a-b-c-')
255 255 * set:
256 256 <baseset [4]>
257 257 4
258 258 $ log -a-b-c-
259 259 4
260 260 $ try '+a+b+c+'
261 261 ('symbol', '+a+b+c+')
262 262 * set:
263 263 <baseset [3]>
264 264 3
265 265 $ try '+a+b+c+:'
266 266 (rangepost
267 267 ('symbol', '+a+b+c+'))
268 268 * set:
269 269 <spanset+ 3:10>
270 270 3
271 271 4
272 272 5
273 273 6
274 274 7
275 275 8
276 276 9
277 277 $ try ':+a+b+c+'
278 278 (rangepre
279 279 ('symbol', '+a+b+c+'))
280 280 * set:
281 281 <spanset+ 0:4>
282 282 0
283 283 1
284 284 2
285 285 3
286 286 $ try -- '-a-b-c-:+a+b+c+'
287 287 (range
288 288 ('symbol', '-a-b-c-')
289 289 ('symbol', '+a+b+c+'))
290 290 * set:
291 291 <spanset- 3:5>
292 292 4
293 293 3
294 294 $ log '-a-b-c-:+a+b+c+'
295 295 4
296 296 3
297 297
298 298 $ try -- -a-b-c--a # complains
299 299 (minus
300 300 (minus
301 301 (minus
302 302 (negate
303 303 ('symbol', 'a'))
304 304 ('symbol', 'b'))
305 305 ('symbol', 'c'))
306 306 (negate
307 307 ('symbol', 'a')))
308 308 abort: unknown revision '-a'!
309 309 [255]
310 310 $ try Γ©
311 311 ('symbol', '\xc3\xa9')
312 312 * set:
313 313 <baseset [9]>
314 314 9
315 315
316 316 no quoting needed
317 317
318 318 $ log ::a-b-c-
319 319 0
320 320 1
321 321 2
322 322
323 323 quoting needed
324 324
325 325 $ try '"-a-b-c-"-a'
326 326 (minus
327 327 ('string', '-a-b-c-')
328 328 ('symbol', 'a'))
329 329 * set:
330 330 <filteredset
331 331 <baseset [4]>,
332 332 <not
333 333 <baseset [0]>>>
334 334 4
335 335
336 336 $ log '1 or 2'
337 337 1
338 338 2
339 339 $ log '1|2'
340 340 1
341 341 2
342 342 $ log '1 and 2'
343 343 $ log '1&2'
344 344 $ try '1&2|3' # precedence - and is higher
345 345 (or
346 346 (list
347 347 (and
348 348 ('symbol', '1')
349 349 ('symbol', '2'))
350 350 ('symbol', '3')))
351 351 * set:
352 352 <addset
353 353 <baseset []>,
354 354 <baseset [3]>>
355 355 3
356 356 $ try '1|2&3'
357 357 (or
358 358 (list
359 359 ('symbol', '1')
360 360 (and
361 361 ('symbol', '2')
362 362 ('symbol', '3'))))
363 363 * set:
364 364 <addset
365 365 <baseset [1]>,
366 366 <baseset []>>
367 367 1
368 368 $ try '1&2&3' # associativity
369 369 (and
370 370 (and
371 371 ('symbol', '1')
372 372 ('symbol', '2'))
373 373 ('symbol', '3'))
374 374 * set:
375 375 <baseset []>
376 376 $ try '1|(2|3)'
377 377 (or
378 378 (list
379 379 ('symbol', '1')
380 380 (group
381 381 (or
382 382 (list
383 383 ('symbol', '2')
384 384 ('symbol', '3'))))))
385 385 * set:
386 386 <addset
387 387 <baseset [1]>,
388 388 <baseset [2, 3]>>
389 389 1
390 390 2
391 391 3
392 392 $ log '1.0' # tag
393 393 6
394 394 $ log 'a' # branch
395 395 0
396 396 $ log '2785f51ee'
397 397 0
398 398 $ log 'date(2005)'
399 399 4
400 400 $ log 'date(this is a test)'
401 401 hg: parse error at 10: unexpected token: symbol
402 402 [255]
403 403 $ log 'date()'
404 404 hg: parse error: date requires a string
405 405 [255]
406 406 $ log 'date'
407 407 abort: unknown revision 'date'!
408 408 [255]
409 409 $ log 'date('
410 410 hg: parse error at 5: not a prefix: end
411 411 [255]
412 412 $ log 'date("\xy")'
413 413 hg: parse error: invalid \x escape
414 414 [255]
415 415 $ log 'date(tip)'
416 416 hg: parse error: invalid date: 'tip'
417 417 [255]
418 418 $ log '0:date'
419 419 abort: unknown revision 'date'!
420 420 [255]
421 421 $ log '::"date"'
422 422 abort: unknown revision 'date'!
423 423 [255]
424 424 $ hg book date -r 4
425 425 $ log '0:date'
426 426 0
427 427 1
428 428 2
429 429 3
430 430 4
431 431 $ log '::date'
432 432 0
433 433 1
434 434 2
435 435 4
436 436 $ log '::"date"'
437 437 0
438 438 1
439 439 2
440 440 4
441 441 $ log 'date(2005) and 1::'
442 442 4
443 443 $ hg book -d date
444 444
445 445 function name should be a symbol
446 446
447 447 $ log '"date"(2005)'
448 448 hg: parse error: not a symbol
449 449 [255]
450 450
451 451 keyword arguments
452 452
453 453 $ log 'extra(branch, value=a)'
454 454 0
455 455
456 456 $ log 'extra(branch, a, b)'
457 457 hg: parse error: extra takes at most 2 positional arguments
458 458 [255]
459 459 $ log 'extra(a, label=b)'
460 460 hg: parse error: extra got multiple values for keyword argument 'label'
461 461 [255]
462 462 $ log 'extra(label=branch, default)'
463 463 hg: parse error: extra got an invalid argument
464 464 [255]
465 465 $ log 'extra(branch, foo+bar=baz)'
466 466 hg: parse error: extra got an invalid argument
467 467 [255]
468 468 $ log 'extra(unknown=branch)'
469 469 hg: parse error: extra got an unexpected keyword argument 'unknown'
470 470 [255]
471 471
472 472 $ try 'foo=bar|baz'
473 473 (keyvalue
474 474 ('symbol', 'foo')
475 475 (or
476 476 (list
477 477 ('symbol', 'bar')
478 478 ('symbol', 'baz'))))
479 479 hg: parse error: can't use a key-value pair in this context
480 480 [255]
481 481
482 482 right-hand side should be optimized recursively
483 483
484 484 $ try --optimize 'foo=(not public())'
485 485 (keyvalue
486 486 ('symbol', 'foo')
487 487 (group
488 488 (not
489 489 (func
490 490 ('symbol', 'public')
491 491 None))))
492 492 * optimized:
493 493 (keyvalue
494 494 ('symbol', 'foo')
495 495 (func
496 496 ('symbol', '_notpublic')
497 497 None
498 498 any))
499 499 hg: parse error: can't use a key-value pair in this context
500 500 [255]
501 501
502 502 parsed tree at stages:
503 503
504 504 $ hg debugrevspec -p all '()'
505 505 * parsed:
506 506 (group
507 507 None)
508 508 * expanded:
509 509 (group
510 510 None)
511 511 * concatenated:
512 512 (group
513 513 None)
514 514 * analyzed:
515 515 None
516 516 * optimized:
517 517 None
518 518 hg: parse error: missing argument
519 519 [255]
520 520
521 521 $ hg debugrevspec --no-optimized -p all '()'
522 522 * parsed:
523 523 (group
524 524 None)
525 525 * expanded:
526 526 (group
527 527 None)
528 528 * concatenated:
529 529 (group
530 530 None)
531 531 * analyzed:
532 532 None
533 533 hg: parse error: missing argument
534 534 [255]
535 535
536 536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
537 537 * parsed:
538 538 (minus
539 539 (group
540 540 (or
541 541 (list
542 542 ('symbol', '0')
543 543 ('symbol', '1'))))
544 544 ('symbol', '1'))
545 545 * analyzed:
546 546 (and
547 547 (or
548 548 (list
549 549 ('symbol', '0')
550 550 ('symbol', '1'))
551 551 define)
552 552 (not
553 553 ('symbol', '1')
554 554 follow)
555 555 define)
556 556 * optimized:
557 557 (difference
558 558 (func
559 559 ('symbol', '_list')
560 560 ('string', '0\x001')
561 561 define)
562 562 ('symbol', '1')
563 563 define)
564 564 0
565 565
566 566 $ hg debugrevspec -p unknown '0'
567 567 abort: invalid stage name: unknown
568 568 [255]
569 569
570 570 $ hg debugrevspec -p all --optimize '0'
571 571 abort: cannot use --optimize with --show-stage
572 572 [255]
573 573
574 574 verify optimized tree:
575 575
576 576 $ hg debugrevspec --verify '0|1'
577 577
578 578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
579 579 * analyzed:
580 580 (and
581 581 (func
582 582 ('symbol', 'r3232')
583 583 None
584 584 define)
585 585 ('symbol', '2')
586 586 define)
587 587 * optimized:
588 588 (and
589 589 ('symbol', '2')
590 590 (func
591 591 ('symbol', 'r3232')
592 592 None
593 593 define)
594 594 define)
595 595 * analyzed set:
596 596 <baseset [2]>
597 597 * optimized set:
598 598 <baseset [2, 2]>
599 599 --- analyzed
600 600 +++ optimized
601 601 2
602 602 +2
603 603 [1]
604 604
605 605 $ hg debugrevspec --no-optimized --verify-optimized '0'
606 606 abort: cannot use --verify-optimized with --no-optimized
607 607 [255]
608 608
609 609 Test that symbols only get parsed as functions if there's an opening
610 610 parenthesis.
611 611
612 612 $ hg book only -r 9
613 613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
614 614 8
615 615 9
616 616
617 617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
618 618 may be hidden (issue5385)
619 619
620 620 $ try -p parsed -p analyzed ':'
621 621 * parsed:
622 622 (rangeall
623 623 None)
624 624 * analyzed:
625 625 (rangeall
626 626 None
627 627 define)
628 628 * set:
629 629 <spanset+ 0:10>
630 630 0
631 631 1
632 632 2
633 633 3
634 634 4
635 635 5
636 636 6
637 637 7
638 638 8
639 639 9
640 640 $ try -p analyzed ':1'
641 641 * analyzed:
642 642 (rangepre
643 643 ('symbol', '1')
644 644 define)
645 645 * set:
646 646 <spanset+ 0:2>
647 647 0
648 648 1
649 649 $ try -p analyzed ':(1|2)'
650 650 * analyzed:
651 651 (rangepre
652 652 (or
653 653 (list
654 654 ('symbol', '1')
655 655 ('symbol', '2'))
656 656 define)
657 657 define)
658 658 * set:
659 659 <spanset+ 0:3>
660 660 0
661 661 1
662 662 2
663 663 $ try -p analyzed ':(1&2)'
664 664 * analyzed:
665 665 (rangepre
666 666 (and
667 667 ('symbol', '1')
668 668 ('symbol', '2')
669 669 define)
670 670 define)
671 671 * set:
672 672 <baseset []>
673 673
674 674 infix/suffix resolution of ^ operator (issue2884):
675 675
676 676 x^:y means (x^):y
677 677
678 678 $ try '1^:2'
679 679 (range
680 680 (parentpost
681 681 ('symbol', '1'))
682 682 ('symbol', '2'))
683 683 * set:
684 684 <spanset+ 0:3>
685 685 0
686 686 1
687 687 2
688 688
689 689 $ try '1^::2'
690 690 (dagrange
691 691 (parentpost
692 692 ('symbol', '1'))
693 693 ('symbol', '2'))
694 694 * set:
695 695 <baseset+ [0, 1, 2]>
696 696 0
697 697 1
698 698 2
699 699
700 700 $ try '9^:'
701 701 (rangepost
702 702 (parentpost
703 703 ('symbol', '9')))
704 704 * set:
705 705 <spanset+ 8:10>
706 706 8
707 707 9
708 708
709 709 x^:y should be resolved before omitting group operators
710 710
711 711 $ try '1^(:2)'
712 712 (parent
713 713 ('symbol', '1')
714 714 (group
715 715 (rangepre
716 716 ('symbol', '2'))))
717 717 hg: parse error: ^ expects a number 0, 1, or 2
718 718 [255]
719 719
720 720 x^:y should be resolved recursively
721 721
722 722 $ try 'sort(1^:2)'
723 723 (func
724 724 ('symbol', 'sort')
725 725 (range
726 726 (parentpost
727 727 ('symbol', '1'))
728 728 ('symbol', '2')))
729 729 * set:
730 730 <spanset+ 0:3>
731 731 0
732 732 1
733 733 2
734 734
735 735 $ try '(3^:4)^:2'
736 736 (range
737 737 (parentpost
738 738 (group
739 739 (range
740 740 (parentpost
741 741 ('symbol', '3'))
742 742 ('symbol', '4'))))
743 743 ('symbol', '2'))
744 744 * set:
745 745 <spanset+ 0:3>
746 746 0
747 747 1
748 748 2
749 749
750 750 $ try '(3^::4)^::2'
751 751 (dagrange
752 752 (parentpost
753 753 (group
754 754 (dagrange
755 755 (parentpost
756 756 ('symbol', '3'))
757 757 ('symbol', '4'))))
758 758 ('symbol', '2'))
759 759 * set:
760 760 <baseset+ [0, 1, 2]>
761 761 0
762 762 1
763 763 2
764 764
765 765 $ try '(9^:)^:'
766 766 (rangepost
767 767 (parentpost
768 768 (group
769 769 (rangepost
770 770 (parentpost
771 771 ('symbol', '9'))))))
772 772 * set:
773 773 <spanset+ 4:10>
774 774 4
775 775 5
776 776 6
777 777 7
778 778 8
779 779 9
780 780
781 781 x^ in alias should also be resolved
782 782
783 783 $ try 'A' --config 'revsetalias.A=1^:2'
784 784 ('symbol', 'A')
785 785 * expanded:
786 786 (range
787 787 (parentpost
788 788 ('symbol', '1'))
789 789 ('symbol', '2'))
790 790 * set:
791 791 <spanset+ 0:3>
792 792 0
793 793 1
794 794 2
795 795
796 796 $ try 'A:2' --config 'revsetalias.A=1^'
797 797 (range
798 798 ('symbol', 'A')
799 799 ('symbol', '2'))
800 800 * expanded:
801 801 (range
802 802 (parentpost
803 803 ('symbol', '1'))
804 804 ('symbol', '2'))
805 805 * set:
806 806 <spanset+ 0:3>
807 807 0
808 808 1
809 809 2
810 810
811 811 but not beyond the boundary of alias expansion, because the resolution should
812 812 be made at the parsing stage
813 813
814 814 $ try '1^A' --config 'revsetalias.A=:2'
815 815 (parent
816 816 ('symbol', '1')
817 817 ('symbol', 'A'))
818 818 * expanded:
819 819 (parent
820 820 ('symbol', '1')
821 821 (rangepre
822 822 ('symbol', '2')))
823 823 hg: parse error: ^ expects a number 0, 1, or 2
824 824 [255]
825 825
826 826 ancestor can accept 0 or more arguments
827 827
828 828 $ log 'ancestor()'
829 829 $ log 'ancestor(1)'
830 830 1
831 831 $ log 'ancestor(4,5)'
832 832 1
833 833 $ log 'ancestor(4,5) and 4'
834 834 $ log 'ancestor(0,0,1,3)'
835 835 0
836 836 $ log 'ancestor(3,1,5,3,5,1)'
837 837 1
838 838 $ log 'ancestor(0,1,3,5)'
839 839 0
840 840 $ log 'ancestor(1,2,3,4,5)'
841 841 1
842 842
843 843 test ancestors
844 844
845 845 $ log 'ancestors(5)'
846 846 0
847 847 1
848 848 3
849 849 5
850 850 $ log 'ancestor(ancestors(5))'
851 851 0
852 852 $ log '::r3232()'
853 853 0
854 854 1
855 855 2
856 856 3
857 857
858 858 $ log 'author(bob)'
859 859 2
860 860 $ log 'author("re:bob|test")'
861 861 0
862 862 1
863 863 2
864 864 3
865 865 4
866 866 5
867 867 6
868 868 7
869 869 8
870 870 9
871 871 $ log 'author(r"re:\S")'
872 872 0
873 873 1
874 874 2
875 875 3
876 876 4
877 877 5
878 878 6
879 879 7
880 880 8
881 881 9
882 882 $ log 'branch(Γ©)'
883 883 8
884 884 9
885 885 $ log 'branch(a)'
886 886 0
887 887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
888 888 0 a
889 889 2 a-b-c-
890 890 3 +a+b+c+
891 891 4 -a-b-c-
892 892 5 !a/b/c/
893 893 6 _a_b_c_
894 894 7 .a.b.c.
895 895 $ log 'children(ancestor(4,5))'
896 896 2
897 897 3
898 898
899 899 $ log 'children(4)'
900 900 6
901 901 8
902 902 $ log 'children(null)'
903 903 0
904 904
905 905 $ log 'closed()'
906 906 $ log 'contains(a)'
907 907 0
908 908 1
909 909 3
910 910 5
911 911 $ log 'contains("../repo/a")'
912 912 0
913 913 1
914 914 3
915 915 5
916 916 $ log 'desc(B)'
917 917 5
918 918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
919 919 5 5 bug
920 920 6 6 issue619
921 921 $ log 'descendants(2 or 3)'
922 922 2
923 923 3
924 924 4
925 925 5
926 926 6
927 927 7
928 928 8
929 929 9
930 930 $ log 'file("b*")'
931 931 1
932 932 4
933 933 $ log 'filelog("b")'
934 934 1
935 935 4
936 936 $ log 'filelog("../repo/b")'
937 937 1
938 938 4
939 939 $ log 'follow()'
940 940 0
941 941 1
942 942 2
943 943 4
944 944 8
945 945 9
946 946 $ log 'grep("issue\d+")'
947 947 6
948 948 $ try 'grep("(")' # invalid regular expression
949 949 (func
950 950 ('symbol', 'grep')
951 951 ('string', '('))
952 952 hg: parse error: invalid match pattern: unbalanced parenthesis
953 953 [255]
954 954 $ try 'grep("\bissue\d+")'
955 955 (func
956 956 ('symbol', 'grep')
957 957 ('string', '\x08issue\\d+'))
958 958 * set:
959 959 <filteredset
960 960 <fullreposet+ 0:10>,
961 961 <grep '\x08issue\\d+'>>
962 962 $ try 'grep(r"\bissue\d+")'
963 963 (func
964 964 ('symbol', 'grep')
965 965 ('string', '\\bissue\\d+'))
966 966 * set:
967 967 <filteredset
968 968 <fullreposet+ 0:10>,
969 969 <grep '\\bissue\\d+'>>
970 970 6
971 971 $ try 'grep(r"\")'
972 972 hg: parse error at 7: unterminated string
973 973 [255]
974 974 $ log 'head()'
975 975 0
976 976 1
977 977 2
978 978 3
979 979 4
980 980 5
981 981 6
982 982 7
983 983 9
984 984 $ log 'heads(6::)'
985 985 7
986 986 $ log 'keyword(issue)'
987 987 6
988 988 $ log 'keyword("test a")'
989 989
990 990 Test first (=limit) and last
991 991
992 992 $ log 'limit(head(), 1)'
993 993 0
994 994 $ log 'limit(author("re:bob|test"), 3, 5)'
995 995 5
996 996 6
997 997 7
998 998 $ log 'limit(author("re:bob|test"), offset=6)'
999 999 6
1000 1000 $ log 'limit(author("re:bob|test"), offset=10)'
1001 1001 $ log 'limit(all(), 1, -1)'
1002 1002 hg: parse error: negative offset
1003 1003 [255]
1004 1004 $ log 'limit(all(), -1)'
1005 1005 hg: parse error: negative number to select
1006 1006 [255]
1007 1007 $ log 'limit(all(), 0)'
1008 1008
1009 1009 $ log 'last(all(), -1)'
1010 1010 hg: parse error: negative number to select
1011 1011 [255]
1012 1012 $ log 'last(all(), 0)'
1013 1013 $ log 'last(all(), 1)'
1014 1014 9
1015 1015 $ log 'last(all(), 2)'
1016 1016 8
1017 1017 9
1018 1018
1019 1019 Test smartset.slice() by first/last()
1020 1020
1021 1021 (using unoptimized set, filteredset as example)
1022 1022
1023 1023 $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")'
1024 1024 * set:
1025 1025 <filteredset
1026 1026 <spanset+ 0:8>,
1027 1027 <branch 're:'>>
1028 1028 $ log 'limit(0:7 & branch("re:"), 3, 4)'
1029 1029 4
1030 1030 5
1031 1031 6
1032 1032 $ log 'limit(7:0 & branch("re:"), 3, 4)'
1033 1033 3
1034 1034 2
1035 1035 1
1036 1036 $ log 'last(0:7 & branch("re:"), 2)'
1037 1037 6
1038 1038 7
1039 1039
1040 1040 (using baseset)
1041 1041
1042 1042 $ hg debugrevspec --no-show-revs -s 0+1+2+3+4+5+6+7
1043 1043 * set:
1044 1044 <baseset [0, 1, 2, 3, 4, 5, 6, 7]>
1045 1045 $ hg debugrevspec --no-show-revs -s 0::7
1046 1046 * set:
1047 1047 <baseset+ [0, 1, 2, 3, 4, 5, 6, 7]>
1048 1048 $ log 'limit(0+1+2+3+4+5+6+7, 3, 4)'
1049 1049 4
1050 1050 5
1051 1051 6
1052 1052 $ log 'limit(sort(0::7, rev), 3, 4)'
1053 1053 4
1054 1054 5
1055 1055 6
1056 1056 $ log 'limit(sort(0::7, -rev), 3, 4)'
1057 1057 3
1058 1058 2
1059 1059 1
1060 1060 $ log 'last(sort(0::7, rev), 2)'
1061 1061 6
1062 1062 7
1063 1063 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 6)'
1064 1064 * set:
1065 1065 <baseset+ [6, 7]>
1066 1066 6
1067 1067 7
1068 1068 $ hg debugrevspec -s 'limit(sort(0::7, rev), 3, 9)'
1069 1069 * set:
1070 1070 <baseset+ []>
1071 1071 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 6)'
1072 1072 * set:
1073 1073 <baseset- [0, 1]>
1074 1074 1
1075 1075 0
1076 1076 $ hg debugrevspec -s 'limit(sort(0::7, -rev), 3, 9)'
1077 1077 * set:
1078 1078 <baseset- []>
1079 1079 $ hg debugrevspec -s 'limit(0::7, 0)'
1080 1080 * set:
1081 1081 <baseset+ []>
1082 1082
1083 1083 (using spanset)
1084 1084
1085 1085 $ hg debugrevspec --no-show-revs -s 0:7
1086 1086 * set:
1087 1087 <spanset+ 0:8>
1088 1088 $ log 'limit(0:7, 3, 4)'
1089 1089 4
1090 1090 5
1091 1091 6
1092 1092 $ log 'limit(7:0, 3, 4)'
1093 1093 3
1094 1094 2
1095 1095 1
1096 1096 $ log 'limit(0:7, 3, 6)'
1097 1097 6
1098 1098 7
1099 1099 $ log 'limit(7:0, 3, 6)'
1100 1100 1
1101 1101 0
1102 1102 $ log 'last(0:7, 2)'
1103 1103 6
1104 1104 7
1105 1105 $ hg debugrevspec -s 'limit(0:7, 3, 6)'
1106 1106 * set:
1107 1107 <spanset+ 6:8>
1108 1108 6
1109 1109 7
1110 1110 $ hg debugrevspec -s 'limit(0:7, 3, 9)'
1111 1111 * set:
1112 1112 <spanset+ 8:8>
1113 1113 $ hg debugrevspec -s 'limit(7:0, 3, 6)'
1114 1114 * set:
1115 1115 <spanset- 0:2>
1116 1116 1
1117 1117 0
1118 1118 $ hg debugrevspec -s 'limit(7:0, 3, 9)'
1119 1119 * set:
1120 1120 <spanset- 0:0>
1121 1121 $ hg debugrevspec -s 'limit(0:7, 0)'
1122 1122 * set:
1123 1123 <spanset+ 0:0>
1124 1124
1125 1125 Test order of first/last revisions
1126 1126
1127 1127 $ hg debugrevspec -s 'first(4:0, 3) & 3:'
1128 1128 * set:
1129 1129 <filteredset
1130 1130 <spanset- 2:5>,
1131 1131 <spanset+ 3:10>>
1132 1132 4
1133 1133 3
1134 1134
1135 1135 $ hg debugrevspec -s '3: & first(4:0, 3)'
1136 1136 * set:
1137 1137 <filteredset
1138 1138 <spanset+ 3:10>,
1139 1139 <spanset- 2:5>>
1140 1140 3
1141 1141 4
1142 1142
1143 1143 $ hg debugrevspec -s 'last(4:0, 3) & :1'
1144 1144 * set:
1145 1145 <filteredset
1146 1146 <spanset- 0:3>,
1147 1147 <spanset+ 0:2>>
1148 1148 1
1149 1149 0
1150 1150
1151 1151 $ hg debugrevspec -s ':1 & last(4:0, 3)'
1152 1152 * set:
1153 1153 <filteredset
1154 1154 <spanset+ 0:2>,
1155 1155 <spanset+ 0:3>>
1156 1156 0
1157 1157 1
1158 1158
1159 1159 Test matching
1160 1160
1161 1161 $ log 'matching(6)'
1162 1162 6
1163 1163 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1164 1164 6
1165 1165 7
1166 1166
1167 1167 Testing min and max
1168 1168
1169 1169 max: simple
1170 1170
1171 1171 $ log 'max(contains(a))'
1172 1172 5
1173 1173
1174 1174 max: simple on unordered set)
1175 1175
1176 1176 $ log 'max((4+0+2+5+7) and contains(a))'
1177 1177 5
1178 1178
1179 1179 max: no result
1180 1180
1181 1181 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1182 1182
1183 1183 max: no result on unordered set
1184 1184
1185 1185 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1186 1186
1187 1187 min: simple
1188 1188
1189 1189 $ log 'min(contains(a))'
1190 1190 0
1191 1191
1192 1192 min: simple on unordered set
1193 1193
1194 1194 $ log 'min((4+0+2+5+7) and contains(a))'
1195 1195 0
1196 1196
1197 1197 min: empty
1198 1198
1199 1199 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1200 1200
1201 1201 min: empty on unordered set
1202 1202
1203 1203 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1204 1204
1205 1205
1206 1206 $ log 'merge()'
1207 1207 6
1208 1208 $ log 'branchpoint()'
1209 1209 1
1210 1210 4
1211 1211 $ log 'modifies(b)'
1212 1212 4
1213 1213 $ log 'modifies("path:b")'
1214 1214 4
1215 1215 $ log 'modifies("*")'
1216 1216 4
1217 1217 6
1218 1218 $ log 'modifies("set:modified()")'
1219 1219 4
1220 1220 $ log 'id(5)'
1221 1221 2
1222 1222 $ log 'only(9)'
1223 1223 8
1224 1224 9
1225 1225 $ log 'only(8)'
1226 1226 8
1227 1227 $ log 'only(9, 5)'
1228 1228 2
1229 1229 4
1230 1230 8
1231 1231 9
1232 1232 $ log 'only(7 + 9, 5 + 2)'
1233 1233 4
1234 1234 6
1235 1235 7
1236 1236 8
1237 1237 9
1238 1238
1239 1239 Test empty set input
1240 1240 $ log 'only(p2())'
1241 1241 $ log 'only(p1(), p2())'
1242 1242 0
1243 1243 1
1244 1244 2
1245 1245 4
1246 1246 8
1247 1247 9
1248 1248
1249 1249 Test '%' operator
1250 1250
1251 1251 $ log '9%'
1252 1252 8
1253 1253 9
1254 1254 $ log '9%5'
1255 1255 2
1256 1256 4
1257 1257 8
1258 1258 9
1259 1259 $ log '(7 + 9)%(5 + 2)'
1260 1260 4
1261 1261 6
1262 1262 7
1263 1263 8
1264 1264 9
1265 1265
1266 1266 Test operand of '%' is optimized recursively (issue4670)
1267 1267
1268 1268 $ try --optimize '8:9-8%'
1269 1269 (onlypost
1270 1270 (minus
1271 1271 (range
1272 1272 ('symbol', '8')
1273 1273 ('symbol', '9'))
1274 1274 ('symbol', '8')))
1275 1275 * optimized:
1276 1276 (func
1277 1277 ('symbol', 'only')
1278 1278 (difference
1279 1279 (range
1280 1280 ('symbol', '8')
1281 1281 ('symbol', '9')
1282 1282 define)
1283 1283 ('symbol', '8')
1284 1284 define)
1285 1285 define)
1286 1286 * set:
1287 1287 <baseset+ [8, 9]>
1288 1288 8
1289 1289 9
1290 1290 $ try --optimize '(9)%(5)'
1291 1291 (only
1292 1292 (group
1293 1293 ('symbol', '9'))
1294 1294 (group
1295 1295 ('symbol', '5')))
1296 1296 * optimized:
1297 1297 (func
1298 1298 ('symbol', 'only')
1299 1299 (list
1300 1300 ('symbol', '9')
1301 1301 ('symbol', '5'))
1302 1302 define)
1303 1303 * set:
1304 1304 <baseset+ [2, 4, 8, 9]>
1305 1305 2
1306 1306 4
1307 1307 8
1308 1308 9
1309 1309
1310 1310 Test the order of operations
1311 1311
1312 1312 $ log '7 + 9%5 + 2'
1313 1313 7
1314 1314 2
1315 1315 4
1316 1316 8
1317 1317 9
1318 1318
1319 1319 Test explicit numeric revision
1320 1320 $ log 'rev(-2)'
1321 1321 $ log 'rev(-1)'
1322 1322 -1
1323 1323 $ log 'rev(0)'
1324 1324 0
1325 1325 $ log 'rev(9)'
1326 1326 9
1327 1327 $ log 'rev(10)'
1328 1328 $ log 'rev(tip)'
1329 1329 hg: parse error: rev expects a number
1330 1330 [255]
1331 1331
1332 1332 Test hexadecimal revision
1333 1333 $ log 'id(2)'
1334 1334 abort: 00changelog.i@2: ambiguous identifier!
1335 1335 [255]
1336 1336 $ log 'id(23268)'
1337 1337 4
1338 1338 $ log 'id(2785f51eece)'
1339 1339 0
1340 1340 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1341 1341 8
1342 1342 $ log 'id(d5d0dcbdc4a)'
1343 1343 $ log 'id(d5d0dcbdc4w)'
1344 1344 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1345 1345 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1346 1346 $ log 'id(1.0)'
1347 1347 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1348 1348
1349 1349 Test null revision
1350 1350 $ log '(null)'
1351 1351 -1
1352 1352 $ log '(null:0)'
1353 1353 -1
1354 1354 0
1355 1355 $ log '(0:null)'
1356 1356 0
1357 1357 -1
1358 1358 $ log 'null::0'
1359 1359 -1
1360 1360 0
1361 1361 $ log 'null:tip - 0:'
1362 1362 -1
1363 1363 $ log 'null: and null::' | head -1
1364 1364 -1
1365 1365 $ log 'null: or 0:' | head -2
1366 1366 -1
1367 1367 0
1368 1368 $ log 'ancestors(null)'
1369 1369 -1
1370 1370 $ log 'reverse(null:)' | tail -2
1371 1371 0
1372 1372 -1
1373 1373 $ log 'first(null:)'
1374 1374 -1
1375 1375 $ log 'min(null:)'
1376 1376 BROKEN: should be '-1'
1377 1377 $ log 'tip:null and all()' | tail -2
1378 1378 1
1379 1379 0
1380 1380
1381 1381 Test working-directory revision
1382 1382 $ hg debugrevspec 'wdir()'
1383 1383 2147483647
1384 1384 $ hg debugrevspec 'wdir()^'
1385 1385 9
1386 1386 $ hg up 7
1387 1387 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1388 1388 $ hg debugrevspec 'wdir()^'
1389 1389 7
1390 1390 $ hg debugrevspec 'wdir()^0'
1391 1391 2147483647
1392 1392 $ hg debugrevspec 'wdir()~3'
1393 1393 5
1394 1394 $ hg debugrevspec 'ancestors(wdir())'
1395 1395 0
1396 1396 1
1397 1397 2
1398 1398 3
1399 1399 4
1400 1400 5
1401 1401 6
1402 1402 7
1403 1403 2147483647
1404 1404 $ hg debugrevspec 'wdir()~0'
1405 1405 2147483647
1406 1406 $ hg debugrevspec 'p1(wdir())'
1407 1407 7
1408 1408 $ hg debugrevspec 'p2(wdir())'
1409 1409 $ hg debugrevspec 'parents(wdir())'
1410 1410 7
1411 1411 $ hg debugrevspec 'wdir()^1'
1412 1412 7
1413 1413 $ hg debugrevspec 'wdir()^2'
1414 1414 $ hg debugrevspec 'wdir()^3'
1415 1415 hg: parse error: ^ expects a number 0, 1, or 2
1416 1416 [255]
1417 1417 For tests consistency
1418 1418 $ hg up 9
1419 1419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1420 1420 $ hg debugrevspec 'tip or wdir()'
1421 1421 9
1422 1422 2147483647
1423 1423 $ hg debugrevspec '0:tip and wdir()'
1424 1424 $ log '0:wdir()' | tail -3
1425 1425 8
1426 1426 9
1427 1427 2147483647
1428 1428 $ log 'wdir():0' | head -3
1429 1429 2147483647
1430 1430 9
1431 1431 8
1432 1432 $ log 'wdir():wdir()'
1433 1433 2147483647
1434 1434 $ log '(all() + wdir()) & min(. + wdir())'
1435 1435 9
1436 1436 $ log '(all() + wdir()) & max(. + wdir())'
1437 1437 2147483647
1438 1438 $ log 'first(wdir() + .)'
1439 1439 2147483647
1440 1440 $ log 'last(. + wdir())'
1441 1441 2147483647
1442 1442
1443 1443 Test working-directory integer revision and node id
1444 1444 (BUG: '0:wdir()' is still needed to populate wdir revision)
1445 1445
1446 1446 $ hg debugrevspec '0:wdir() & 2147483647'
1447 1447 2147483647
1448 1448 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1449 1449 2147483647
1450 1450 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1451 1451 2147483647
1452 1452 $ hg debugrevspec '0:wdir() & ffffffffffff'
1453 1453 2147483647
1454 1454 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1455 1455 2147483647
1456 1456 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1457 1457 2147483647
1458 1458
1459 1459 $ cd ..
1460 1460
1461 1461 Test short 'ff...' hash collision
1462 1462 (BUG: '0:wdir()' is still needed to populate wdir revision)
1463 1463
1464 1464 $ hg init wdir-hashcollision
1465 1465 $ cd wdir-hashcollision
1466 1466 $ cat <<EOF >> .hg/hgrc
1467 1467 > [experimental]
1468 1468 > evolution = createmarkers
1469 1469 > EOF
1470 1470 $ echo 0 > a
1471 1471 $ hg ci -qAm 0
1472 1472 $ for i in 2463 2961 6726 78127; do
1473 1473 > hg up -q 0
1474 1474 > echo $i > a
1475 1475 > hg ci -qm $i
1476 1476 > done
1477 1477 $ hg up -q null
1478 1478 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1479 1479 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1480 1480 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1481 1481 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1482 1482 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1483 1483 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1484 1484 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1485 1485 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1486 1486
1487 1487 $ hg debugrevspec '0:wdir() & fff'
1488 1488 abort: 00changelog.i@fff: ambiguous identifier!
1489 1489 [255]
1490 1490 $ hg debugrevspec '0:wdir() & ffff'
1491 1491 abort: 00changelog.i@ffff: ambiguous identifier!
1492 1492 [255]
1493 1493 $ hg debugrevspec '0:wdir() & fffb'
1494 1494 abort: 00changelog.i@fffb: ambiguous identifier!
1495 1495 [255]
1496 1496 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1497 1497 $ hg debugrevspec '0:wdir() & id(fffb)'
1498 1498 2
1499 1499 $ hg debugrevspec '0:wdir() & ffff8'
1500 1500 4
1501 1501 $ hg debugrevspec '0:wdir() & fffff'
1502 1502 2147483647
1503 1503
1504 1504 $ cd ..
1505 1505
1506 1506 Test branch() with wdir()
1507 1507
1508 1508 $ cd repo
1509 1509
1510 1510 $ log '0:wdir() & branch("literal:Γ©")'
1511 1511 8
1512 1512 9
1513 1513 2147483647
1514 1514 $ log '0:wdir() & branch("re:Γ©")'
1515 1515 8
1516 1516 9
1517 1517 2147483647
1518 1518 $ log '0:wdir() & branch("re:^a")'
1519 1519 0
1520 1520 2
1521 1521 $ log '0:wdir() & branch(8)'
1522 1522 8
1523 1523 9
1524 1524 2147483647
1525 1525
1526 1526 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1527 1527 itself isn't returned unless it is explicitly populated.
1528 1528
1529 1529 $ log 'branch(wdir())'
1530 1530 8
1531 1531 9
1532 1532 $ log '0:wdir() & branch(wdir())'
1533 1533 8
1534 1534 9
1535 1535 2147483647
1536 1536
1537 1537 $ log 'outgoing()'
1538 1538 8
1539 1539 9
1540 1540 $ log 'outgoing("../remote1")'
1541 1541 8
1542 1542 9
1543 1543 $ log 'outgoing("../remote2")'
1544 1544 3
1545 1545 5
1546 1546 6
1547 1547 7
1548 1548 9
1549 1549 $ log 'p1(merge())'
1550 1550 5
1551 1551 $ log 'p2(merge())'
1552 1552 4
1553 1553 $ log 'parents(merge())'
1554 1554 4
1555 1555 5
1556 1556 $ log 'p1(branchpoint())'
1557 1557 0
1558 1558 2
1559 1559 $ log 'p2(branchpoint())'
1560 1560 $ log 'parents(branchpoint())'
1561 1561 0
1562 1562 2
1563 1563 $ log 'removes(a)'
1564 1564 2
1565 1565 6
1566 1566 $ log 'roots(all())'
1567 1567 0
1568 1568 $ log 'reverse(2 or 3 or 4 or 5)'
1569 1569 5
1570 1570 4
1571 1571 3
1572 1572 2
1573 1573 $ log 'reverse(all())'
1574 1574 9
1575 1575 8
1576 1576 7
1577 1577 6
1578 1578 5
1579 1579 4
1580 1580 3
1581 1581 2
1582 1582 1
1583 1583 0
1584 1584 $ log 'reverse(all()) & filelog(b)'
1585 1585 4
1586 1586 1
1587 1587 $ log 'rev(5)'
1588 1588 5
1589 1589 $ log 'sort(limit(reverse(all()), 3))'
1590 1590 7
1591 1591 8
1592 1592 9
1593 1593 $ log 'sort(2 or 3 or 4 or 5, date)'
1594 1594 2
1595 1595 3
1596 1596 5
1597 1597 4
1598 1598 $ log 'tagged()'
1599 1599 6
1600 1600 $ log 'tag()'
1601 1601 6
1602 1602 $ log 'tag(1.0)'
1603 1603 6
1604 1604 $ log 'tag(tip)'
1605 1605 9
1606 1606
1607 1607 Test order of revisions in compound expression
1608 1608 ----------------------------------------------
1609 1609
1610 1610 The general rule is that only the outermost (= leftmost) predicate can
1611 1611 enforce its ordering requirement. The other predicates should take the
1612 1612 ordering defined by it.
1613 1613
1614 1614 'A & B' should follow the order of 'A':
1615 1615
1616 1616 $ log '2:0 & 0::2'
1617 1617 2
1618 1618 1
1619 1619 0
1620 1620
1621 1621 'head()' combines sets in right order:
1622 1622
1623 1623 $ log '2:0 & head()'
1624 1624 2
1625 1625 1
1626 1626 0
1627 1627
1628 1628 'x:y' takes ordering parameter into account:
1629 1629
1630 1630 $ try -p optimized '3:0 & 0:3 & not 2:1'
1631 1631 * optimized:
1632 1632 (difference
1633 1633 (and
1634 1634 (range
1635 1635 ('symbol', '3')
1636 1636 ('symbol', '0')
1637 1637 define)
1638 1638 (range
1639 1639 ('symbol', '0')
1640 1640 ('symbol', '3')
1641 1641 follow)
1642 1642 define)
1643 1643 (range
1644 1644 ('symbol', '2')
1645 1645 ('symbol', '1')
1646 1646 any)
1647 1647 define)
1648 1648 * set:
1649 1649 <filteredset
1650 1650 <filteredset
1651 1651 <spanset- 0:4>,
1652 1652 <spanset+ 0:4>>,
1653 1653 <not
1654 1654 <spanset+ 1:3>>>
1655 1655 3
1656 1656 0
1657 1657
1658 1658 'a + b', which is optimized to '_list(a b)', should take the ordering of
1659 1659 the left expression:
1660 1660
1661 1661 $ try --optimize '2:0 & (0 + 1 + 2)'
1662 1662 (and
1663 1663 (range
1664 1664 ('symbol', '2')
1665 1665 ('symbol', '0'))
1666 1666 (group
1667 1667 (or
1668 1668 (list
1669 1669 ('symbol', '0')
1670 1670 ('symbol', '1')
1671 1671 ('symbol', '2')))))
1672 1672 * optimized:
1673 1673 (and
1674 1674 (range
1675 1675 ('symbol', '2')
1676 1676 ('symbol', '0')
1677 1677 define)
1678 1678 (func
1679 1679 ('symbol', '_list')
1680 1680 ('string', '0\x001\x002')
1681 1681 follow)
1682 1682 define)
1683 1683 * set:
1684 1684 <filteredset
1685 1685 <spanset- 0:3>,
1686 1686 <baseset [0, 1, 2]>>
1687 1687 2
1688 1688 1
1689 1689 0
1690 1690
1691 1691 'A + B' should take the ordering of the left expression:
1692 1692
1693 1693 $ try --optimize '2:0 & (0:1 + 2)'
1694 1694 (and
1695 1695 (range
1696 1696 ('symbol', '2')
1697 1697 ('symbol', '0'))
1698 1698 (group
1699 1699 (or
1700 1700 (list
1701 1701 (range
1702 1702 ('symbol', '0')
1703 1703 ('symbol', '1'))
1704 1704 ('symbol', '2')))))
1705 1705 * optimized:
1706 1706 (and
1707 1707 (range
1708 1708 ('symbol', '2')
1709 1709 ('symbol', '0')
1710 1710 define)
1711 1711 (or
1712 1712 (list
1713 1713 ('symbol', '2')
1714 1714 (range
1715 1715 ('symbol', '0')
1716 1716 ('symbol', '1')
1717 1717 follow))
1718 1718 follow)
1719 1719 define)
1720 1720 * set:
1721 1721 <filteredset
1722 1722 <spanset- 0:3>,
1723 1723 <addset
1724 1724 <baseset [2]>,
1725 1725 <spanset+ 0:2>>>
1726 1726 2
1727 1727 1
1728 1728 0
1729 1729
1730 1730 '_intlist(a b)' should behave like 'a + b':
1731 1731
1732 1732 $ trylist --optimize '2:0 & %ld' 0 1 2
1733 1733 (and
1734 1734 (range
1735 1735 ('symbol', '2')
1736 1736 ('symbol', '0'))
1737 1737 (func
1738 1738 ('symbol', '_intlist')
1739 1739 ('string', '0\x001\x002')))
1740 1740 * optimized:
1741 1741 (and
1742 1742 (func
1743 1743 ('symbol', '_intlist')
1744 1744 ('string', '0\x001\x002')
1745 1745 follow)
1746 1746 (range
1747 1747 ('symbol', '2')
1748 1748 ('symbol', '0')
1749 1749 define)
1750 1750 define)
1751 1751 * set:
1752 1752 <filteredset
1753 1753 <spanset- 0:3>,
1754 1754 <baseset+ [0, 1, 2]>>
1755 1755 2
1756 1756 1
1757 1757 0
1758 1758
1759 1759 $ trylist --optimize '%ld & 2:0' 0 2 1
1760 1760 (and
1761 1761 (func
1762 1762 ('symbol', '_intlist')
1763 1763 ('string', '0\x002\x001'))
1764 1764 (range
1765 1765 ('symbol', '2')
1766 1766 ('symbol', '0')))
1767 1767 * optimized:
1768 1768 (and
1769 1769 (func
1770 1770 ('symbol', '_intlist')
1771 1771 ('string', '0\x002\x001')
1772 1772 define)
1773 1773 (range
1774 1774 ('symbol', '2')
1775 1775 ('symbol', '0')
1776 1776 follow)
1777 1777 define)
1778 1778 * set:
1779 1779 <filteredset
1780 1780 <baseset [0, 2, 1]>,
1781 1781 <spanset- 0:3>>
1782 1782 0
1783 1783 2
1784 1784 1
1785 1785
1786 1786 '_hexlist(a b)' should behave like 'a + b':
1787 1787
1788 1788 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1789 1789 (and
1790 1790 (range
1791 1791 ('symbol', '2')
1792 1792 ('symbol', '0'))
1793 1793 (func
1794 1794 ('symbol', '_hexlist')
1795 1795 ('string', '*'))) (glob)
1796 1796 * optimized:
1797 1797 (and
1798 1798 (range
1799 1799 ('symbol', '2')
1800 1800 ('symbol', '0')
1801 1801 define)
1802 1802 (func
1803 1803 ('symbol', '_hexlist')
1804 1804 ('string', '*') (glob)
1805 1805 follow)
1806 1806 define)
1807 1807 * set:
1808 1808 <filteredset
1809 1809 <spanset- 0:3>,
1810 1810 <baseset [0, 1, 2]>>
1811 1811 2
1812 1812 1
1813 1813 0
1814 1814
1815 1815 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1816 1816 (and
1817 1817 (func
1818 1818 ('symbol', '_hexlist')
1819 1819 ('string', '*')) (glob)
1820 1820 (range
1821 1821 ('symbol', '2')
1822 1822 ('symbol', '0')))
1823 1823 * optimized:
1824 1824 (and
1825 1825 (range
1826 1826 ('symbol', '2')
1827 1827 ('symbol', '0')
1828 1828 follow)
1829 1829 (func
1830 1830 ('symbol', '_hexlist')
1831 1831 ('string', '*') (glob)
1832 1832 define)
1833 1833 define)
1834 1834 * set:
1835 1835 <baseset [0, 2, 1]>
1836 1836 0
1837 1837 2
1838 1838 1
1839 1839
1840 1840 '_list' should not go through the slow follow-order path if order doesn't
1841 1841 matter:
1842 1842
1843 1843 $ try -p optimized '2:0 & not (0 + 1)'
1844 1844 * optimized:
1845 1845 (difference
1846 1846 (range
1847 1847 ('symbol', '2')
1848 1848 ('symbol', '0')
1849 1849 define)
1850 1850 (func
1851 1851 ('symbol', '_list')
1852 1852 ('string', '0\x001')
1853 1853 any)
1854 1854 define)
1855 1855 * set:
1856 1856 <filteredset
1857 1857 <spanset- 0:3>,
1858 1858 <not
1859 1859 <baseset [0, 1]>>>
1860 1860 2
1861 1861
1862 1862 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1863 1863 * optimized:
1864 1864 (difference
1865 1865 (range
1866 1866 ('symbol', '2')
1867 1867 ('symbol', '0')
1868 1868 define)
1869 1869 (and
1870 1870 (range
1871 1871 ('symbol', '0')
1872 1872 ('symbol', '2')
1873 1873 any)
1874 1874 (func
1875 1875 ('symbol', '_list')
1876 1876 ('string', '0\x001')
1877 1877 any)
1878 1878 any)
1879 1879 define)
1880 1880 * set:
1881 1881 <filteredset
1882 1882 <spanset- 0:3>,
1883 1883 <not
1884 1884 <baseset [0, 1]>>>
1885 1885 2
1886 1886
1887 1887 because 'present()' does nothing other than suppressing an error, the
1888 1888 ordering requirement should be forwarded to the nested expression
1889 1889
1890 1890 $ try -p optimized 'present(2 + 0 + 1)'
1891 1891 * optimized:
1892 1892 (func
1893 1893 ('symbol', 'present')
1894 1894 (func
1895 1895 ('symbol', '_list')
1896 1896 ('string', '2\x000\x001')
1897 1897 define)
1898 1898 define)
1899 1899 * set:
1900 1900 <baseset [2, 0, 1]>
1901 1901 2
1902 1902 0
1903 1903 1
1904 1904
1905 1905 $ try --optimize '2:0 & present(0 + 1 + 2)'
1906 1906 (and
1907 1907 (range
1908 1908 ('symbol', '2')
1909 1909 ('symbol', '0'))
1910 1910 (func
1911 1911 ('symbol', 'present')
1912 1912 (or
1913 1913 (list
1914 1914 ('symbol', '0')
1915 1915 ('symbol', '1')
1916 1916 ('symbol', '2')))))
1917 1917 * optimized:
1918 1918 (and
1919 1919 (range
1920 1920 ('symbol', '2')
1921 1921 ('symbol', '0')
1922 1922 define)
1923 1923 (func
1924 1924 ('symbol', 'present')
1925 1925 (func
1926 1926 ('symbol', '_list')
1927 1927 ('string', '0\x001\x002')
1928 1928 follow)
1929 1929 follow)
1930 1930 define)
1931 1931 * set:
1932 1932 <filteredset
1933 1933 <spanset- 0:3>,
1934 1934 <baseset [0, 1, 2]>>
1935 1935 2
1936 1936 1
1937 1937 0
1938 1938
1939 1939 'reverse()' should take effect only if it is the outermost expression:
1940 1940
1941 1941 $ try --optimize '0:2 & reverse(all())'
1942 1942 (and
1943 1943 (range
1944 1944 ('symbol', '0')
1945 1945 ('symbol', '2'))
1946 1946 (func
1947 1947 ('symbol', 'reverse')
1948 1948 (func
1949 1949 ('symbol', 'all')
1950 1950 None)))
1951 1951 * optimized:
1952 1952 (and
1953 1953 (range
1954 1954 ('symbol', '0')
1955 1955 ('symbol', '2')
1956 1956 define)
1957 1957 (func
1958 1958 ('symbol', 'reverse')
1959 1959 (func
1960 1960 ('symbol', 'all')
1961 1961 None
1962 1962 define)
1963 1963 follow)
1964 1964 define)
1965 1965 * set:
1966 1966 <filteredset
1967 1967 <spanset+ 0:3>,
1968 1968 <spanset+ 0:10>>
1969 1969 0
1970 1970 1
1971 1971 2
1972 1972
1973 1973 'sort()' should take effect only if it is the outermost expression:
1974 1974
1975 1975 $ try --optimize '0:2 & sort(all(), -rev)'
1976 1976 (and
1977 1977 (range
1978 1978 ('symbol', '0')
1979 1979 ('symbol', '2'))
1980 1980 (func
1981 1981 ('symbol', 'sort')
1982 1982 (list
1983 1983 (func
1984 1984 ('symbol', 'all')
1985 1985 None)
1986 1986 (negate
1987 1987 ('symbol', 'rev')))))
1988 1988 * optimized:
1989 1989 (and
1990 1990 (range
1991 1991 ('symbol', '0')
1992 1992 ('symbol', '2')
1993 1993 define)
1994 1994 (func
1995 1995 ('symbol', 'sort')
1996 1996 (list
1997 1997 (func
1998 1998 ('symbol', 'all')
1999 1999 None
2000 2000 define)
2001 2001 ('string', '-rev'))
2002 2002 follow)
2003 2003 define)
2004 2004 * set:
2005 2005 <filteredset
2006 2006 <spanset+ 0:3>,
2007 2007 <spanset+ 0:10>>
2008 2008 0
2009 2009 1
2010 2010 2
2011 2011
2012 2012 invalid argument passed to noop sort():
2013 2013
2014 2014 $ log '0:2 & sort()'
2015 2015 hg: parse error: sort requires one or two arguments
2016 2016 [255]
2017 2017 $ log '0:2 & sort(all(), -invalid)'
2018 2018 hg: parse error: unknown sort key '-invalid'
2019 2019 [255]
2020 2020
2021 2021 for 'A & f(B)', 'B' should not be affected by the order of 'A':
2022 2022
2023 2023 $ try --optimize '2:0 & first(1 + 0 + 2)'
2024 2024 (and
2025 2025 (range
2026 2026 ('symbol', '2')
2027 2027 ('symbol', '0'))
2028 2028 (func
2029 2029 ('symbol', 'first')
2030 2030 (or
2031 2031 (list
2032 2032 ('symbol', '1')
2033 2033 ('symbol', '0')
2034 2034 ('symbol', '2')))))
2035 2035 * optimized:
2036 2036 (and
2037 2037 (range
2038 2038 ('symbol', '2')
2039 2039 ('symbol', '0')
2040 2040 define)
2041 2041 (func
2042 2042 ('symbol', 'first')
2043 2043 (func
2044 2044 ('symbol', '_list')
2045 2045 ('string', '1\x000\x002')
2046 2046 define)
2047 2047 follow)
2048 2048 define)
2049 2049 * set:
2050 2050 <filteredset
2051 2051 <baseset [1]>,
2052 2052 <spanset- 0:3>>
2053 2053 1
2054 2054
2055 2055 $ try --optimize '2:0 & not last(0 + 2 + 1)'
2056 2056 (and
2057 2057 (range
2058 2058 ('symbol', '2')
2059 2059 ('symbol', '0'))
2060 2060 (not
2061 2061 (func
2062 2062 ('symbol', 'last')
2063 2063 (or
2064 2064 (list
2065 2065 ('symbol', '0')
2066 2066 ('symbol', '2')
2067 2067 ('symbol', '1'))))))
2068 2068 * optimized:
2069 2069 (difference
2070 2070 (range
2071 2071 ('symbol', '2')
2072 2072 ('symbol', '0')
2073 2073 define)
2074 2074 (func
2075 2075 ('symbol', 'last')
2076 2076 (func
2077 2077 ('symbol', '_list')
2078 2078 ('string', '0\x002\x001')
2079 2079 define)
2080 2080 any)
2081 2081 define)
2082 2082 * set:
2083 2083 <filteredset
2084 2084 <spanset- 0:3>,
2085 2085 <not
2086 2086 <baseset [1]>>>
2087 2087 2
2088 2088 0
2089 2089
2090 2090 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
2091 2091
2092 2092 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
2093 2093 (and
2094 2094 (range
2095 2095 ('symbol', '2')
2096 2096 ('symbol', '0'))
2097 2097 (range
2098 2098 (group
2099 2099 (or
2100 2100 (list
2101 2101 ('symbol', '1')
2102 2102 ('symbol', '0')
2103 2103 ('symbol', '2'))))
2104 2104 (group
2105 2105 (or
2106 2106 (list
2107 2107 ('symbol', '0')
2108 2108 ('symbol', '2')
2109 2109 ('symbol', '1'))))))
2110 2110 * optimized:
2111 2111 (and
2112 2112 (range
2113 2113 ('symbol', '2')
2114 2114 ('symbol', '0')
2115 2115 define)
2116 2116 (range
2117 2117 (func
2118 2118 ('symbol', '_list')
2119 2119 ('string', '1\x000\x002')
2120 2120 define)
2121 2121 (func
2122 2122 ('symbol', '_list')
2123 2123 ('string', '0\x002\x001')
2124 2124 define)
2125 2125 follow)
2126 2126 define)
2127 2127 * set:
2128 2128 <filteredset
2129 2129 <spanset- 0:3>,
2130 2130 <baseset [1]>>
2131 2131 1
2132 2132
2133 2133 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
2134 2134 the ordering rule is determined before the rewrite; in this example,
2135 2135 'B' follows the order of the initial set, which is the same order as 'A'
2136 2136 since 'A' also follows the order:
2137 2137
2138 2138 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
2139 2139 (and
2140 2140 (func
2141 2141 ('symbol', 'contains')
2142 2142 ('string', 'glob:*'))
2143 2143 (group
2144 2144 (or
2145 2145 (list
2146 2146 ('symbol', '2')
2147 2147 ('symbol', '0')
2148 2148 ('symbol', '1')))))
2149 2149 * optimized:
2150 2150 (and
2151 2151 (func
2152 2152 ('symbol', '_list')
2153 2153 ('string', '2\x000\x001')
2154 2154 follow)
2155 2155 (func
2156 2156 ('symbol', 'contains')
2157 2157 ('string', 'glob:*')
2158 2158 define)
2159 2159 define)
2160 2160 * set:
2161 2161 <filteredset
2162 2162 <baseset+ [0, 1, 2]>,
2163 2163 <contains 'glob:*'>>
2164 2164 0
2165 2165 1
2166 2166 2
2167 2167
2168 2168 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2169 2169 the order appropriately:
2170 2170
2171 2171 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2172 2172 (and
2173 2173 (func
2174 2174 ('symbol', 'reverse')
2175 2175 (func
2176 2176 ('symbol', 'contains')
2177 2177 ('string', 'glob:*')))
2178 2178 (group
2179 2179 (or
2180 2180 (list
2181 2181 ('symbol', '0')
2182 2182 ('symbol', '2')
2183 2183 ('symbol', '1')))))
2184 2184 * optimized:
2185 2185 (and
2186 2186 (func
2187 2187 ('symbol', '_list')
2188 2188 ('string', '0\x002\x001')
2189 2189 follow)
2190 2190 (func
2191 2191 ('symbol', 'reverse')
2192 2192 (func
2193 2193 ('symbol', 'contains')
2194 2194 ('string', 'glob:*')
2195 2195 define)
2196 2196 define)
2197 2197 define)
2198 2198 * set:
2199 2199 <filteredset
2200 2200 <baseset- [0, 1, 2]>,
2201 2201 <contains 'glob:*'>>
2202 2202 2
2203 2203 1
2204 2204 0
2205 2205
2206 2206 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2207 2207 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2208 2208
2209 2209 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2210 2210 * optimized:
2211 2211 (and
2212 2212 (range
2213 2213 ('symbol', '0')
2214 2214 ('symbol', '2')
2215 2215 define)
2216 2216 (or
2217 2217 (list
2218 2218 ('symbol', '2')
2219 2219 (func
2220 2220 ('symbol', 'reverse')
2221 2221 (func
2222 2222 ('symbol', 'contains')
2223 2223 ('string', 'a')
2224 2224 define)
2225 2225 follow))
2226 2226 follow)
2227 2227 define)
2228 2228 * set:
2229 2229 <filteredset
2230 2230 <spanset+ 0:3>,
2231 2231 <addset
2232 2232 <baseset [2]>,
2233 2233 <filteredset
2234 2234 <fullreposet+ 0:10>,
2235 2235 <contains 'a'>>>>
2236 2236 0
2237 2237 1
2238 2238 2
2239 2239
2240 2240 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2241 2241 * optimized:
2242 2242 (and
2243 2243 (range
2244 2244 ('symbol', '0')
2245 2245 ('symbol', '2')
2246 2246 follow)
2247 2247 (or
2248 2248 (list
2249 2249 (func
2250 2250 ('symbol', 'reverse')
2251 2251 (func
2252 2252 ('symbol', 'contains')
2253 2253 ('string', 'a')
2254 2254 define)
2255 2255 define)
2256 2256 ('symbol', '2'))
2257 2257 define)
2258 2258 define)
2259 2259 * set:
2260 2260 <addset
2261 2261 <filteredset
2262 2262 <spanset- 0:3>,
2263 2263 <contains 'a'>>,
2264 2264 <baseset [2]>>
2265 2265 1
2266 2266 0
2267 2267 2
2268 2268
2269 2269 test sort revset
2270 2270 --------------------------------------------
2271 2271
2272 2272 test when adding two unordered revsets
2273 2273
2274 2274 $ log 'sort(keyword(issue) or modifies(b))'
2275 2275 4
2276 2276 6
2277 2277
2278 2278 test when sorting a reversed collection in the same way it is
2279 2279
2280 2280 $ log 'sort(reverse(all()), -rev)'
2281 2281 9
2282 2282 8
2283 2283 7
2284 2284 6
2285 2285 5
2286 2286 4
2287 2287 3
2288 2288 2
2289 2289 1
2290 2290 0
2291 2291
2292 2292 test when sorting a reversed collection
2293 2293
2294 2294 $ log 'sort(reverse(all()), rev)'
2295 2295 0
2296 2296 1
2297 2297 2
2298 2298 3
2299 2299 4
2300 2300 5
2301 2301 6
2302 2302 7
2303 2303 8
2304 2304 9
2305 2305
2306 2306
2307 2307 test sorting two sorted collections in different orders
2308 2308
2309 2309 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2310 2310 2
2311 2311 6
2312 2312 8
2313 2313 9
2314 2314
2315 2315 test sorting two sorted collections in different orders backwards
2316 2316
2317 2317 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2318 2318 9
2319 2319 8
2320 2320 6
2321 2321 2
2322 2322
2323 2323 test empty sort key which is noop
2324 2324
2325 2325 $ log 'sort(0 + 2 + 1, "")'
2326 2326 0
2327 2327 2
2328 2328 1
2329 2329
2330 2330 test invalid sort keys
2331 2331
2332 2332 $ log 'sort(all(), -invalid)'
2333 2333 hg: parse error: unknown sort key '-invalid'
2334 2334 [255]
2335 2335
2336 2336 $ cd ..
2337 2337
2338 2338 test sorting by multiple keys including variable-length strings
2339 2339
2340 2340 $ hg init sorting
2341 2341 $ cd sorting
2342 2342 $ cat <<EOF >> .hg/hgrc
2343 2343 > [ui]
2344 2344 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2345 2345 > [templatealias]
2346 2346 > p5(s) = pad(s, 5)
2347 2347 > EOF
2348 2348 $ hg branch -qf b12
2349 2349 $ hg ci -m m111 -u u112 -d '111 10800'
2350 2350 $ hg branch -qf b11
2351 2351 $ hg ci -m m12 -u u111 -d '112 7200'
2352 2352 $ hg branch -qf b111
2353 2353 $ hg ci -m m11 -u u12 -d '111 3600'
2354 2354 $ hg branch -qf b112
2355 2355 $ hg ci -m m111 -u u11 -d '120 0'
2356 2356 $ hg branch -qf b111
2357 2357 $ hg ci -m m112 -u u111 -d '110 14400'
2358 2358 created new head
2359 2359
2360 2360 compare revisions (has fast path):
2361 2361
2362 2362 $ hg log -r 'sort(all(), rev)'
2363 2363 0 b12 m111 u112 111 10800
2364 2364 1 b11 m12 u111 112 7200
2365 2365 2 b111 m11 u12 111 3600
2366 2366 3 b112 m111 u11 120 0
2367 2367 4 b111 m112 u111 110 14400
2368 2368
2369 2369 $ hg log -r 'sort(all(), -rev)'
2370 2370 4 b111 m112 u111 110 14400
2371 2371 3 b112 m111 u11 120 0
2372 2372 2 b111 m11 u12 111 3600
2373 2373 1 b11 m12 u111 112 7200
2374 2374 0 b12 m111 u112 111 10800
2375 2375
2376 2376 compare variable-length strings (issue5218):
2377 2377
2378 2378 $ hg log -r 'sort(all(), branch)'
2379 2379 1 b11 m12 u111 112 7200
2380 2380 2 b111 m11 u12 111 3600
2381 2381 4 b111 m112 u111 110 14400
2382 2382 3 b112 m111 u11 120 0
2383 2383 0 b12 m111 u112 111 10800
2384 2384
2385 2385 $ hg log -r 'sort(all(), -branch)'
2386 2386 0 b12 m111 u112 111 10800
2387 2387 3 b112 m111 u11 120 0
2388 2388 2 b111 m11 u12 111 3600
2389 2389 4 b111 m112 u111 110 14400
2390 2390 1 b11 m12 u111 112 7200
2391 2391
2392 2392 $ hg log -r 'sort(all(), desc)'
2393 2393 2 b111 m11 u12 111 3600
2394 2394 0 b12 m111 u112 111 10800
2395 2395 3 b112 m111 u11 120 0
2396 2396 4 b111 m112 u111 110 14400
2397 2397 1 b11 m12 u111 112 7200
2398 2398
2399 2399 $ hg log -r 'sort(all(), -desc)'
2400 2400 1 b11 m12 u111 112 7200
2401 2401 4 b111 m112 u111 110 14400
2402 2402 0 b12 m111 u112 111 10800
2403 2403 3 b112 m111 u11 120 0
2404 2404 2 b111 m11 u12 111 3600
2405 2405
2406 2406 $ hg log -r 'sort(all(), user)'
2407 2407 3 b112 m111 u11 120 0
2408 2408 1 b11 m12 u111 112 7200
2409 2409 4 b111 m112 u111 110 14400
2410 2410 0 b12 m111 u112 111 10800
2411 2411 2 b111 m11 u12 111 3600
2412 2412
2413 2413 $ hg log -r 'sort(all(), -user)'
2414 2414 2 b111 m11 u12 111 3600
2415 2415 0 b12 m111 u112 111 10800
2416 2416 1 b11 m12 u111 112 7200
2417 2417 4 b111 m112 u111 110 14400
2418 2418 3 b112 m111 u11 120 0
2419 2419
2420 2420 compare dates (tz offset should have no effect):
2421 2421
2422 2422 $ hg log -r 'sort(all(), date)'
2423 2423 4 b111 m112 u111 110 14400
2424 2424 0 b12 m111 u112 111 10800
2425 2425 2 b111 m11 u12 111 3600
2426 2426 1 b11 m12 u111 112 7200
2427 2427 3 b112 m111 u11 120 0
2428 2428
2429 2429 $ hg log -r 'sort(all(), -date)'
2430 2430 3 b112 m111 u11 120 0
2431 2431 1 b11 m12 u111 112 7200
2432 2432 0 b12 m111 u112 111 10800
2433 2433 2 b111 m11 u12 111 3600
2434 2434 4 b111 m112 u111 110 14400
2435 2435
2436 2436 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2437 2437 because '-k' reverses the comparison, not the list itself:
2438 2438
2439 2439 $ hg log -r 'sort(0 + 2, date)'
2440 2440 0 b12 m111 u112 111 10800
2441 2441 2 b111 m11 u12 111 3600
2442 2442
2443 2443 $ hg log -r 'sort(0 + 2, -date)'
2444 2444 0 b12 m111 u112 111 10800
2445 2445 2 b111 m11 u12 111 3600
2446 2446
2447 2447 $ hg log -r 'reverse(sort(0 + 2, date))'
2448 2448 2 b111 m11 u12 111 3600
2449 2449 0 b12 m111 u112 111 10800
2450 2450
2451 2451 sort by multiple keys:
2452 2452
2453 2453 $ hg log -r 'sort(all(), "branch -rev")'
2454 2454 1 b11 m12 u111 112 7200
2455 2455 4 b111 m112 u111 110 14400
2456 2456 2 b111 m11 u12 111 3600
2457 2457 3 b112 m111 u11 120 0
2458 2458 0 b12 m111 u112 111 10800
2459 2459
2460 2460 $ hg log -r 'sort(all(), "-desc -date")'
2461 2461 1 b11 m12 u111 112 7200
2462 2462 4 b111 m112 u111 110 14400
2463 2463 3 b112 m111 u11 120 0
2464 2464 0 b12 m111 u112 111 10800
2465 2465 2 b111 m11 u12 111 3600
2466 2466
2467 2467 $ hg log -r 'sort(all(), "user -branch date rev")'
2468 2468 3 b112 m111 u11 120 0
2469 2469 4 b111 m112 u111 110 14400
2470 2470 1 b11 m12 u111 112 7200
2471 2471 0 b12 m111 u112 111 10800
2472 2472 2 b111 m11 u12 111 3600
2473 2473
2474 2474 toposort prioritises graph branches
2475 2475
2476 2476 $ hg up 2
2477 2477 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2478 2478 $ touch a
2479 2479 $ hg addremove
2480 2480 adding a
2481 2481 $ hg ci -m 't1' -u 'tu' -d '130 0'
2482 2482 created new head
2483 2483 $ echo 'a' >> a
2484 2484 $ hg ci -m 't2' -u 'tu' -d '130 0'
2485 2485 $ hg book book1
2486 2486 $ hg up 4
2487 2487 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2488 2488 (leaving bookmark book1)
2489 2489 $ touch a
2490 2490 $ hg addremove
2491 2491 adding a
2492 2492 $ hg ci -m 't3' -u 'tu' -d '130 0'
2493 2493
2494 2494 $ hg log -r 'sort(all(), topo)'
2495 2495 7 b111 t3 tu 130 0
2496 2496 4 b111 m112 u111 110 14400
2497 2497 3 b112 m111 u11 120 0
2498 2498 6 b111 t2 tu 130 0
2499 2499 5 b111 t1 tu 130 0
2500 2500 2 b111 m11 u12 111 3600
2501 2501 1 b11 m12 u111 112 7200
2502 2502 0 b12 m111 u112 111 10800
2503 2503
2504 2504 $ hg log -r 'sort(all(), -topo)'
2505 2505 0 b12 m111 u112 111 10800
2506 2506 1 b11 m12 u111 112 7200
2507 2507 2 b111 m11 u12 111 3600
2508 2508 5 b111 t1 tu 130 0
2509 2509 6 b111 t2 tu 130 0
2510 2510 3 b112 m111 u11 120 0
2511 2511 4 b111 m112 u111 110 14400
2512 2512 7 b111 t3 tu 130 0
2513 2513
2514 2514 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2515 2515 6 b111 t2 tu 130 0
2516 2516 5 b111 t1 tu 130 0
2517 2517 7 b111 t3 tu 130 0
2518 2518 4 b111 m112 u111 110 14400
2519 2519 3 b112 m111 u11 120 0
2520 2520 2 b111 m11 u12 111 3600
2521 2521 1 b11 m12 u111 112 7200
2522 2522 0 b12 m111 u112 111 10800
2523 2523
2524 2524 topographical sorting can't be combined with other sort keys, and you can't
2525 2525 use the topo.firstbranch option when topo sort is not active:
2526 2526
2527 2527 $ hg log -r 'sort(all(), "topo user")'
2528 2528 hg: parse error: topo sort order cannot be combined with other sort keys
2529 2529 [255]
2530 2530
2531 2531 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2532 2532 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2533 2533 [255]
2534 2534
2535 2535 topo.firstbranch should accept any kind of expressions:
2536 2536
2537 2537 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2538 2538 0 b12 m111 u112 111 10800
2539 2539
2540 2540 $ cd ..
2541 2541 $ cd repo
2542 2542
2543 2543 test subtracting something from an addset
2544 2544
2545 2545 $ log '(outgoing() or removes(a)) - removes(a)'
2546 2546 8
2547 2547 9
2548 2548
2549 2549 test intersecting something with an addset
2550 2550
2551 2551 $ log 'parents(outgoing() or removes(a))'
2552 2552 1
2553 2553 4
2554 2554 5
2555 2555 8
2556 2556
2557 2557 test that `or` operation combines elements in the right order:
2558 2558
2559 2559 $ log '3:4 or 2:5'
2560 2560 3
2561 2561 4
2562 2562 2
2563 2563 5
2564 2564 $ log '3:4 or 5:2'
2565 2565 3
2566 2566 4
2567 2567 5
2568 2568 2
2569 2569 $ log 'sort(3:4 or 2:5)'
2570 2570 2
2571 2571 3
2572 2572 4
2573 2573 5
2574 2574 $ log 'sort(3:4 or 5:2)'
2575 2575 2
2576 2576 3
2577 2577 4
2578 2578 5
2579 2579
2580 2580 test that more than one `-r`s are combined in the right order and deduplicated:
2581 2581
2582 2582 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2583 2583 3
2584 2584 4
2585 2585 5
2586 2586 2
2587 2587 0
2588 2588 1
2589 2589
2590 2590 test that `or` operation skips duplicated revisions from right-hand side
2591 2591
2592 2592 $ try 'reverse(1::5) or ancestors(4)'
2593 2593 (or
2594 2594 (list
2595 2595 (func
2596 2596 ('symbol', 'reverse')
2597 2597 (dagrange
2598 2598 ('symbol', '1')
2599 2599 ('symbol', '5')))
2600 2600 (func
2601 2601 ('symbol', 'ancestors')
2602 2602 ('symbol', '4'))))
2603 2603 * set:
2604 2604 <addset
2605 2605 <baseset- [1, 3, 5]>,
2606 2606 <generatorset+>>
2607 2607 5
2608 2608 3
2609 2609 1
2610 2610 0
2611 2611 2
2612 2612 4
2613 2613 $ try 'sort(ancestors(4) or reverse(1::5))'
2614 2614 (func
2615 2615 ('symbol', 'sort')
2616 2616 (or
2617 2617 (list
2618 2618 (func
2619 2619 ('symbol', 'ancestors')
2620 2620 ('symbol', '4'))
2621 2621 (func
2622 2622 ('symbol', 'reverse')
2623 2623 (dagrange
2624 2624 ('symbol', '1')
2625 2625 ('symbol', '5'))))))
2626 2626 * set:
2627 2627 <addset+
2628 2628 <generatorset+>,
2629 2629 <baseset- [1, 3, 5]>>
2630 2630 0
2631 2631 1
2632 2632 2
2633 2633 3
2634 2634 4
2635 2635 5
2636 2636
2637 2637 test optimization of trivial `or` operation
2638 2638
2639 2639 $ try --optimize '0|(1)|"2"|-2|tip|null'
2640 2640 (or
2641 2641 (list
2642 2642 ('symbol', '0')
2643 2643 (group
2644 2644 ('symbol', '1'))
2645 2645 ('string', '2')
2646 2646 (negate
2647 2647 ('symbol', '2'))
2648 2648 ('symbol', 'tip')
2649 2649 ('symbol', 'null')))
2650 2650 * optimized:
2651 2651 (func
2652 2652 ('symbol', '_list')
2653 2653 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2654 2654 define)
2655 2655 * set:
2656 2656 <baseset [0, 1, 2, 8, 9, -1]>
2657 2657 0
2658 2658 1
2659 2659 2
2660 2660 8
2661 2661 9
2662 2662 -1
2663 2663
2664 2664 $ try --optimize '0|1|2:3'
2665 2665 (or
2666 2666 (list
2667 2667 ('symbol', '0')
2668 2668 ('symbol', '1')
2669 2669 (range
2670 2670 ('symbol', '2')
2671 2671 ('symbol', '3'))))
2672 2672 * optimized:
2673 2673 (or
2674 2674 (list
2675 2675 (func
2676 2676 ('symbol', '_list')
2677 2677 ('string', '0\x001')
2678 2678 define)
2679 2679 (range
2680 2680 ('symbol', '2')
2681 2681 ('symbol', '3')
2682 2682 define))
2683 2683 define)
2684 2684 * set:
2685 2685 <addset
2686 2686 <baseset [0, 1]>,
2687 2687 <spanset+ 2:4>>
2688 2688 0
2689 2689 1
2690 2690 2
2691 2691 3
2692 2692
2693 2693 $ try --optimize '0:1|2|3:4|5|6'
2694 2694 (or
2695 2695 (list
2696 2696 (range
2697 2697 ('symbol', '0')
2698 2698 ('symbol', '1'))
2699 2699 ('symbol', '2')
2700 2700 (range
2701 2701 ('symbol', '3')
2702 2702 ('symbol', '4'))
2703 2703 ('symbol', '5')
2704 2704 ('symbol', '6')))
2705 2705 * optimized:
2706 2706 (or
2707 2707 (list
2708 2708 (range
2709 2709 ('symbol', '0')
2710 2710 ('symbol', '1')
2711 2711 define)
2712 2712 ('symbol', '2')
2713 2713 (range
2714 2714 ('symbol', '3')
2715 2715 ('symbol', '4')
2716 2716 define)
2717 2717 (func
2718 2718 ('symbol', '_list')
2719 2719 ('string', '5\x006')
2720 2720 define))
2721 2721 define)
2722 2722 * set:
2723 2723 <addset
2724 2724 <addset
2725 2725 <spanset+ 0:2>,
2726 2726 <baseset [2]>>,
2727 2727 <addset
2728 2728 <spanset+ 3:5>,
2729 2729 <baseset [5, 6]>>>
2730 2730 0
2731 2731 1
2732 2732 2
2733 2733 3
2734 2734 4
2735 2735 5
2736 2736 6
2737 2737
2738 2738 unoptimized `or` looks like this
2739 2739
2740 2740 $ try --no-optimized -p analyzed '0|1|2|3|4'
2741 2741 * analyzed:
2742 2742 (or
2743 2743 (list
2744 2744 ('symbol', '0')
2745 2745 ('symbol', '1')
2746 2746 ('symbol', '2')
2747 2747 ('symbol', '3')
2748 2748 ('symbol', '4'))
2749 2749 define)
2750 2750 * set:
2751 2751 <addset
2752 2752 <addset
2753 2753 <baseset [0]>,
2754 2754 <baseset [1]>>,
2755 2755 <addset
2756 2756 <baseset [2]>,
2757 2757 <addset
2758 2758 <baseset [3]>,
2759 2759 <baseset [4]>>>>
2760 2760 0
2761 2761 1
2762 2762 2
2763 2763 3
2764 2764 4
2765 2765
2766 2766 test that `_list` should be narrowed by provided `subset`
2767 2767
2768 2768 $ log '0:2 and (null|1|2|3)'
2769 2769 1
2770 2770 2
2771 2771
2772 2772 test that `_list` should remove duplicates
2773 2773
2774 2774 $ log '0|1|2|1|2|-1|tip'
2775 2775 0
2776 2776 1
2777 2777 2
2778 2778 9
2779 2779
2780 2780 test unknown revision in `_list`
2781 2781
2782 2782 $ log '0|unknown'
2783 2783 abort: unknown revision 'unknown'!
2784 2784 [255]
2785 2785
2786 2786 test integer range in `_list`
2787 2787
2788 2788 $ log '-1|-10'
2789 2789 9
2790 2790 0
2791 2791
2792 2792 $ log '-10|-11'
2793 2793 abort: unknown revision '-11'!
2794 2794 [255]
2795 2795
2796 2796 $ log '9|10'
2797 2797 abort: unknown revision '10'!
2798 2798 [255]
2799 2799
2800 2800 test '0000' != '0' in `_list`
2801 2801
2802 2802 $ log '0|0000'
2803 2803 0
2804 2804 -1
2805 2805
2806 2806 test ',' in `_list`
2807 2807 $ log '0,1'
2808 2808 hg: parse error: can't use a list in this context
2809 2809 (see hg help "revsets.x or y")
2810 2810 [255]
2811 2811 $ try '0,1,2'
2812 2812 (list
2813 2813 ('symbol', '0')
2814 2814 ('symbol', '1')
2815 2815 ('symbol', '2'))
2816 2816 hg: parse error: can't use a list in this context
2817 2817 (see hg help "revsets.x or y")
2818 2818 [255]
2819 2819
2820 2820 test that chained `or` operations make balanced addsets
2821 2821
2822 2822 $ try '0:1|1:2|2:3|3:4|4:5'
2823 2823 (or
2824 2824 (list
2825 2825 (range
2826 2826 ('symbol', '0')
2827 2827 ('symbol', '1'))
2828 2828 (range
2829 2829 ('symbol', '1')
2830 2830 ('symbol', '2'))
2831 2831 (range
2832 2832 ('symbol', '2')
2833 2833 ('symbol', '3'))
2834 2834 (range
2835 2835 ('symbol', '3')
2836 2836 ('symbol', '4'))
2837 2837 (range
2838 2838 ('symbol', '4')
2839 2839 ('symbol', '5'))))
2840 2840 * set:
2841 2841 <addset
2842 2842 <addset
2843 2843 <spanset+ 0:2>,
2844 2844 <spanset+ 1:3>>,
2845 2845 <addset
2846 2846 <spanset+ 2:4>,
2847 2847 <addset
2848 2848 <spanset+ 3:5>,
2849 2849 <spanset+ 4:6>>>>
2850 2850 0
2851 2851 1
2852 2852 2
2853 2853 3
2854 2854 4
2855 2855 5
2856 2856
2857 2857 no crash by empty group "()" while optimizing `or` operations
2858 2858
2859 2859 $ try --optimize '0|()'
2860 2860 (or
2861 2861 (list
2862 2862 ('symbol', '0')
2863 2863 (group
2864 2864 None)))
2865 2865 * optimized:
2866 2866 (or
2867 2867 (list
2868 2868 ('symbol', '0')
2869 2869 None)
2870 2870 define)
2871 2871 hg: parse error: missing argument
2872 2872 [255]
2873 2873
2874 2874 test that chained `or` operations never eat up stack (issue4624)
2875 2875 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2876 2876
2877 2877 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2878 2878 0
2879 2879 1
2880 2880
2881 2881 test that repeated `-r` options never eat up stack (issue4565)
2882 2882 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2883 2883
2884 2884 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2885 2885 0
2886 2886 1
2887 2887
2888 2888 check that conversion to only works
2889 2889 $ try --optimize '::3 - ::1'
2890 2890 (minus
2891 2891 (dagrangepre
2892 2892 ('symbol', '3'))
2893 2893 (dagrangepre
2894 2894 ('symbol', '1')))
2895 2895 * optimized:
2896 2896 (func
2897 2897 ('symbol', 'only')
2898 2898 (list
2899 2899 ('symbol', '3')
2900 2900 ('symbol', '1'))
2901 2901 define)
2902 2902 * set:
2903 2903 <baseset+ [3]>
2904 2904 3
2905 2905 $ try --optimize 'ancestors(1) - ancestors(3)'
2906 2906 (minus
2907 2907 (func
2908 2908 ('symbol', 'ancestors')
2909 2909 ('symbol', '1'))
2910 2910 (func
2911 2911 ('symbol', 'ancestors')
2912 2912 ('symbol', '3')))
2913 2913 * optimized:
2914 2914 (func
2915 2915 ('symbol', 'only')
2916 2916 (list
2917 2917 ('symbol', '1')
2918 2918 ('symbol', '3'))
2919 2919 define)
2920 2920 * set:
2921 2921 <baseset+ []>
2922 2922 $ try --optimize 'not ::2 and ::6'
2923 2923 (and
2924 2924 (not
2925 2925 (dagrangepre
2926 2926 ('symbol', '2')))
2927 2927 (dagrangepre
2928 2928 ('symbol', '6')))
2929 2929 * optimized:
2930 2930 (func
2931 2931 ('symbol', 'only')
2932 2932 (list
2933 2933 ('symbol', '6')
2934 2934 ('symbol', '2'))
2935 2935 define)
2936 2936 * set:
2937 2937 <baseset+ [3, 4, 5, 6]>
2938 2938 3
2939 2939 4
2940 2940 5
2941 2941 6
2942 2942 $ try --optimize 'ancestors(6) and not ancestors(4)'
2943 2943 (and
2944 2944 (func
2945 2945 ('symbol', 'ancestors')
2946 2946 ('symbol', '6'))
2947 2947 (not
2948 2948 (func
2949 2949 ('symbol', 'ancestors')
2950 2950 ('symbol', '4'))))
2951 2951 * optimized:
2952 2952 (func
2953 2953 ('symbol', 'only')
2954 2954 (list
2955 2955 ('symbol', '6')
2956 2956 ('symbol', '4'))
2957 2957 define)
2958 2958 * set:
2959 2959 <baseset+ [3, 5, 6]>
2960 2960 3
2961 2961 5
2962 2962 6
2963 2963
2964 2964 no crash by empty group "()" while optimizing to "only()"
2965 2965
2966 2966 $ try --optimize '::1 and ()'
2967 2967 (and
2968 2968 (dagrangepre
2969 2969 ('symbol', '1'))
2970 2970 (group
2971 2971 None))
2972 2972 * optimized:
2973 2973 (and
2974 2974 None
2975 2975 (func
2976 2976 ('symbol', 'ancestors')
2977 2977 ('symbol', '1')
2978 2978 define)
2979 2979 define)
2980 2980 hg: parse error: missing argument
2981 2981 [255]
2982 2982
2983 optimization to only() works only if ancestors() takes only one argument
2984
2985 $ hg debugrevspec -p optimized 'ancestors(6) - ancestors(4, 1)'
2986 * optimized:
2987 (difference
2988 (func
2989 ('symbol', 'ancestors')
2990 ('symbol', '6')
2991 define)
2992 (func
2993 ('symbol', 'ancestors')
2994 (list
2995 ('symbol', '4')
2996 ('symbol', '1'))
2997 any)
2998 define)
2999 hg: parse error: can't use a list in this context
3000 (see hg help "revsets.x or y")
3001 [255]
3002 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3003 * optimized:
3004 (difference
3005 (func
3006 ('symbol', 'ancestors')
3007 (list
3008 ('symbol', '6')
3009 ('symbol', '1'))
3010 define)
3011 (func
3012 ('symbol', 'ancestors')
3013 ('symbol', '4')
3014 any)
3015 define)
3016 hg: parse error: can't use a list in this context
3017 (see hg help "revsets.x or y")
3018 [255]
3019
3020 optimization disabled if keyword arguments passed (because we're too lazy
3021 to support it)
3022
3023 $ hg debugrevspec -p optimized 'ancestors(set=6) - ancestors(set=4)'
3024 * optimized:
3025 (difference
3026 (func
3027 ('symbol', 'ancestors')
3028 (keyvalue
3029 ('symbol', 'set')
3030 ('symbol', '6'))
3031 define)
3032 (func
3033 ('symbol', 'ancestors')
3034 (keyvalue
3035 ('symbol', 'set')
3036 ('symbol', '4'))
3037 any)
3038 define)
3039 hg: parse error: can't use a key-value pair in this context
3040 [255]
3041
2983 3042 invalid function call should not be optimized to only()
2984 3043
2985 3044 $ log '"ancestors"(6) and not ancestors(4)'
2986 3045 hg: parse error: not a symbol
2987 3046 [255]
2988 3047
2989 3048 $ log 'ancestors(6) and not "ancestors"(4)'
2990 3049 hg: parse error: not a symbol
2991 3050 [255]
2992 3051
2993 3052 we can use patterns when searching for tags
2994 3053
2995 3054 $ log 'tag("1..*")'
2996 3055 abort: tag '1..*' does not exist!
2997 3056 [255]
2998 3057 $ log 'tag("re:1..*")'
2999 3058 6
3000 3059 $ log 'tag("re:[0-9].[0-9]")'
3001 3060 6
3002 3061 $ log 'tag("literal:1.0")'
3003 3062 6
3004 3063 $ log 'tag("re:0..*")'
3005 3064
3006 3065 $ log 'tag(unknown)'
3007 3066 abort: tag 'unknown' does not exist!
3008 3067 [255]
3009 3068 $ log 'tag("re:unknown")'
3010 3069 $ log 'present(tag("unknown"))'
3011 3070 $ log 'present(tag("re:unknown"))'
3012 3071 $ log 'branch(unknown)'
3013 3072 abort: unknown revision 'unknown'!
3014 3073 [255]
3015 3074 $ log 'branch("literal:unknown")'
3016 3075 abort: branch 'unknown' does not exist!
3017 3076 [255]
3018 3077 $ log 'branch("re:unknown")'
3019 3078 $ log 'present(branch("unknown"))'
3020 3079 $ log 'present(branch("re:unknown"))'
3021 3080 $ log 'user(bob)'
3022 3081 2
3023 3082
3024 3083 $ log '4::8'
3025 3084 4
3026 3085 8
3027 3086 $ log '4:8'
3028 3087 4
3029 3088 5
3030 3089 6
3031 3090 7
3032 3091 8
3033 3092
3034 3093 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
3035 3094 4
3036 3095 2
3037 3096 5
3038 3097
3039 3098 $ log 'not 0 and 0:2'
3040 3099 1
3041 3100 2
3042 3101 $ log 'not 1 and 0:2'
3043 3102 0
3044 3103 2
3045 3104 $ log 'not 2 and 0:2'
3046 3105 0
3047 3106 1
3048 3107 $ log '(1 and 2)::'
3049 3108 $ log '(1 and 2):'
3050 3109 $ log '(1 and 2):3'
3051 3110 $ log 'sort(head(), -rev)'
3052 3111 9
3053 3112 7
3054 3113 6
3055 3114 5
3056 3115 4
3057 3116 3
3058 3117 2
3059 3118 1
3060 3119 0
3061 3120 $ log '4::8 - 8'
3062 3121 4
3063 3122
3064 3123 matching() should preserve the order of the input set:
3065 3124
3066 3125 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
3067 3126 2
3068 3127 3
3069 3128 1
3070 3129
3071 3130 $ log 'named("unknown")'
3072 3131 abort: namespace 'unknown' does not exist!
3073 3132 [255]
3074 3133 $ log 'named("re:unknown")'
3075 3134 abort: no namespace exists that match 'unknown'!
3076 3135 [255]
3077 3136 $ log 'present(named("unknown"))'
3078 3137 $ log 'present(named("re:unknown"))'
3079 3138
3080 3139 $ log 'tag()'
3081 3140 6
3082 3141 $ log 'named("tags")'
3083 3142 6
3084 3143
3085 3144 issue2437
3086 3145
3087 3146 $ log '3 and p1(5)'
3088 3147 3
3089 3148 $ log '4 and p2(6)'
3090 3149 4
3091 3150 $ log '1 and parents(:2)'
3092 3151 1
3093 3152 $ log '2 and children(1:)'
3094 3153 2
3095 3154 $ log 'roots(all()) or roots(all())'
3096 3155 0
3097 3156 $ hg debugrevspec 'roots(all()) or roots(all())'
3098 3157 0
3099 3158 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
3100 3159 9
3101 3160 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
3102 3161 4
3103 3162
3104 3163 issue2654: report a parse error if the revset was not completely parsed
3105 3164
3106 3165 $ log '1 OR 2'
3107 3166 hg: parse error at 2: invalid token
3108 3167 [255]
3109 3168
3110 3169 or operator should preserve ordering:
3111 3170 $ log 'reverse(2::4) or tip'
3112 3171 4
3113 3172 2
3114 3173 9
3115 3174
3116 3175 parentrevspec
3117 3176
3118 3177 $ log 'merge()^0'
3119 3178 6
3120 3179 $ log 'merge()^'
3121 3180 5
3122 3181 $ log 'merge()^1'
3123 3182 5
3124 3183 $ log 'merge()^2'
3125 3184 4
3126 3185 $ log '(not merge())^2'
3127 3186 $ log 'merge()^^'
3128 3187 3
3129 3188 $ log 'merge()^1^'
3130 3189 3
3131 3190 $ log 'merge()^^^'
3132 3191 1
3133 3192
3134 3193 $ hg debugrevspec -s '(merge() | 0)~-1'
3135 3194 * set:
3136 3195 <baseset+ [1, 7]>
3137 3196 1
3138 3197 7
3139 3198 $ log 'merge()~-1'
3140 3199 7
3141 3200 $ log 'tip~-1'
3142 3201 $ log '(tip | merge())~-1'
3143 3202 7
3144 3203 $ log 'merge()~0'
3145 3204 6
3146 3205 $ log 'merge()~1'
3147 3206 5
3148 3207 $ log 'merge()~2'
3149 3208 3
3150 3209 $ log 'merge()~2^1'
3151 3210 1
3152 3211 $ log 'merge()~3'
3153 3212 1
3154 3213
3155 3214 $ log '(-3:tip)^'
3156 3215 4
3157 3216 6
3158 3217 8
3159 3218
3160 3219 $ log 'tip^foo'
3161 3220 hg: parse error: ^ expects a number 0, 1, or 2
3162 3221 [255]
3163 3222
3164 3223 $ log 'branchpoint()~-1'
3165 3224 abort: revision in set has more than one child!
3166 3225 [255]
3167 3226
3168 3227 Bogus function gets suggestions
3169 3228 $ log 'add()'
3170 3229 hg: parse error: unknown identifier: add
3171 3230 (did you mean adds?)
3172 3231 [255]
3173 3232 $ log 'added()'
3174 3233 hg: parse error: unknown identifier: added
3175 3234 (did you mean adds?)
3176 3235 [255]
3177 3236 $ log 'remo()'
3178 3237 hg: parse error: unknown identifier: remo
3179 3238 (did you mean one of remote, removes?)
3180 3239 [255]
3181 3240 $ log 'babar()'
3182 3241 hg: parse error: unknown identifier: babar
3183 3242 [255]
3184 3243
3185 3244 Bogus function with a similar internal name doesn't suggest the internal name
3186 3245 $ log 'matches()'
3187 3246 hg: parse error: unknown identifier: matches
3188 3247 (did you mean matching?)
3189 3248 [255]
3190 3249
3191 3250 Undocumented functions aren't suggested as similar either
3192 3251 $ log 'tagged2()'
3193 3252 hg: parse error: unknown identifier: tagged2
3194 3253 [255]
3195 3254
3196 3255 multiple revspecs
3197 3256
3198 3257 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3199 3258 8
3200 3259 9
3201 3260 4
3202 3261 5
3203 3262 6
3204 3263 7
3205 3264
3206 3265 test usage in revpair (with "+")
3207 3266
3208 3267 (real pair)
3209 3268
3210 3269 $ hg diff -r 'tip^^' -r 'tip'
3211 3270 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3212 3271 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3213 3272 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3214 3273 @@ -0,0 +1,1 @@
3215 3274 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3216 3275 $ hg diff -r 'tip^^::tip'
3217 3276 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3218 3277 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3219 3278 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3220 3279 @@ -0,0 +1,1 @@
3221 3280 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3222 3281
3223 3282 (single rev)
3224 3283
3225 3284 $ hg diff -r 'tip^' -r 'tip^'
3226 3285 $ hg diff -r 'tip^:tip^'
3227 3286
3228 3287 (single rev that does not looks like a range)
3229 3288
3230 3289 $ hg diff -r 'tip^::tip^ or tip^'
3231 3290 diff -r d5d0dcbdc4d9 .hgtags
3232 3291 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3233 3292 +++ b/.hgtags * (glob)
3234 3293 @@ -0,0 +1,1 @@
3235 3294 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3236 3295 $ hg diff -r 'tip^ or tip^'
3237 3296 diff -r d5d0dcbdc4d9 .hgtags
3238 3297 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3239 3298 +++ b/.hgtags * (glob)
3240 3299 @@ -0,0 +1,1 @@
3241 3300 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3242 3301
3243 3302 (no rev)
3244 3303
3245 3304 $ hg diff -r 'author("babar") or author("celeste")'
3246 3305 abort: empty revision range
3247 3306 [255]
3248 3307
3249 3308 aliases:
3250 3309
3251 3310 $ echo '[revsetalias]' >> .hg/hgrc
3252 3311 $ echo 'm = merge()' >> .hg/hgrc
3253 3312 (revset aliases can override builtin revsets)
3254 3313 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3255 3314 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3256 3315 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3257 3316 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3258 3317 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3259 3318
3260 3319 $ try m
3261 3320 ('symbol', 'm')
3262 3321 * expanded:
3263 3322 (func
3264 3323 ('symbol', 'merge')
3265 3324 None)
3266 3325 * set:
3267 3326 <filteredset
3268 3327 <fullreposet+ 0:10>,
3269 3328 <merge>>
3270 3329 6
3271 3330
3272 3331 $ HGPLAIN=1
3273 3332 $ export HGPLAIN
3274 3333 $ try m
3275 3334 ('symbol', 'm')
3276 3335 abort: unknown revision 'm'!
3277 3336 [255]
3278 3337
3279 3338 $ HGPLAINEXCEPT=revsetalias
3280 3339 $ export HGPLAINEXCEPT
3281 3340 $ try m
3282 3341 ('symbol', 'm')
3283 3342 * expanded:
3284 3343 (func
3285 3344 ('symbol', 'merge')
3286 3345 None)
3287 3346 * set:
3288 3347 <filteredset
3289 3348 <fullreposet+ 0:10>,
3290 3349 <merge>>
3291 3350 6
3292 3351
3293 3352 $ unset HGPLAIN
3294 3353 $ unset HGPLAINEXCEPT
3295 3354
3296 3355 $ try 'p2(.)'
3297 3356 (func
3298 3357 ('symbol', 'p2')
3299 3358 ('symbol', '.'))
3300 3359 * expanded:
3301 3360 (func
3302 3361 ('symbol', 'p1')
3303 3362 ('symbol', '.'))
3304 3363 * set:
3305 3364 <baseset+ [8]>
3306 3365 8
3307 3366
3308 3367 $ HGPLAIN=1
3309 3368 $ export HGPLAIN
3310 3369 $ try 'p2(.)'
3311 3370 (func
3312 3371 ('symbol', 'p2')
3313 3372 ('symbol', '.'))
3314 3373 * set:
3315 3374 <baseset+ []>
3316 3375
3317 3376 $ HGPLAINEXCEPT=revsetalias
3318 3377 $ export HGPLAINEXCEPT
3319 3378 $ try 'p2(.)'
3320 3379 (func
3321 3380 ('symbol', 'p2')
3322 3381 ('symbol', '.'))
3323 3382 * expanded:
3324 3383 (func
3325 3384 ('symbol', 'p1')
3326 3385 ('symbol', '.'))
3327 3386 * set:
3328 3387 <baseset+ [8]>
3329 3388 8
3330 3389
3331 3390 $ unset HGPLAIN
3332 3391 $ unset HGPLAINEXCEPT
3333 3392
3334 3393 test alias recursion
3335 3394
3336 3395 $ try sincem
3337 3396 ('symbol', 'sincem')
3338 3397 * expanded:
3339 3398 (func
3340 3399 ('symbol', 'descendants')
3341 3400 (func
3342 3401 ('symbol', 'merge')
3343 3402 None))
3344 3403 * set:
3345 3404 <addset+
3346 3405 <filteredset
3347 3406 <fullreposet+ 0:10>,
3348 3407 <merge>>,
3349 3408 <generatorset+>>
3350 3409 6
3351 3410 7
3352 3411
3353 3412 test infinite recursion
3354 3413
3355 3414 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3356 3415 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3357 3416 $ try recurse1
3358 3417 ('symbol', 'recurse1')
3359 3418 hg: parse error: infinite expansion of revset alias "recurse1" detected
3360 3419 [255]
3361 3420
3362 3421 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3363 3422 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3364 3423 $ try "level2(level1(1, 2), 3)"
3365 3424 (func
3366 3425 ('symbol', 'level2')
3367 3426 (list
3368 3427 (func
3369 3428 ('symbol', 'level1')
3370 3429 (list
3371 3430 ('symbol', '1')
3372 3431 ('symbol', '2')))
3373 3432 ('symbol', '3')))
3374 3433 * expanded:
3375 3434 (or
3376 3435 (list
3377 3436 ('symbol', '3')
3378 3437 (or
3379 3438 (list
3380 3439 ('symbol', '1')
3381 3440 ('symbol', '2')))))
3382 3441 * set:
3383 3442 <addset
3384 3443 <baseset [3]>,
3385 3444 <baseset [1, 2]>>
3386 3445 3
3387 3446 1
3388 3447 2
3389 3448
3390 3449 test nesting and variable passing
3391 3450
3392 3451 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3393 3452 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3394 3453 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3395 3454 $ try 'nested(2:5)'
3396 3455 (func
3397 3456 ('symbol', 'nested')
3398 3457 (range
3399 3458 ('symbol', '2')
3400 3459 ('symbol', '5')))
3401 3460 * expanded:
3402 3461 (func
3403 3462 ('symbol', 'max')
3404 3463 (range
3405 3464 ('symbol', '2')
3406 3465 ('symbol', '5')))
3407 3466 * set:
3408 3467 <baseset
3409 3468 <max
3410 3469 <fullreposet+ 0:10>,
3411 3470 <spanset+ 2:6>>>
3412 3471 5
3413 3472
3414 3473 test chained `or` operations are flattened at parsing phase
3415 3474
3416 3475 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3417 3476 $ try 'chainedorops(0:1, 1:2, 2:3)'
3418 3477 (func
3419 3478 ('symbol', 'chainedorops')
3420 3479 (list
3421 3480 (range
3422 3481 ('symbol', '0')
3423 3482 ('symbol', '1'))
3424 3483 (range
3425 3484 ('symbol', '1')
3426 3485 ('symbol', '2'))
3427 3486 (range
3428 3487 ('symbol', '2')
3429 3488 ('symbol', '3'))))
3430 3489 * expanded:
3431 3490 (or
3432 3491 (list
3433 3492 (range
3434 3493 ('symbol', '0')
3435 3494 ('symbol', '1'))
3436 3495 (range
3437 3496 ('symbol', '1')
3438 3497 ('symbol', '2'))
3439 3498 (range
3440 3499 ('symbol', '2')
3441 3500 ('symbol', '3'))))
3442 3501 * set:
3443 3502 <addset
3444 3503 <spanset+ 0:2>,
3445 3504 <addset
3446 3505 <spanset+ 1:3>,
3447 3506 <spanset+ 2:4>>>
3448 3507 0
3449 3508 1
3450 3509 2
3451 3510 3
3452 3511
3453 3512 test variable isolation, variable placeholders are rewritten as string
3454 3513 then parsed and matched again as string. Check they do not leak too
3455 3514 far away.
3456 3515
3457 3516 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3458 3517 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3459 3518 $ try 'callinjection(2:5)'
3460 3519 (func
3461 3520 ('symbol', 'callinjection')
3462 3521 (range
3463 3522 ('symbol', '2')
3464 3523 ('symbol', '5')))
3465 3524 * expanded:
3466 3525 (func
3467 3526 ('symbol', 'descendants')
3468 3527 (func
3469 3528 ('symbol', 'max')
3470 3529 ('string', '$1')))
3471 3530 abort: unknown revision '$1'!
3472 3531 [255]
3473 3532
3474 3533 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3475 3534 but 'all()' should never be substituted to '0()'.
3476 3535
3477 3536 $ echo 'universe = all()' >> .hg/hgrc
3478 3537 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3479 3538 $ try 'shadowall(0)'
3480 3539 (func
3481 3540 ('symbol', 'shadowall')
3482 3541 ('symbol', '0'))
3483 3542 * expanded:
3484 3543 (and
3485 3544 ('symbol', '0')
3486 3545 (func
3487 3546 ('symbol', 'all')
3488 3547 None))
3489 3548 * set:
3490 3549 <filteredset
3491 3550 <baseset [0]>,
3492 3551 <spanset+ 0:10>>
3493 3552 0
3494 3553
3495 3554 test unknown reference:
3496 3555
3497 3556 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3498 3557 (func
3499 3558 ('symbol', 'unknownref')
3500 3559 ('symbol', '0'))
3501 3560 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3502 3561 [255]
3503 3562
3504 3563 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3505 3564 ('symbol', 'tip')
3506 3565 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3507 3566 * set:
3508 3567 <baseset [9]>
3509 3568 9
3510 3569
3511 3570 $ try 'tip'
3512 3571 ('symbol', 'tip')
3513 3572 * set:
3514 3573 <baseset [9]>
3515 3574 9
3516 3575
3517 3576 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3518 3577 ('symbol', 'tip')
3519 3578 warning: bad declaration of revset alias "bad name": at 4: invalid token
3520 3579 * set:
3521 3580 <baseset [9]>
3522 3581 9
3523 3582 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3524 3583 $ try 'strictreplacing("foo", tip)'
3525 3584 (func
3526 3585 ('symbol', 'strictreplacing')
3527 3586 (list
3528 3587 ('string', 'foo')
3529 3588 ('symbol', 'tip')))
3530 3589 * expanded:
3531 3590 (or
3532 3591 (list
3533 3592 ('symbol', 'tip')
3534 3593 (func
3535 3594 ('symbol', 'desc')
3536 3595 ('string', '$1'))))
3537 3596 * set:
3538 3597 <addset
3539 3598 <baseset [9]>,
3540 3599 <filteredset
3541 3600 <fullreposet+ 0:10>,
3542 3601 <desc '$1'>>>
3543 3602 9
3544 3603
3545 3604 $ try 'd(2:5)'
3546 3605 (func
3547 3606 ('symbol', 'd')
3548 3607 (range
3549 3608 ('symbol', '2')
3550 3609 ('symbol', '5')))
3551 3610 * expanded:
3552 3611 (func
3553 3612 ('symbol', 'reverse')
3554 3613 (func
3555 3614 ('symbol', 'sort')
3556 3615 (list
3557 3616 (range
3558 3617 ('symbol', '2')
3559 3618 ('symbol', '5'))
3560 3619 ('symbol', 'date'))))
3561 3620 * set:
3562 3621 <baseset [4, 5, 3, 2]>
3563 3622 4
3564 3623 5
3565 3624 3
3566 3625 2
3567 3626 $ try 'rs(2 or 3, date)'
3568 3627 (func
3569 3628 ('symbol', 'rs')
3570 3629 (list
3571 3630 (or
3572 3631 (list
3573 3632 ('symbol', '2')
3574 3633 ('symbol', '3')))
3575 3634 ('symbol', 'date')))
3576 3635 * expanded:
3577 3636 (func
3578 3637 ('symbol', 'reverse')
3579 3638 (func
3580 3639 ('symbol', 'sort')
3581 3640 (list
3582 3641 (or
3583 3642 (list
3584 3643 ('symbol', '2')
3585 3644 ('symbol', '3')))
3586 3645 ('symbol', 'date'))))
3587 3646 * set:
3588 3647 <baseset [3, 2]>
3589 3648 3
3590 3649 2
3591 3650 $ try 'rs()'
3592 3651 (func
3593 3652 ('symbol', 'rs')
3594 3653 None)
3595 3654 hg: parse error: invalid number of arguments: 0
3596 3655 [255]
3597 3656 $ try 'rs(2)'
3598 3657 (func
3599 3658 ('symbol', 'rs')
3600 3659 ('symbol', '2'))
3601 3660 hg: parse error: invalid number of arguments: 1
3602 3661 [255]
3603 3662 $ try 'rs(2, data, 7)'
3604 3663 (func
3605 3664 ('symbol', 'rs')
3606 3665 (list
3607 3666 ('symbol', '2')
3608 3667 ('symbol', 'data')
3609 3668 ('symbol', '7')))
3610 3669 hg: parse error: invalid number of arguments: 3
3611 3670 [255]
3612 3671 $ try 'rs4(2 or 3, x, x, date)'
3613 3672 (func
3614 3673 ('symbol', 'rs4')
3615 3674 (list
3616 3675 (or
3617 3676 (list
3618 3677 ('symbol', '2')
3619 3678 ('symbol', '3')))
3620 3679 ('symbol', 'x')
3621 3680 ('symbol', 'x')
3622 3681 ('symbol', 'date')))
3623 3682 * expanded:
3624 3683 (func
3625 3684 ('symbol', 'reverse')
3626 3685 (func
3627 3686 ('symbol', 'sort')
3628 3687 (list
3629 3688 (or
3630 3689 (list
3631 3690 ('symbol', '2')
3632 3691 ('symbol', '3')))
3633 3692 ('symbol', 'date'))))
3634 3693 * set:
3635 3694 <baseset [3, 2]>
3636 3695 3
3637 3696 2
3638 3697
3639 3698 issue4553: check that revset aliases override existing hash prefix
3640 3699
3641 3700 $ hg log -qr e
3642 3701 6:e0cc66ef77e8
3643 3702
3644 3703 $ hg log -qr e --config revsetalias.e="all()"
3645 3704 0:2785f51eece5
3646 3705 1:d75937da8da0
3647 3706 2:5ed5505e9f1c
3648 3707 3:8528aa5637f2
3649 3708 4:2326846efdab
3650 3709 5:904fa392b941
3651 3710 6:e0cc66ef77e8
3652 3711 7:013af1973af4
3653 3712 8:d5d0dcbdc4d9
3654 3713 9:24286f4ae135
3655 3714
3656 3715 $ hg log -qr e: --config revsetalias.e="0"
3657 3716 0:2785f51eece5
3658 3717 1:d75937da8da0
3659 3718 2:5ed5505e9f1c
3660 3719 3:8528aa5637f2
3661 3720 4:2326846efdab
3662 3721 5:904fa392b941
3663 3722 6:e0cc66ef77e8
3664 3723 7:013af1973af4
3665 3724 8:d5d0dcbdc4d9
3666 3725 9:24286f4ae135
3667 3726
3668 3727 $ hg log -qr :e --config revsetalias.e="9"
3669 3728 0:2785f51eece5
3670 3729 1:d75937da8da0
3671 3730 2:5ed5505e9f1c
3672 3731 3:8528aa5637f2
3673 3732 4:2326846efdab
3674 3733 5:904fa392b941
3675 3734 6:e0cc66ef77e8
3676 3735 7:013af1973af4
3677 3736 8:d5d0dcbdc4d9
3678 3737 9:24286f4ae135
3679 3738
3680 3739 $ hg log -qr e:
3681 3740 6:e0cc66ef77e8
3682 3741 7:013af1973af4
3683 3742 8:d5d0dcbdc4d9
3684 3743 9:24286f4ae135
3685 3744
3686 3745 $ hg log -qr :e
3687 3746 0:2785f51eece5
3688 3747 1:d75937da8da0
3689 3748 2:5ed5505e9f1c
3690 3749 3:8528aa5637f2
3691 3750 4:2326846efdab
3692 3751 5:904fa392b941
3693 3752 6:e0cc66ef77e8
3694 3753
3695 3754 issue2549 - correct optimizations
3696 3755
3697 3756 $ try 'limit(1 or 2 or 3, 2) and not 2'
3698 3757 (and
3699 3758 (func
3700 3759 ('symbol', 'limit')
3701 3760 (list
3702 3761 (or
3703 3762 (list
3704 3763 ('symbol', '1')
3705 3764 ('symbol', '2')
3706 3765 ('symbol', '3')))
3707 3766 ('symbol', '2')))
3708 3767 (not
3709 3768 ('symbol', '2')))
3710 3769 * set:
3711 3770 <filteredset
3712 3771 <baseset [1, 2]>,
3713 3772 <not
3714 3773 <baseset [2]>>>
3715 3774 1
3716 3775 $ try 'max(1 or 2) and not 2'
3717 3776 (and
3718 3777 (func
3719 3778 ('symbol', 'max')
3720 3779 (or
3721 3780 (list
3722 3781 ('symbol', '1')
3723 3782 ('symbol', '2'))))
3724 3783 (not
3725 3784 ('symbol', '2')))
3726 3785 * set:
3727 3786 <filteredset
3728 3787 <baseset
3729 3788 <max
3730 3789 <fullreposet+ 0:10>,
3731 3790 <baseset [1, 2]>>>,
3732 3791 <not
3733 3792 <baseset [2]>>>
3734 3793 $ try 'min(1 or 2) and not 1'
3735 3794 (and
3736 3795 (func
3737 3796 ('symbol', 'min')
3738 3797 (or
3739 3798 (list
3740 3799 ('symbol', '1')
3741 3800 ('symbol', '2'))))
3742 3801 (not
3743 3802 ('symbol', '1')))
3744 3803 * set:
3745 3804 <filteredset
3746 3805 <baseset
3747 3806 <min
3748 3807 <fullreposet+ 0:10>,
3749 3808 <baseset [1, 2]>>>,
3750 3809 <not
3751 3810 <baseset [1]>>>
3752 3811 $ try 'last(1 or 2, 1) and not 2'
3753 3812 (and
3754 3813 (func
3755 3814 ('symbol', 'last')
3756 3815 (list
3757 3816 (or
3758 3817 (list
3759 3818 ('symbol', '1')
3760 3819 ('symbol', '2')))
3761 3820 ('symbol', '1')))
3762 3821 (not
3763 3822 ('symbol', '2')))
3764 3823 * set:
3765 3824 <filteredset
3766 3825 <baseset [2]>,
3767 3826 <not
3768 3827 <baseset [2]>>>
3769 3828
3770 3829 issue4289 - ordering of built-ins
3771 3830 $ hg log -M -q -r 3:2
3772 3831 3:8528aa5637f2
3773 3832 2:5ed5505e9f1c
3774 3833
3775 3834 test revsets started with 40-chars hash (issue3669)
3776 3835
3777 3836 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3778 3837 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3779 3838 9
3780 3839 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3781 3840 8
3782 3841
3783 3842 test or-ed indirect predicates (issue3775)
3784 3843
3785 3844 $ log '6 or 6^1' | sort
3786 3845 5
3787 3846 6
3788 3847 $ log '6^1 or 6' | sort
3789 3848 5
3790 3849 6
3791 3850 $ log '4 or 4~1' | sort
3792 3851 2
3793 3852 4
3794 3853 $ log '4~1 or 4' | sort
3795 3854 2
3796 3855 4
3797 3856 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3798 3857 0
3799 3858 1
3800 3859 2
3801 3860 3
3802 3861 4
3803 3862 5
3804 3863 6
3805 3864 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3806 3865 0
3807 3866 1
3808 3867 2
3809 3868 3
3810 3869 4
3811 3870 5
3812 3871 6
3813 3872
3814 3873 tests for 'remote()' predicate:
3815 3874 #. (csets in remote) (id) (remote)
3816 3875 1. less than local current branch "default"
3817 3876 2. same with local specified "default"
3818 3877 3. more than local specified specified
3819 3878
3820 3879 $ hg clone --quiet -U . ../remote3
3821 3880 $ cd ../remote3
3822 3881 $ hg update -q 7
3823 3882 $ echo r > r
3824 3883 $ hg ci -Aqm 10
3825 3884 $ log 'remote()'
3826 3885 7
3827 3886 $ log 'remote("a-b-c-")'
3828 3887 2
3829 3888 $ cd ../repo
3830 3889 $ log 'remote(".a.b.c.", "../remote3")'
3831 3890
3832 3891 tests for concatenation of strings/symbols by "##"
3833 3892
3834 3893 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3835 3894 (_concat
3836 3895 (_concat
3837 3896 (_concat
3838 3897 ('symbol', '278')
3839 3898 ('string', '5f5'))
3840 3899 ('symbol', '1ee'))
3841 3900 ('string', 'ce5'))
3842 3901 * concatenated:
3843 3902 ('string', '2785f51eece5')
3844 3903 * set:
3845 3904 <baseset [0]>
3846 3905 0
3847 3906
3848 3907 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3849 3908 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3850 3909 (func
3851 3910 ('symbol', 'cat4')
3852 3911 (list
3853 3912 ('symbol', '278')
3854 3913 ('string', '5f5')
3855 3914 ('symbol', '1ee')
3856 3915 ('string', 'ce5')))
3857 3916 * expanded:
3858 3917 (_concat
3859 3918 (_concat
3860 3919 (_concat
3861 3920 ('symbol', '278')
3862 3921 ('string', '5f5'))
3863 3922 ('symbol', '1ee'))
3864 3923 ('string', 'ce5'))
3865 3924 * concatenated:
3866 3925 ('string', '2785f51eece5')
3867 3926 * set:
3868 3927 <baseset [0]>
3869 3928 0
3870 3929
3871 3930 (check concatenation in alias nesting)
3872 3931
3873 3932 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3874 3933 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3875 3934 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3876 3935 0
3877 3936
3878 3937 (check operator priority)
3879 3938
3880 3939 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3881 3940 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3882 3941 0
3883 3942 4
3884 3943
3885 3944 $ cd ..
3886 3945
3887 3946 prepare repository that has "default" branches of multiple roots
3888 3947
3889 3948 $ hg init namedbranch
3890 3949 $ cd namedbranch
3891 3950
3892 3951 $ echo default0 >> a
3893 3952 $ hg ci -Aqm0
3894 3953 $ echo default1 >> a
3895 3954 $ hg ci -m1
3896 3955
3897 3956 $ hg branch -q stable
3898 3957 $ echo stable2 >> a
3899 3958 $ hg ci -m2
3900 3959 $ echo stable3 >> a
3901 3960 $ hg ci -m3
3902 3961
3903 3962 $ hg update -q null
3904 3963 $ echo default4 >> a
3905 3964 $ hg ci -Aqm4
3906 3965 $ echo default5 >> a
3907 3966 $ hg ci -m5
3908 3967
3909 3968 "null" revision belongs to "default" branch (issue4683)
3910 3969
3911 3970 $ log 'branch(null)'
3912 3971 0
3913 3972 1
3914 3973 4
3915 3974 5
3916 3975
3917 3976 "null" revision belongs to "default" branch, but it shouldn't appear in set
3918 3977 unless explicitly specified (issue4682)
3919 3978
3920 3979 $ log 'children(branch(default))'
3921 3980 1
3922 3981 2
3923 3982 5
3924 3983
3925 3984 $ cd ..
3926 3985
3927 3986 test author/desc/keyword in problematic encoding
3928 3987 # unicode: cp932:
3929 3988 # u30A2 0x83 0x41(= 'A')
3930 3989 # u30C2 0x83 0x61(= 'a')
3931 3990
3932 3991 $ hg init problematicencoding
3933 3992 $ cd problematicencoding
3934 3993
3935 3994 $ python > setup.sh <<EOF
3936 3995 > print u'''
3937 3996 > echo a > text
3938 3997 > hg add text
3939 3998 > hg --encoding utf-8 commit -u '\u30A2' -m none
3940 3999 > echo b > text
3941 4000 > hg --encoding utf-8 commit -u '\u30C2' -m none
3942 4001 > echo c > text
3943 4002 > hg --encoding utf-8 commit -u none -m '\u30A2'
3944 4003 > echo d > text
3945 4004 > hg --encoding utf-8 commit -u none -m '\u30C2'
3946 4005 > '''.encode('utf-8')
3947 4006 > EOF
3948 4007 $ sh < setup.sh
3949 4008
3950 4009 test in problematic encoding
3951 4010 $ python > test.sh <<EOF
3952 4011 > print u'''
3953 4012 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3954 4013 > echo ====
3955 4014 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3956 4015 > echo ====
3957 4016 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3958 4017 > echo ====
3959 4018 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3960 4019 > echo ====
3961 4020 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3962 4021 > echo ====
3963 4022 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3964 4023 > '''.encode('cp932')
3965 4024 > EOF
3966 4025 $ sh < test.sh
3967 4026 0
3968 4027 ====
3969 4028 1
3970 4029 ====
3971 4030 2
3972 4031 ====
3973 4032 3
3974 4033 ====
3975 4034 0
3976 4035 2
3977 4036 ====
3978 4037 1
3979 4038 3
3980 4039
3981 4040 test error message of bad revset
3982 4041 $ hg log -r 'foo\\'
3983 4042 hg: parse error at 3: syntax error in revset 'foo\\'
3984 4043 [255]
3985 4044
3986 4045 $ cd ..
3987 4046
3988 4047 Test that revset predicate of extension isn't loaded at failure of
3989 4048 loading it
3990 4049
3991 4050 $ cd repo
3992 4051
3993 4052 $ cat <<EOF > $TESTTMP/custompredicate.py
3994 4053 > from mercurial import error, registrar, revset
3995 4054 >
3996 4055 > revsetpredicate = registrar.revsetpredicate()
3997 4056 >
3998 4057 > @revsetpredicate('custom1()')
3999 4058 > def custom1(repo, subset, x):
4000 4059 > return revset.baseset([1])
4001 4060 >
4002 4061 > raise error.Abort('intentional failure of loading extension')
4003 4062 > EOF
4004 4063 $ cat <<EOF > .hg/hgrc
4005 4064 > [extensions]
4006 4065 > custompredicate = $TESTTMP/custompredicate.py
4007 4066 > EOF
4008 4067
4009 4068 $ hg debugrevspec "custom1()"
4010 4069 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
4011 4070 hg: parse error: unknown identifier: custom1
4012 4071 [255]
4013 4072
4014 4073 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now