Mercurial > hg-stable
comparison hgext/histedit.py @ 27082:4898e442f392
histedit: make verification configurable
Before we can add a 'base' action to histedit need to change verification
so that action can specify which steps of verification should run for it.
Also it's everything we need for the exec and stop actions implementation.
I thought about baking verification into each histedit action (so each
of them is responsible for verifying its constraints) but it felt wrong
because:
- every action would need to know its context (eg. the list of all other
actions)
- a lot of duplicated work will be added - each action will iterate through
all others
- the steps of the verification would need to be extracted and named anyway
in order to be reused
The verifyrules function grows too big now. I plan to refator it in one of
the next series.
author | Mateusz Kwapich <mitrandir@fb.com> |
---|---|
date | Tue, 17 Nov 2015 16:37:26 -0800 |
parents | 1168499e5266 |
children | 6d5d7ac41ef4 |
comparison
equal
deleted
inserted
replaced
27081:37290f2f2c3b | 27082:4898e442f392 |
---|---|
331 try: | 331 try: |
332 node = repo[rulehash].node() | 332 node = repo[rulehash].node() |
333 except error.RepoError: | 333 except error.RepoError: |
334 raise error.Abort(_('unknown changeset %s listed') % rulehash[:12]) | 334 raise error.Abort(_('unknown changeset %s listed') % rulehash[:12]) |
335 return cls(state, node) | 335 return cls(state, node) |
336 | |
337 def constraints(self): | |
338 """Return a set of constrains that this action should be verified for | |
339 | |
340 Available constraints: | |
341 noduplicates - aborts if there are multiple rules for one node | |
342 noother - abort if the node doesn't belong to edited stack | |
343 """ | |
344 | |
345 return set(['noduplicates', 'noother']) | |
346 | |
347 def nodetoverify(self): | |
348 """Returns a node associated with the action that will be used for | |
349 verification purposes. | |
350 | |
351 If the action doesn't correspond to node it should return None | |
352 """ | |
353 return self.node | |
336 | 354 |
337 def run(self): | 355 def run(self): |
338 """Runs the action. The default behavior is simply apply the action's | 356 """Runs the action. The default behavior is simply apply the action's |
339 rulectx onto the current parentctx.""" | 357 rulectx onto the current parentctx.""" |
340 self.applychange() | 358 self.applychange() |
808 f = open(rules) | 826 f = open(rules) |
809 rules = f.read() | 827 rules = f.read() |
810 f.close() | 828 f.close() |
811 rules = [l for l in (r.strip() for r in rules.splitlines()) | 829 rules = [l for l in (r.strip() for r in rules.splitlines()) |
812 if l and not l.startswith('#')] | 830 if l and not l.startswith('#')] |
813 rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules]) | 831 rules = verifyrules(rules, state, [repo[c] for [_a, c] in state.rules]) |
814 state.rules = rules | 832 state.rules = rules |
815 state.write() | 833 state.write() |
816 return | 834 return |
817 elif goal == 'abort': | 835 elif goal == 'abort': |
818 try: | 836 try: |
889 f = open(rules) | 907 f = open(rules) |
890 rules = f.read() | 908 rules = f.read() |
891 f.close() | 909 f.close() |
892 rules = [l for l in (r.strip() for r in rules.splitlines()) | 910 rules = [l for l in (r.strip() for r in rules.splitlines()) |
893 if l and not l.startswith('#')] | 911 if l and not l.startswith('#')] |
894 rules = verifyrules(rules, repo, ctxs) | 912 rules = verifyrules(rules, state, ctxs) |
895 | 913 |
896 parentctxnode = repo[root].parents()[0].node() | 914 parentctxnode = repo[root].parents()[0].node() |
897 | 915 |
898 state.parentctxnode = parentctxnode | 916 state.parentctxnode = parentctxnode |
899 state.rules = rules | 917 state.rules = rules |
1037 f.write(rules) | 1055 f.write(rules) |
1038 f.close() | 1056 f.close() |
1039 | 1057 |
1040 return rules | 1058 return rules |
1041 | 1059 |
1042 def verifyrules(rules, repo, ctxs): | 1060 def verifyrules(rules, state, ctxs): |
1043 """Verify that there exists exactly one edit rule per given changeset. | 1061 """Verify that there exists exactly one edit rule per given changeset. |
1044 | 1062 |
1045 Will abort if there are to many or too few rules, a malformed rule, | 1063 Will abort if there are to many or too few rules, a malformed rule, |
1046 or a rule on a changeset outside of the user-given range. | 1064 or a rule on a changeset outside of the user-given range. |
1047 """ | 1065 """ |
1066 known_constraints = ['noother', 'noduplicates'] | |
1048 parsed = [] | 1067 parsed = [] |
1049 expected = set(c.hex() for c in ctxs) | 1068 expected = set(c.hex() for c in ctxs) |
1050 seen = set() | 1069 seen = set() |
1051 for r in rules: | 1070 for r in rules: |
1052 if ' ' not in r: | 1071 if ' ' not in r: |
1053 raise error.Abort(_('malformed line "%s"') % r) | 1072 raise error.Abort(_('malformed line "%s"') % r) |
1054 action, rest = r.split(' ', 1) | 1073 verb, rest = r.split(' ', 1) |
1055 ha = rest.strip().split(' ', 1)[0] | 1074 |
1056 try: | 1075 if verb not in actiontable or verb.startswith('_'): |
1057 ha = repo[ha].hex() | 1076 raise error.Abort(_('unknown action "%s"') % verb) |
1058 except error.RepoError: | 1077 action = actiontable[verb].fromrule(state, rest) |
1059 raise error.Abort(_('unknown changeset %s listed') % ha[:12]) | 1078 constraints = action.constraints() |
1060 if ha not in expected: | 1079 for constraint in constraints: |
1061 raise error.Abort( | 1080 if constraint not in known_constraints: |
1062 _('may not use changesets other than the ones listed')) | 1081 error.Abort(_('unknown constraint "%s"') % constraint) |
1063 if ha in seen: | 1082 |
1064 raise error.Abort(_('duplicated command for changeset %s') % | 1083 nodetoverify = action.nodetoverify() |
1065 ha[:12]) | 1084 if nodetoverify is not None: |
1066 seen.add(ha) | 1085 ha = node.hex(nodetoverify) |
1067 if action not in actiontable or action.startswith('_'): | 1086 if 'noother' in constraints and ha not in expected: |
1068 raise error.Abort(_('unknown action "%s"') % action) | 1087 raise error.Abort( |
1069 parsed.append([action, ha]) | 1088 _('may not use "%s" with changesets ' |
1089 'other than the ones listed') % verb) | |
1090 if 'noduplicates' in constraints and ha in seen: | |
1091 raise error.Abort(_('duplicated command for changeset %s') % | |
1092 ha[:12]) | |
1093 seen.add(ha) | |
1094 rest = ha | |
1095 parsed.append([verb, rest]) | |
1070 missing = sorted(expected - seen) # sort to stabilize output | 1096 missing = sorted(expected - seen) # sort to stabilize output |
1071 if missing: | 1097 if missing: |
1072 raise error.Abort(_('missing rules for changeset %s') % | 1098 raise error.Abort(_('missing rules for changeset %s') % |
1073 missing[0][:12], | 1099 missing[0][:12], |
1074 hint=_('do you want to use the drop action?')) | 1100 hint=_('do you want to use the drop action?')) |