##// 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 1308 return w + wa, (op, x[1], ta)
1309 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 1332 class revsetalias(object):
1312 1333 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
1313 1334 args = None
@@ -1324,7 +1345,9 b' class revsetalias(object):'
1324 1345 self.tree = ('func', ('symbol', m.group(1)))
1325 1346 self.args = [x.strip() for x in m.group(2).split(',')]
1326 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 1351 else:
1329 1352 self.name = name
1330 1353 self.tree = ('symbol', name)
@@ -1332,6 +1355,8 b' class revsetalias(object):'
1332 1355 self.replacement, pos = parse(value)
1333 1356 if pos != len(value):
1334 1357 raise error.ParseError(_('invalid token'), pos)
1358 # Check for placeholder injection
1359 _checkaliasarg(self.replacement, self.args)
1335 1360
1336 1361 def _getalias(aliases, tree):
1337 1362 """If tree looks like an unexpanded alias, return it. Return None
@@ -1352,13 +1377,14 b' def _getalias(aliases, tree):'
1352 1377 return None
1353 1378
1354 1379 def _expandargs(tree, args):
1355 """Replace all occurences of ('string', name) with the
1356 substitution value of the same name in args, recursively.
1380 """Replace _aliasarg instances with the substitution value of the
1381 same name in args, recursively.
1357 1382 """
1358 if not isinstance(tree, tuple):
1383 if not tree or not isinstance(tree, tuple):
1359 1384 return tree
1360 if len(tree) == 2 and tree[0] == 'string':
1361 return args.get(tree[1], tree)
1385 arg = _getaliasarg(tree)
1386 if arg is not None:
1387 return args[arg]
1362 1388 return tuple(_expandargs(t, args) for t in tree)
1363 1389
1364 1390 def _expandaliases(aliases, tree, expanding):
@@ -1376,22 +1402,22 b' def _expandaliases(aliases, tree, expand'
1376 1402 raise error.ParseError(_('infinite expansion of revset alias "%s" '
1377 1403 'detected') % alias.name)
1378 1404 expanding.append(alias)
1379 result = alias.replacement
1405 result = _expandaliases(aliases, alias.replacement, expanding)
1406 expanding.pop()
1380 1407 if alias.args is not None:
1381 1408 l = getlist(tree[2])
1382 1409 if len(l) != len(alias.args):
1383 1410 raise error.ParseError(
1384 1411 _('invalid number of arguments: %s') % len(l))
1412 l = [_expandaliases(aliases, a, []) for a in l]
1385 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 1414 else:
1390 1415 result = tuple(_expandaliases(aliases, t, expanding)
1391 1416 for t in tree)
1392 1417 return result
1393 1418
1394 1419 def findaliases(ui, tree):
1420 _checkaliasarg(tree)
1395 1421 aliases = {}
1396 1422 for k, v in ui.configitems('revsetalias'):
1397 1423 alias = revsetalias(k, v)
@@ -527,6 +527,27 b' test infinite recursion'
527 527 hg: parse error: infinite expansion of revset alias "recurse1" detected
528 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 551 test nesting and variable passing
531 552
532 553 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
@@ -565,6 +586,19 b' far away.'
565 586 abort: unknown revision '$1'!
566 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 602 $ try 'd(2:5)'
569 603 (func
570 604 ('symbol', 'd')
General Comments 0
You need to be logged in to leave comments. Login now