Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revset.py @ 16778:2ac08d8b21aa
merge with stable
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Tue, 22 May 2012 14:37:20 -0500 |
parents | d0b9ebba41e9 30e46d7138de |
children | 107a3270a24a |
comparison
equal
deleted
inserted
replaced
16777:058e14da7044 | 16778:2ac08d8b21aa |
---|---|
1306 else: | 1306 else: |
1307 w = 1 | 1307 w = 1 |
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 |
1314 | 1335 |
1315 def __init__(self, name, value): | 1336 def __init__(self, name, value): |
1322 if m: | 1343 if m: |
1323 self.name = m.group(1) | 1344 self.name = m.group(1) |
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) |
1331 | 1354 |
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 |
1338 otherwise. | 1363 otherwise. |
1339 """ | 1364 """ |
1350 if alias and alias.args is not None and alias.tree == tree[:2]: | 1375 if alias and alias.args is not None and alias.tree == tree[:2]: |
1351 return alias | 1376 return alias |
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): |
1365 """Expand aliases in tree, recursively. | 1391 """Expand aliases in tree, recursively. |
1366 | 1392 |
1374 if alias is not None: | 1400 if alias is not None: |
1375 if alias in expanding: | 1401 if alias in expanding: |
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) |
1398 aliases[alias.name] = alias | 1424 aliases[alias.name] = alias |
1399 return _expandaliases(aliases, tree, []) | 1425 return _expandaliases(aliases, tree, []) |