src/topic/discovery.py
changeset 1887 68125d026b07
parent 1886 0504e76bfbd9
child 1899 b65f39791f92
equal deleted inserted replaced
1886:0504e76bfbd9 1887:68125d026b07
       
     1 import weakref
     1 from mercurial import branchmap
     2 from mercurial import branchmap
       
     3 from mercurial import error
       
     4 from mercurial import exchange
       
     5 from mercurial.i18n import _
     2 from . import topicmap
     6 from . import topicmap
     3 
     7 
     4 def _headssummary(orig, repo, remote, outgoing):
     8 def _headssummary(orig, repo, remote, outgoing):
     5     publishing = ('phases' not in remote.listkeys('namespaces')
     9     publishing = ('phases' not in remote.listkeys('namespaces')
     6                   or bool(remote.listkeys('phases').get('publishing', False)))
    10                   or bool(remote.listkeys('phases').get('publishing', False)))
    47                 return super(repocls, self).branchmap(topic=usetopic)
    51                 return super(repocls, self).branchmap(topic=usetopic)
    48         repo.__class__ = repocls
    52         repo.__class__ = repocls
    49         return orig(repo, proto)
    53         return orig(repo, proto)
    50     finally:
    54     finally:
    51         repo.__class__ = oldrepo
    55         repo.__class__ = oldrepo
       
    56 
       
    57 
       
    58 # Discovery have deficiency around phases, branch can get new heads with pure
       
    59 # phases change. This happened with a changeset was allowed to be pushed
       
    60 # because it had a topic, but it later become public and create a new branch
       
    61 # head.
       
    62 #
       
    63 # Handle this by doing an extra check for new head creation server side
       
    64 def _nbheads(repo):
       
    65     data = {}
       
    66     for b in repo.branchmap().iterbranches():
       
    67         if ':' in b[0]:
       
    68             continue
       
    69         data[b[0]] = len(b[1])
       
    70     return data
       
    71 
       
    72 def handlecheckheads(orig, op, inpart):
       
    73     orig(op, inpart)
       
    74     if op.repo.publishing():
       
    75         return
       
    76     tr = op.gettransaction()
       
    77     if tr.hookargs['source'] not in ('push', 'serve'): # not a push
       
    78         return
       
    79     tr._prepushheads = _nbheads(op.repo)
       
    80     reporef = weakref.ref(op.repo)
       
    81     oldvalidator = tr.validator
       
    82     def validator(tr):
       
    83         repo = reporef()
       
    84         if repo is not None:
       
    85             repo.invalidatecaches()
       
    86             finalheads = _nbheads(repo)
       
    87             for branch, oldnb in tr._prepushheads.iteritems():
       
    88                 newnb = finalheads.pop(branch, 0)
       
    89                 if oldnb < newnb:
       
    90                     msg = _('push create a new head on branch "%s"' % branch)
       
    91                     raise error.Abort(msg)
       
    92             for branch, newnb in finalheads.iteritems():
       
    93                 if 1 < newnb:
       
    94                     msg = _('push create more than 1 head on new branch "%s"' % branch)
       
    95                     raise error.Abort(msg)
       
    96         return oldvalidator(tr)
       
    97     tr.validator = validator
       
    98 handlecheckheads.params = frozenset()
       
    99 
       
   100 def _pushb2phases(orig, pushop, bundler):
       
   101     hascheck =  any(p.type == 'check:heads' for p in  bundler._parts)
       
   102     if pushop.outdatedphases and not hascheck:
       
   103         exchange._pushb2ctxcheckheads(pushop, bundler)
       
   104     return orig(pushop, bundler)
       
   105 
       
   106 
       
   107