Show More
@@ -1071,46 +1071,85 b' class revsetalias(object):' | |||||
1071 | h = heads(default) |
|
1071 | h = heads(default) | |
1072 | b($1) = ancestors($1) - ancestors(default) |
|
1072 | b($1) = ancestors($1) - ancestors(default) | |
1073 | ''' |
|
1073 | ''' | |
1074 | if isinstance(name, tuple): # parameter substitution |
|
1074 | m = self.funcre.search(name) | |
1075 | self.tree = name |
|
1075 | if m: | |
1076 |
self. |
|
1076 | self.name = m.group(1) | |
1077 | else: # alias definition |
|
1077 | self.tree = ('func', ('symbol', m.group(1))) | |
1078 | m = self.funcre.search(name) |
|
1078 | self.args = [x.strip() for x in m.group(2).split(',')] | |
1079 |
|
|
1079 | for arg in self.args: | |
1080 | self.tree = ('func', ('symbol', m.group(1))) |
|
1080 | value = value.replace(arg, repr(arg)) | |
1081 | self.args = [x.strip() for x in m.group(2).split(',')] |
|
1081 | else: | |
1082 | for arg in self.args: |
|
1082 | self.name = name | |
1083 | value = value.replace(arg, repr(arg)) |
|
1083 | self.tree = ('symbol', name) | |
1084 | else: |
|
1084 | ||
1085 | self.tree = ('symbol', name) |
|
1085 | self.replacement, pos = parse(value) | |
|
1086 | if pos != len(value): | |||
|
1087 | raise error.ParseError(_('invalid token'), pos) | |||
1086 |
|
1088 | |||
1087 | self.replacement, pos = parse(value) |
|
1089 | def _getalias(aliases, tree): | |
1088 | if pos != len(value): |
|
1090 | """If tree looks like an unexpanded alias, return it. Return None | |
1089 | raise error.ParseError(_('invalid token'), pos) |
|
1091 | otherwise. | |
|
1092 | """ | |||
|
1093 | if isinstance(tree, tuple) and tree: | |||
|
1094 | if tree[0] == 'symbol' and len(tree) == 2: | |||
|
1095 | name = tree[1] | |||
|
1096 | alias = aliases.get(name) | |||
|
1097 | if alias and alias.args is None and alias.tree == tree: | |||
|
1098 | return alias | |||
|
1099 | if tree[0] == 'func' and len(tree) > 1: | |||
|
1100 | if tree[1][0] == 'symbol' and len(tree[1]) == 2: | |||
|
1101 | name = tree[1][1] | |||
|
1102 | alias = aliases.get(name) | |||
|
1103 | if alias and alias.args is not None and alias.tree == tree[:2]: | |||
|
1104 | return alias | |||
|
1105 | return None | |||
1090 |
|
1106 | |||
1091 | def process(self, tree): |
|
1107 | def _expandargs(tree, args): | |
1092 | if isinstance(tree, tuple): |
|
1108 | """Replace all occurences of ('string', name) with the | |
1093 | if self.args is None: |
|
1109 | substitution value of the same name in args, recursively. | |
1094 | if tree == self.tree: |
|
1110 | """ | |
1095 | return self.replacement |
|
1111 | if not isinstance(tree, tuple): | |
1096 | elif tree[:2] == self.tree: |
|
1112 | return tree | |
1097 | l = getlist(tree[2]) |
|
1113 | if len(tree) == 2 and tree[0] == 'string': | |
1098 | if len(l) != len(self.args): |
|
1114 | return args.get(tree[1], tree) | |
1099 | raise error.ParseError( |
|
1115 | return tuple(_expandargs(t, args) for t in tree) | |
1100 | _('invalid number of arguments: %s') % len(l)) |
|
1116 | ||
1101 | result = self.replacement |
|
1117 | def _expandaliases(aliases, tree, expanding): | |
1102 | for a, v in zip(self.args, l): |
|
1118 | """Expand aliases in tree, recursively. | |
1103 | valalias = revsetalias(('string', a), v) |
|
1119 | ||
1104 | result = valalias.process(result) |
|
1120 | 'aliases' is a dictionary mapping user defined aliases to | |
1105 | return result |
|
1121 | revsetalias objects. | |
1106 | return tuple(map(self.process, tree)) |
|
1122 | """ | |
|
1123 | if not isinstance(tree, tuple): | |||
|
1124 | # Do not expand raw strings | |||
1107 | return tree |
|
1125 | return tree | |
|
1126 | alias = _getalias(aliases, tree) | |||
|
1127 | if alias is not None: | |||
|
1128 | if alias in expanding: | |||
|
1129 | raise error.ParseError(_('infinite expansion of revset alias "%s" ' | |||
|
1130 | 'detected') % alias.name) | |||
|
1131 | expanding.append(alias) | |||
|
1132 | result = alias.replacement | |||
|
1133 | if alias.args is not None: | |||
|
1134 | l = getlist(tree[2]) | |||
|
1135 | if len(l) != len(alias.args): | |||
|
1136 | raise error.ParseError( | |||
|
1137 | _('invalid number of arguments: %s') % len(l)) | |||
|
1138 | result = _expandargs(result, dict(zip(alias.args, l))) | |||
|
1139 | # Recurse in place, the base expression may have been rewritten | |||
|
1140 | result = _expandaliases(aliases, result, expanding) | |||
|
1141 | expanding.pop() | |||
|
1142 | else: | |||
|
1143 | result = tuple(_expandaliases(aliases, t, expanding) | |||
|
1144 | for t in tree) | |||
|
1145 | return result | |||
1108 |
|
1146 | |||
1109 | def findaliases(ui, tree): |
|
1147 | def findaliases(ui, tree): | |
|
1148 | aliases = {} | |||
1110 | for k, v in ui.configitems('revsetalias'): |
|
1149 | for k, v in ui.configitems('revsetalias'): | |
1111 | alias = revsetalias(k, v) |
|
1150 | alias = revsetalias(k, v) | |
1112 | tree = alias.process(tree) |
|
1151 | aliases[alias.name] = alias | |
1113 | return tree |
|
1152 | return _expandaliases(aliases, tree, []) | |
1114 |
|
1153 | |||
1115 | parse = parser.parser(tokenize, elements).parse |
|
1154 | parse = parser.parser(tokenize, elements).parse | |
1116 |
|
1155 |
@@ -430,6 +430,7 b' aliases:' | |||||
430 |
|
430 | |||
431 | $ echo '[revsetalias]' >> .hg/hgrc |
|
431 | $ echo '[revsetalias]' >> .hg/hgrc | |
432 | $ echo 'm = merge()' >> .hg/hgrc |
|
432 | $ echo 'm = merge()' >> .hg/hgrc | |
|
433 | $ echo 'sincem = descendants(m)' >> .hg/hgrc | |||
433 | $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc |
|
434 | $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc | |
434 | $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc |
|
435 | $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc | |
435 | $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc |
|
436 | $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc | |
@@ -438,6 +439,46 b' aliases:' | |||||
438 | ('symbol', 'm') |
|
439 | ('symbol', 'm') | |
439 | ('func', ('symbol', 'merge'), None) |
|
440 | ('func', ('symbol', 'merge'), None) | |
440 | 6 |
|
441 | 6 | |
|
442 | ||||
|
443 | test alias recursion | |||
|
444 | ||||
|
445 | $ try sincem | |||
|
446 | ('symbol', 'sincem') | |||
|
447 | ('func', ('symbol', 'descendants'), ('func', ('symbol', 'merge'), None)) | |||
|
448 | 6 | |||
|
449 | 7 | |||
|
450 | ||||
|
451 | test infinite recursion | |||
|
452 | ||||
|
453 | $ echo 'recurse1 = recurse2' >> .hg/hgrc | |||
|
454 | $ echo 'recurse2 = recurse1' >> .hg/hgrc | |||
|
455 | $ try recurse1 | |||
|
456 | ('symbol', 'recurse1') | |||
|
457 | hg: parse error: infinite expansion of revset alias "recurse1" detected | |||
|
458 | [255] | |||
|
459 | ||||
|
460 | test nesting and variable passing | |||
|
461 | ||||
|
462 | $ echo 'nested($1) = nested2($1)' >> .hg/hgrc | |||
|
463 | $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc | |||
|
464 | $ echo 'nested3($1) = max($1)' >> .hg/hgrc | |||
|
465 | $ try 'nested(2:5)' | |||
|
466 | ('func', ('symbol', 'nested'), ('range', ('symbol', '2'), ('symbol', '5'))) | |||
|
467 | ('func', ('symbol', 'max'), ('range', ('symbol', '2'), ('symbol', '5'))) | |||
|
468 | 5 | |||
|
469 | ||||
|
470 | test variable isolation, variable placeholders are rewritten as string | |||
|
471 | then parsed and matched again as string. Check they do not leak too | |||
|
472 | far away. | |||
|
473 | ||||
|
474 | $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc | |||
|
475 | $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc | |||
|
476 | $ try 'callinjection(2:5)' | |||
|
477 | ('func', ('symbol', 'callinjection'), ('range', ('symbol', '2'), ('symbol', '5'))) | |||
|
478 | ('func', ('symbol', 'descendants'), ('func', ('symbol', 'max'), ('string', '$1'))) | |||
|
479 | abort: unknown revision '$1'! | |||
|
480 | [255] | |||
|
481 | ||||
441 | $ try 'd(2:5)' |
|
482 | $ try 'd(2:5)' | |
442 | ('func', ('symbol', 'd'), ('range', ('symbol', '2'), ('symbol', '5'))) |
|
483 | ('func', ('symbol', 'd'), ('range', ('symbol', '2'), ('symbol', '5'))) | |
443 | ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('range', ('symbol', '2'), ('symbol', '5')), ('symbol', 'date')))) |
|
484 | ('func', ('symbol', 'reverse'), ('func', ('symbol', 'sort'), ('list', ('range', ('symbol', '2'), ('symbol', '5')), ('symbol', 'date')))) |
General Comments 0
You need to be logged in to leave comments.
Login now