2035 |
2035 |
2036 class revsetalias(object): |
2036 class revsetalias(object): |
2037 funcre = re.compile('^([^(]+)\(([^)]+)\)$') |
2037 funcre = re.compile('^([^(]+)\(([^)]+)\)$') |
2038 args = None |
2038 args = None |
2039 |
2039 |
|
2040 # error message at parsing, or None |
|
2041 error = None |
|
2042 # whether own `error` information is already shown or not. |
|
2043 # this avoids showing same warning multiple times at each `findaliases`. |
|
2044 warned = False |
|
2045 |
2040 def __init__(self, name, value): |
2046 def __init__(self, name, value): |
2041 '''Aliases like: |
2047 '''Aliases like: |
2042 |
2048 |
2043 h = heads(default) |
2049 h = heads(default) |
2044 b($1) = ancestors($1) - ancestors(default) |
2050 b($1) = ancestors($1) - ancestors(default) |
2054 value = value.replace(arg, '_aliasarg(%r)' % (arg,)) |
2060 value = value.replace(arg, '_aliasarg(%r)' % (arg,)) |
2055 else: |
2061 else: |
2056 self.name = name |
2062 self.name = name |
2057 self.tree = ('symbol', name) |
2063 self.tree = ('symbol', name) |
2058 |
2064 |
2059 self.replacement, pos = parse(value) |
2065 try: |
2060 if pos != len(value): |
2066 self.replacement, pos = parse(value) |
2061 raise error.ParseError(_('invalid token'), pos) |
2067 if pos != len(value): |
2062 # Check for placeholder injection |
2068 raise error.ParseError(_('invalid token'), pos) |
2063 _checkaliasarg(self.replacement, self.args) |
2069 # Check for placeholder injection |
|
2070 _checkaliasarg(self.replacement, self.args) |
|
2071 except error.ParseError, inst: |
|
2072 if len(inst.args) > 1: |
|
2073 self.error = _('at %s: %s') % (inst.args[1], inst.args[0]) |
|
2074 else: |
|
2075 self.error = inst.args[0] |
2064 |
2076 |
2065 def _getalias(aliases, tree): |
2077 def _getalias(aliases, tree): |
2066 """If tree looks like an unexpanded alias, return it. Return None |
2078 """If tree looks like an unexpanded alias, return it. Return None |
2067 otherwise. |
2079 otherwise. |
2068 """ |
2080 """ |
2100 if not isinstance(tree, tuple): |
2112 if not isinstance(tree, tuple): |
2101 # Do not expand raw strings |
2113 # Do not expand raw strings |
2102 return tree |
2114 return tree |
2103 alias = _getalias(aliases, tree) |
2115 alias = _getalias(aliases, tree) |
2104 if alias is not None: |
2116 if alias is not None: |
|
2117 if alias.error: |
|
2118 raise util.Abort(_('failed to parse revset alias "%s": %s') % |
|
2119 (alias.name, alias.error)) |
2105 if alias in expanding: |
2120 if alias in expanding: |
2106 raise error.ParseError(_('infinite expansion of revset alias "%s" ' |
2121 raise error.ParseError(_('infinite expansion of revset alias "%s" ' |
2107 'detected') % alias.name) |
2122 'detected') % alias.name) |
2108 expanding.append(alias) |
2123 expanding.append(alias) |
2109 if alias.name not in cache: |
2124 if alias.name not in cache: |
2121 else: |
2136 else: |
2122 result = tuple(_expandaliases(aliases, t, expanding, cache) |
2137 result = tuple(_expandaliases(aliases, t, expanding, cache) |
2123 for t in tree) |
2138 for t in tree) |
2124 return result |
2139 return result |
2125 |
2140 |
2126 def findaliases(ui, tree): |
2141 def findaliases(ui, tree, showwarning=None): |
2127 _checkaliasarg(tree) |
2142 _checkaliasarg(tree) |
2128 aliases = {} |
2143 aliases = {} |
2129 for k, v in ui.configitems('revsetalias'): |
2144 for k, v in ui.configitems('revsetalias'): |
2130 alias = revsetalias(k, v) |
2145 alias = revsetalias(k, v) |
2131 aliases[alias.name] = alias |
2146 aliases[alias.name] = alias |
2132 return _expandaliases(aliases, tree, [], {}) |
2147 tree = _expandaliases(aliases, tree, [], {}) |
|
2148 if showwarning: |
|
2149 # warn about problematic (but not referred) aliases |
|
2150 for name, alias in sorted(aliases.iteritems()): |
|
2151 if alias.error and not alias.warned: |
|
2152 msg = _('failed to parse revset alias "%s": %s' |
|
2153 ) % (name, alias.error) |
|
2154 showwarning(_('warning: %s\n') % (msg)) |
|
2155 alias.warned = True |
|
2156 return tree |
2133 |
2157 |
2134 def parse(spec, lookup=None): |
2158 def parse(spec, lookup=None): |
2135 p = parser.parser(tokenize, elements) |
2159 p = parser.parser(tokenize, elements) |
2136 return p.parse(spec, lookup=lookup) |
2160 return p.parse(spec, lookup=lookup) |
2137 |
2161 |
2143 lookup = repo.__contains__ |
2167 lookup = repo.__contains__ |
2144 tree, pos = parse(spec, lookup) |
2168 tree, pos = parse(spec, lookup) |
2145 if (pos != len(spec)): |
2169 if (pos != len(spec)): |
2146 raise error.ParseError(_("invalid token"), pos) |
2170 raise error.ParseError(_("invalid token"), pos) |
2147 if ui: |
2171 if ui: |
2148 tree = findaliases(ui, tree) |
2172 tree = findaliases(ui, tree, showwarning=ui.warn) |
2149 weight, tree = optimize(tree, True) |
2173 weight, tree = optimize(tree, True) |
2150 def mfunc(repo, subset): |
2174 def mfunc(repo, subset): |
2151 if util.safehasattr(subset, 'isascending'): |
2175 if util.safehasattr(subset, 'isascending'): |
2152 result = getset(repo, subset, tree) |
2176 result = getset(repo, subset, tree) |
2153 else: |
2177 else: |