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 |
s |
|
|
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