Mercurial > evolve
diff src/topic/discovery.py @ 1887:68125d026b07
push: hackish handeling of new branch head from phase move
The current head checking mechanism is not expecting "head change" from phase
movement. Topic allows that, changeset with a topic moving to public can
create a new head. We introduce a hack to double check that no head were added
at the transaction level to work around this.
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Sat, 12 Mar 2016 18:42:16 +0000 |
parents | 0504e76bfbd9 |
children | b65f39791f92 |
line wrap: on
line diff
--- a/src/topic/discovery.py Sat Mar 12 18:19:27 2016 +0000 +++ b/src/topic/discovery.py Sat Mar 12 18:42:16 2016 +0000 @@ -1,4 +1,8 @@ +import weakref from mercurial import branchmap +from mercurial import error +from mercurial import exchange +from mercurial.i18n import _ from . import topicmap def _headssummary(orig, repo, remote, outgoing): @@ -49,3 +53,55 @@ return orig(repo, proto) finally: repo.__class__ = oldrepo + + +# Discovery have deficiency around phases, branch can get new heads with pure +# phases change. This happened with a changeset was allowed to be pushed +# because it had a topic, but it later become public and create a new branch +# head. +# +# Handle this by doing an extra check for new head creation server side +def _nbheads(repo): + data = {} + for b in repo.branchmap().iterbranches(): + if ':' in b[0]: + continue + data[b[0]] = len(b[1]) + return data + +def handlecheckheads(orig, op, inpart): + orig(op, inpart) + if op.repo.publishing(): + return + tr = op.gettransaction() + if tr.hookargs['source'] not in ('push', 'serve'): # not a push + return + tr._prepushheads = _nbheads(op.repo) + reporef = weakref.ref(op.repo) + oldvalidator = tr.validator + def validator(tr): + repo = reporef() + if repo is not None: + repo.invalidatecaches() + finalheads = _nbheads(repo) + for branch, oldnb in tr._prepushheads.iteritems(): + newnb = finalheads.pop(branch, 0) + if oldnb < newnb: + msg = _('push create a new head on branch "%s"' % branch) + raise error.Abort(msg) + for branch, newnb in finalheads.iteritems(): + if 1 < newnb: + msg = _('push create more than 1 head on new branch "%s"' % branch) + raise error.Abort(msg) + return oldvalidator(tr) + tr.validator = validator +handlecheckheads.params = frozenset() + +def _pushb2phases(orig, pushop, bundler): + hascheck = any(p.type == 'check:heads' for p in bundler._parts) + if pushop.outdatedphases and not hascheck: + exchange._pushb2ctxcheckheads(pushop, bundler) + return orig(pushop, bundler) + + +