1281 else: |
1281 else: |
1282 w = 1 |
1282 w = 1 |
1283 return w + wa, (op, x[1], ta) |
1283 return w + wa, (op, x[1], ta) |
1284 return 1, x |
1284 return 1, x |
1285 |
1285 |
|
1286 _aliasarg = ('func', ('symbol', '_aliasarg')) |
|
1287 def _getaliasarg(tree): |
|
1288 """If tree matches ('func', ('symbol', '_aliasarg'), ('string', X)) |
|
1289 return X, None otherwise. |
|
1290 """ |
|
1291 if (len(tree) == 3 and tree[:2] == _aliasarg |
|
1292 and tree[2][0] == 'string'): |
|
1293 return tree[2][1] |
|
1294 return None |
|
1295 |
|
1296 def _checkaliasarg(tree, known=None): |
|
1297 """Check tree contains no _aliasarg construct or only ones which |
|
1298 value is in known. Used to avoid alias placeholders injection. |
|
1299 """ |
|
1300 if isinstance(tree, tuple): |
|
1301 arg = _getaliasarg(tree) |
|
1302 if arg is not None and (not known or arg not in known): |
|
1303 raise error.ParseError(_("not a function: %s") % '_aliasarg') |
|
1304 for t in tree: |
|
1305 _checkaliasarg(t, known) |
|
1306 |
1286 class revsetalias(object): |
1307 class revsetalias(object): |
1287 funcre = re.compile('^([^(]+)\(([^)]+)\)$') |
1308 funcre = re.compile('^([^(]+)\(([^)]+)\)$') |
1288 args = None |
1309 args = None |
1289 |
1310 |
1290 def __init__(self, name, value): |
1311 def __init__(self, name, value): |
1297 if m: |
1318 if m: |
1298 self.name = m.group(1) |
1319 self.name = m.group(1) |
1299 self.tree = ('func', ('symbol', m.group(1))) |
1320 self.tree = ('func', ('symbol', m.group(1))) |
1300 self.args = [x.strip() for x in m.group(2).split(',')] |
1321 self.args = [x.strip() for x in m.group(2).split(',')] |
1301 for arg in self.args: |
1322 for arg in self.args: |
1302 value = value.replace(arg, repr(arg)) |
1323 # _aliasarg() is an unknown symbol only used separate |
|
1324 # alias argument placeholders from regular strings. |
|
1325 value = value.replace(arg, '_aliasarg(%r)' % (arg,)) |
1303 else: |
1326 else: |
1304 self.name = name |
1327 self.name = name |
1305 self.tree = ('symbol', name) |
1328 self.tree = ('symbol', name) |
1306 |
1329 |
1307 self.replacement, pos = parse(value) |
1330 self.replacement, pos = parse(value) |
1308 if pos != len(value): |
1331 if pos != len(value): |
1309 raise error.ParseError(_('invalid token'), pos) |
1332 raise error.ParseError(_('invalid token'), pos) |
|
1333 # Check for placeholder injection |
|
1334 _checkaliasarg(self.replacement, self.args) |
1310 |
1335 |
1311 def _getalias(aliases, tree): |
1336 def _getalias(aliases, tree): |
1312 """If tree looks like an unexpanded alias, return it. Return None |
1337 """If tree looks like an unexpanded alias, return it. Return None |
1313 otherwise. |
1338 otherwise. |
1314 """ |
1339 """ |
1325 if alias and alias.args is not None and alias.tree == tree[:2]: |
1350 if alias and alias.args is not None and alias.tree == tree[:2]: |
1326 return alias |
1351 return alias |
1327 return None |
1352 return None |
1328 |
1353 |
1329 def _expandargs(tree, args): |
1354 def _expandargs(tree, args): |
1330 """Replace all occurences of ('string', name) with the |
1355 """Replace _aliasarg instances with the substitution value of the |
1331 substitution value of the same name in args, recursively. |
1356 same name in args, recursively. |
1332 """ |
1357 """ |
1333 if not isinstance(tree, tuple): |
1358 if not tree or not isinstance(tree, tuple): |
1334 return tree |
1359 return tree |
1335 if len(tree) == 2 and tree[0] == 'string': |
1360 arg = _getaliasarg(tree) |
1336 return args.get(tree[1], tree) |
1361 if arg is not None: |
|
1362 return args[arg] |
1337 return tuple(_expandargs(t, args) for t in tree) |
1363 return tuple(_expandargs(t, args) for t in tree) |
1338 |
1364 |
1339 def _expandaliases(aliases, tree, expanding): |
1365 def _expandaliases(aliases, tree, expanding): |
1340 """Expand aliases in tree, recursively. |
1366 """Expand aliases in tree, recursively. |
1341 |
1367 |
1365 result = tuple(_expandaliases(aliases, t, expanding) |
1391 result = tuple(_expandaliases(aliases, t, expanding) |
1366 for t in tree) |
1392 for t in tree) |
1367 return result |
1393 return result |
1368 |
1394 |
1369 def findaliases(ui, tree): |
1395 def findaliases(ui, tree): |
|
1396 _checkaliasarg(tree) |
1370 aliases = {} |
1397 aliases = {} |
1371 for k, v in ui.configitems('revsetalias'): |
1398 for k, v in ui.configitems('revsetalias'): |
1372 alias = revsetalias(k, v) |
1399 alias = revsetalias(k, v) |
1373 aliases[alias.name] = alias |
1400 aliases[alias.name] = alias |
1374 return _expandaliases(aliases, tree, []) |
1401 return _expandaliases(aliases, tree, []) |