diff -r bbeef801409c -r beabde937e36 states.py --- 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 ')), + } + + +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 +