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