##// END OF EJS Templates
merge with stable
Matt Mackall -
r16778:2ac08d8b merge default
parent child Browse files
Show More
@@ -1308,6 +1308,27 b' def optimize(x, small):'
1308 return w + wa, (op, x[1], ta)
1308 return w + wa, (op, x[1], ta)
1309 return 1, x
1309 return 1, x
1310
1310
1311 _aliasarg = ('func', ('symbol', '_aliasarg'))
1312 def _getaliasarg(tree):
1313 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
1314 return X, None otherwise.
1315 """
1316 if (len(tree) == 3 and tree[:2] == _aliasarg
1317 and tree[2][0] == 'string'):
1318 return tree[2][1]
1319 return None
1320
1321 def _checkaliasarg(tree, known=None):
1322 """Check tree contains no _aliasarg construct or only ones which
1323 value is in known. Used to avoid alias placeholders injection.
1324 """
1325 if isinstance(tree, tuple):
1326 arg = _getaliasarg(tree)
1327 if arg is not None and (not known or arg not in known):
1328 raise error.ParseError(_("not a function: %s") % '_aliasarg')
1329 for t in tree:
1330 _checkaliasarg(t, known)
1331
1311 class revsetalias(object):
1332 class revsetalias(object):
1312 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
1333 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
1313 args = None
1334 args = None
@@ -1324,7 +1345,9 b' class revsetalias(object):'
1324 self.tree = ('func', ('symbol', m.group(1)))
1345 self.tree = ('func', ('symbol', m.group(1)))
1325 self.args = [x.strip() for x in m.group(2).split(',')]
1346 self.args = [x.strip() for x in m.group(2).split(',')]
1326 for arg in self.args:
1347 for arg in self.args:
1327 value = value.replace(arg, repr(arg))
1348 # _aliasarg() is an unknown symbol only used separate
1349 # alias argument placeholders from regular strings.
1350 value = value.replace(arg, '_aliasarg(%r)' % (arg,))
1328 else:
1351 else:
1329 self.name = name
1352 self.name = name
1330 self.tree = ('symbol', name)
1353 self.tree = ('symbol', name)
@@ -1332,6 +1355,8 b' class revsetalias(object):'
1332 self.replacement, pos = parse(value)
1355 self.replacement, pos = parse(value)
1333 if pos != len(value):
1356 if pos != len(value):
1334 raise error.ParseError(_('invalid token'), pos)
1357 raise error.ParseError(_('invalid token'), pos)
1358 # Check for placeholder injection
1359 _checkaliasarg(self.replacement, self.args)
1335
1360
1336 def _getalias(aliases, tree):
1361 def _getalias(aliases, tree):
1337 """If tree looks like an unexpanded alias, return it. Return None
1362 """If tree looks like an unexpanded alias, return it. Return None
@@ -1352,13 +1377,14 b' def _getalias(aliases, tree):'
1352 return None
1377 return None
1353
1378
1354 def _expandargs(tree, args):
1379 def _expandargs(tree, args):
1355 """Replace all occurences of ('string', name) with the
1380 """Replace _aliasarg instances with the substitution value of the
1356 substitution value of the same name in args, recursively.
1381 same name in args, recursively.
1357 """
1382 """
1358 if not isinstance(tree, tuple):
1383 if not tree or not isinstance(tree, tuple):
1359 return tree
1384 return tree
1360 if len(tree) == 2 and tree[0] == 'string':
1385 arg = _getaliasarg(tree)
1361 return args.get(tree[1], tree)
1386 if arg is not None:
1387 return args[arg]
1362 return tuple(_expandargs(t, args) for t in tree)
1388 return tuple(_expandargs(t, args) for t in tree)
1363
1389
1364 def _expandaliases(aliases, tree, expanding):
1390 def _expandaliases(aliases, tree, expanding):
@@ -1376,22 +1402,22 b' def _expandaliases(aliases, tree, expand'
1376 raise error.ParseError(_('infinite expansion of revset alias "%s" '
1402 raise error.ParseError(_('infinite expansion of revset alias "%s" '
1377 'detected') % alias.name)
1403 'detected') % alias.name)
1378 expanding.append(alias)
1404 expanding.append(alias)
1379 result = alias.replacement
1405 result = _expandaliases(aliases, alias.replacement, expanding)
1406 expanding.pop()
1380 if alias.args is not None:
1407 if alias.args is not None:
1381 l = getlist(tree[2])
1408 l = getlist(tree[2])
1382 if len(l) != len(alias.args):
1409 if len(l) != len(alias.args):
1383 raise error.ParseError(
1410 raise error.ParseError(
1384 _('invalid number of arguments: %s') % len(l))
1411 _('invalid number of arguments: %s') % len(l))
1412 l = [_expandaliases(aliases, a, []) for a in l]
1385 result = _expandargs(result, dict(zip(alias.args, l)))
1413 result = _expandargs(result, dict(zip(alias.args, l)))
1386 # Recurse in place, the base expression may have been rewritten
1387 result = _expandaliases(aliases, result, expanding)
1388 expanding.pop()
1389 else:
1414 else:
1390 result = tuple(_expandaliases(aliases, t, expanding)
1415 result = tuple(_expandaliases(aliases, t, expanding)
1391 for t in tree)
1416 for t in tree)
1392 return result
1417 return result
1393
1418
1394 def findaliases(ui, tree):
1419 def findaliases(ui, tree):
1420 _checkaliasarg(tree)
1395 aliases = {}
1421 aliases = {}
1396 for k, v in ui.configitems('revsetalias'):
1422 for k, v in ui.configitems('revsetalias'):
1397 alias = revsetalias(k, v)
1423 alias = revsetalias(k, v)
@@ -527,6 +527,27 b' test infinite recursion'
527 hg: parse error: infinite expansion of revset alias "recurse1" detected
527 hg: parse error: infinite expansion of revset alias "recurse1" detected
528 [255]
528 [255]
529
529
530 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
531 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
532 $ try "level2(level1(1, 2), 3)"
533 (func
534 ('symbol', 'level2')
535 (list
536 (func
537 ('symbol', 'level1')
538 (list
539 ('symbol', '1')
540 ('symbol', '2')))
541 ('symbol', '3')))
542 (or
543 ('symbol', '3')
544 (or
545 ('symbol', '1')
546 ('symbol', '2')))
547 3
548 1
549 2
550
530 test nesting and variable passing
551 test nesting and variable passing
531
552
532 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
553 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
@@ -565,6 +586,19 b' far away.'
565 abort: unknown revision '$1'!
586 abort: unknown revision '$1'!
566 [255]
587 [255]
567
588
589 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
590 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
591 $ try 'callinjection2(2:5)'
592 (func
593 ('symbol', 'callinjection2')
594 (range
595 ('symbol', '2')
596 ('symbol', '5')))
597 hg: parse error: not a function: _aliasarg
598 [255]
599 >>> data = file('.hg/hgrc', 'rb').read()
600 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
601
568 $ try 'd(2:5)'
602 $ try 'd(2:5)'
569 (func
603 (func
570 ('symbol', 'd')
604 ('symbol', 'd')
General Comments 0
You need to be logged in to leave comments. Login now