mercurial/revset.py
branchstable
changeset 16771 2f3317d53d51
parent 16748 0a730d3c5aae
child 16772 30e46d7138de
equal deleted inserted replaced
16768:23a125545c3d 16771:2f3317d53d51
  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, [])