hgext/histedit.py
changeset 27082 4898e442f392
parent 27051 1168499e5266
child 27083 6d5d7ac41ef4
--- a/hgext/histedit.py	Fri Nov 13 18:31:58 2015 +0800
+++ b/hgext/histedit.py	Tue Nov 17 16:37:26 2015 -0800
@@ -334,6 +334,24 @@
             raise error.Abort(_('unknown changeset %s listed') % rulehash[:12])
         return cls(state, node)
 
+    def constraints(self):
+        """Return a set of constrains that this action should be verified for
+
+           Available constraints:
+               noduplicates - aborts if there are multiple rules for one node
+               noother - abort if the node doesn't belong to edited stack
+        """
+
+        return set(['noduplicates', 'noother'])
+
+    def nodetoverify(self):
+        """Returns a node associated with the action that will be used for
+        verification purposes.
+
+        If the action doesn't correspond to node it should return None
+        """
+        return self.node
+
     def run(self):
         """Runs the action. The default behavior is simply apply the action's
         rulectx onto the current parentctx."""
@@ -810,7 +828,7 @@
             f.close()
         rules = [l for l in (r.strip() for r in rules.splitlines())
                  if l and not l.startswith('#')]
-        rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules])
+        rules = verifyrules(rules, state, [repo[c] for [_a, c] in state.rules])
         state.rules = rules
         state.write()
         return
@@ -891,7 +909,7 @@
             f.close()
         rules = [l for l in (r.strip() for r in rules.splitlines())
                  if l and not l.startswith('#')]
-        rules = verifyrules(rules, repo, ctxs)
+        rules = verifyrules(rules, state, ctxs)
 
         parentctxnode = repo[root].parents()[0].node()
 
@@ -1039,34 +1057,42 @@
 
     return rules
 
-def verifyrules(rules, repo, ctxs):
+def verifyrules(rules, state, ctxs):
     """Verify that there exists exactly one edit rule per given changeset.
 
     Will abort if there are to many or too few rules, a malformed rule,
     or a rule on a changeset outside of the user-given range.
     """
+    known_constraints = ['noother', 'noduplicates']
     parsed = []
     expected = set(c.hex() for c in ctxs)
     seen = set()
     for r in rules:
         if ' ' not in r:
             raise error.Abort(_('malformed line "%s"') % r)
-        action, rest = r.split(' ', 1)
-        ha = rest.strip().split(' ', 1)[0]
-        try:
-            ha = repo[ha].hex()
-        except error.RepoError:
-            raise error.Abort(_('unknown changeset %s listed') % ha[:12])
-        if ha not in expected:
-            raise error.Abort(
-                _('may not use changesets other than the ones listed'))
-        if ha in seen:
-            raise error.Abort(_('duplicated command for changeset %s') %
-                    ha[:12])
-        seen.add(ha)
-        if action not in actiontable or action.startswith('_'):
-            raise error.Abort(_('unknown action "%s"') % action)
-        parsed.append([action, ha])
+        verb, rest = r.split(' ', 1)
+
+        if verb not in actiontable or verb.startswith('_'):
+            raise error.Abort(_('unknown action "%s"') % verb)
+        action = actiontable[verb].fromrule(state, rest)
+        constraints = action.constraints()
+        for constraint in constraints:
+            if constraint not in known_constraints:
+                error.Abort(_('unknown constraint "%s"') % constraint)
+
+        nodetoverify = action.nodetoverify()
+        if nodetoverify is not None:
+            ha = node.hex(nodetoverify)
+            if 'noother' in constraints and ha not in expected:
+                raise error.Abort(
+                    _('may not use "%s" with changesets '
+                      'other than the ones listed') % verb)
+            if 'noduplicates' in constraints and ha in seen:
+                raise error.Abort(_('duplicated command for changeset %s') %
+                        ha[:12])
+            seen.add(ha)
+            rest = ha
+        parsed.append([verb, rest])
     missing = sorted(expected - seen)  # sort to stabilize output
     if missing:
         raise error.Abort(_('missing rules for changeset %s') %