--- a/states.py Fri May 20 16:16:34 2011 +0200
+++ b/states.py Fri May 20 19:14:19 2011 +0200
@@ -17,22 +17,39 @@
name are not fixed yet.
'''
+from functools import partial
+from mercurial.i18n import _
+from mercurial import cmdutil
+from mercurial import scmutil
+from mercurial import context
+from mercurial import revset
+from mercurial import templatekw
+from mercurial import util
+from mercurial import node
+from mercurial.node import nullid
+from mercurial import discovery
+from mercurial import extensions
-STATES = (0, )
+_NOPULLPUSH=2
+
+STATES = (0, _NOPULLPUSH)
def statename(state):
return str(STATES)
-import mercurial.context
-import mercurial.templatekw
+# util function
+#############################
+def noderange(repo, revsets):
+ return map(repo.changelog.node,
+ scmutil.revrange(repo, revsets))
# Patch changectx
#############################
def state(ctx):
return ctx._repo.nodestate(ctx.node())
-mercurial.context.changectx.state = state
+context.changectx.state = state
# improve template
#############################
@@ -40,16 +57,126 @@
def showstate(ctx, **args):
return ctx.state()
+# New revset predicate
+#############################
-mercurial.templatekw.keywords['state'] = showstate
+def revsetpublicheads(repo, subset, x):
+ args = revset.getargs(x, 0, 0, 'publicheads takes no arguments')
+ heads = map(repo.changelog.rev, repo._statesheads[0])
+ heads.sort()
+ return heads
+
+def extsetup(ui):
+ revset.symbols['publicheads'] = revsetpublicheads
+
+REVSETHEADS = {0: 'publicheads()'}
+
+# New commands
+#############################
+
+def cmdsetstate(ui, repo, state, *changesets):
+ """turn private changesets into public ones"""
+ #assert repo.ui.configbool('private', 'enable', False)
+ state = int(state) #for now
+ revs = scmutil.revrange(repo, changesets)
+ repo.setstate(state, [repo.changelog.node(rev) for rev in revs])
+ return 0
+
+cmdtable = {
+ 'setstate': (cmdsetstate, [], _('state <revset>')),
+ }
+
+
+templatekw.keywords['state'] = showstate
+
+
+
+
+
+
+def uisetup(ui):
+ def filter_private(orig, repo, *args,**kwargs):
+ common, heads = orig(repo, *args, **kwargs)
+ return common, repo._reducehead(heads, repo._publicheads)
+ extensions.wrapfunction(discovery, 'findcommonoutgoing', filter_private)
def reposetup(ui, repo):
if not repo.local():
return
+
class statefulrepo(repo.__class__):
def nodestate(self, node):
+ rev = self.changelog.rev(node)
+ for head in self._publicheads:
+ revhead = self.changelog.rev(head)
+ if self.changelog.descendant(revhead, rev):
+ return STATES[1]
return STATES[0]
+ @property
+ def _publicheads(self):
+ if self.ui.configbool('states', 'private', False):
+ return self._statesheads[0]
+ return self.heads()
+
+ @util.propertycache
+ def _statesheads(self):
+ return self._readstatesheads()
+
+
+ def _readstatesheads(self):
+ statesheads = {}
+ try:
+ f = self.opener('publicheads')
+ try:
+ heads = sorted([node.bin(n) for n in f.read().split() if n])
+ finally:
+ f.close()
+ except IOError:
+ heads = [nullid]
+ statesheads[0] = heads
+ return statesheads
+
+ def _writestateshead(self):
+ # transaction!
+ f = self.opener('publicheads', 'w', atomictemp=True)
+ try:
+ for h in self._statesheads[0]:
+ f.write(node.hex(h) + '\n')
+ f.rename()
+ finally:
+ f.close()
+
+ def setstate(self, state, nodes):
+ """freeze targets changeset and it's ancestors.
+
+ Simplify the list of head."""
+ heads = self._statesheads[state]
+ olds = heads[:]
+ heads.extend(nodes)
+ heads[:] = set(heads)
+ heads.sort()
+ if olds != heads:
+ heads[:] = noderange(repo, ["heads(::%s)" % REVSETHEADS[state]])
+ heads.sort()
+ if olds != heads:
+ self._writestateshead()
+
+ def _reducehead(self, candidates, max):
+ selected = set()
+ for candidate in candidates:
+ rev = self.changelog.rev(candidate)
+ ok = True
+ for h in max:
+ revh = self.changelog.rev(h)
+ if self.changelog.descendant(revh, rev):
+ ok = False
+ selected.add(h)
+ if ok:
+ selected.add(candidate)
+ return sorted(selected)
+
repo.__class__ = statefulrepo
+