hgext/states.py
changeset 96 d5170cc7881c
parent 90 a5f6194eb05c
child 97 e672cb1263cb
--- a/hgext/states.py	Wed Sep 21 03:52:13 2011 +0200
+++ b/hgext/states.py	Sun Sep 25 12:43:00 2011 +0200
@@ -197,8 +197,6 @@
 
 TODO:
 
-- implement --exact
-
 - implement consistency check
 
 - implement --force
@@ -533,20 +531,30 @@
 
 # automatic generation of command that set state
 def makecmd(state):
-    def cmdmoveheads(ui, repo, *changesets):
+    def cmdmoveheads(ui, repo, *changesets, **opts):
         """set revisions in %s state
 
         This command also alter state of ancestors if necessary.
         """ % state
+        if not state in repo._enabledstates:
+            raise error.Abort(
+                    _('state %s is not activated' % state),
+                    hint=_('try ``hg states %s`` before' % state))
+        if opts.get('exact'):
+            repo.setstate_unsafe(state, changesets)
+            return 0
         revs = scmutil.revrange(repo, changesets)
         repo.setstate(state, [repo.changelog.node(rev) for rev in revs])
         return 0
     return cmdmoveheads
 
 for state in STATES:
-    if state.trackheads:
-        cmdmoveheads = makecmd(state)
-        cmdtable[state.name] = (cmdmoveheads, [], '<revset>')
+    cmdmoveheads = makecmd(state)
+    cmdtable[state.name] = (cmdmoveheads, [
+        ('e', 'exact', False, _('move boundary so that revs are exactly in '
+                               'state <state> ( all([rev.state == <state> for '
+                                'rev in revs]))'))
+        ], '<revset>')
 
 # Pushkey mechanism for mutable
 #########################################
@@ -795,6 +803,32 @@
             """{ state-object -> set(defining head)} mapping"""
             return _readstatesheads(self)
 
+        def setstate_unsafe(self, state, changesets):
+            """Change state of targets changesets and it's ancestors.
+
+            Simplify the list of heads.
+
+            Unlike ``setstate``, the "lower" states are also changed
+            """
+            #modify "lower" states
+            req_nodes_rst = '|'.join('((%s)::)' % rst for rst in changesets)
+            for st in STATES:
+                if st >= state: # only modify lower state heads for now
+                    continue
+                try:
+                    heads = self._statesheads[st]
+                except KeyError: # forget non-activated states
+                    continue
+                olds = heads[:]
+                rst = "heads((::%s()) - (%s))" % (st.headssymbol, req_nodes_rst)
+                heads[:] = noderange(repo, [rst])
+                if olds != heads:
+                    _writestateshead(self)
+            #modify the state
+            if state in self._statesheads:
+                revs = scmutil.revrange(repo, changesets)
+                repo.setstate(state, [repo.changelog.node(rev) for rev in revs])
+
         def setstate(self, state, nodes):
             """change state of targets changeset and it's ancestors.