hgext3rd/topic/discovery.py
changeset 1901 85390446f8c1
parent 1899 b65f39791f92
child 1903 58cdf061d49a
equal deleted inserted replaced
1899:b65f39791f92 1901:85390446f8c1
       
     1 import weakref
       
     2 from mercurial import branchmap
       
     3 from mercurial import error
       
     4 from mercurial import exchange
       
     5 from mercurial.i18n import _
       
     6 from . import topicmap
       
     7 
       
     8 def _headssummary(orig, repo, remote, outgoing):
       
     9     publishing = ('phases' not in remote.listkeys('namespaces')
       
    10                   or bool(remote.listkeys('phases').get('publishing', False)))
       
    11     if publishing:
       
    12         return orig(repo, remote, outgoing)
       
    13     oldgetitem = repo.__getitem__
       
    14     oldrepo = repo.__class__
       
    15     oldbranchcache = branchmap.branchcache
       
    16     oldfilename = branchmap._filename
       
    17     try:
       
    18         class repocls(repo.__class__):
       
    19             def __getitem__(self, key):
       
    20                 ctx = super(repocls, self).__getitem__(key)
       
    21                 oldbranch = ctx.branch
       
    22                 def branch():
       
    23                     branch = oldbranch()
       
    24                     topic = ctx.topic()
       
    25                     if topic:
       
    26                         branch = "%s:%s" % (branch, topic)
       
    27                     return branch
       
    28                 ctx.branch = branch
       
    29                 return ctx
       
    30         repo.__class__ = repocls
       
    31         branchmap.branchcache = topicmap.topiccache
       
    32         branchmap._filename = topicmap._filename
       
    33         summary = orig(repo, remote, outgoing)
       
    34         for key, value in summary.iteritems():
       
    35             if ':' in key: # This is a topic
       
    36                 if value[0] is None and value[1]:
       
    37                     summary[key] = ([value[1].pop(0)], ) + value[1:]
       
    38         return summary
       
    39     finally:
       
    40         repo.__class__ = oldrepo
       
    41         branchmap.branchcache = oldbranchcache
       
    42         branchmap._filename = oldfilename
       
    43 
       
    44 def wireprotobranchmap(orig, repo, proto):
       
    45     oldrepo = repo.__class__
       
    46     try:
       
    47         class repocls(repo.__class__):
       
    48             def branchmap(self):
       
    49                 usetopic = not self.publishing()
       
    50                 return super(repocls, self).branchmap(topic=usetopic)
       
    51         repo.__class__ = repocls
       
    52         return orig(repo, proto)
       
    53     finally:
       
    54         repo.__class__ = oldrepo
       
    55 
       
    56 
       
    57 # Discovery have deficiency around phases, branch can get new heads with pure
       
    58 # phases change. This happened with a changeset was allowed to be pushed
       
    59 # because it had a topic, but it later become public and create a new branch
       
    60 # head.
       
    61 #
       
    62 # Handle this by doing an extra check for new head creation server side
       
    63 def _nbheads(repo):
       
    64     data = {}
       
    65     for b in repo.branchmap().iterbranches():
       
    66         if ':' in b[0]:
       
    67             continue
       
    68         data[b[0]] = len(b[1])
       
    69     return data
       
    70 
       
    71 def handlecheckheads(orig, op, inpart):
       
    72     orig(op, inpart)
       
    73     if op.repo.publishing():
       
    74         return
       
    75     tr = op.gettransaction()
       
    76     if tr.hookargs['source'] not in ('push', 'serve'): # not a push
       
    77         return
       
    78     tr._prepushheads = _nbheads(op.repo)
       
    79     reporef = weakref.ref(op.repo)
       
    80     oldvalidator = tr.validator
       
    81     def validator(tr):
       
    82         repo = reporef()
       
    83         if repo is not None:
       
    84             repo.invalidatecaches()
       
    85             finalheads = _nbheads(repo)
       
    86             for branch, oldnb in tr._prepushheads.iteritems():
       
    87                 newnb = finalheads.pop(branch, 0)
       
    88                 if oldnb < newnb:
       
    89                     msg = _('push create a new head on branch "%s"' % branch)
       
    90                     raise error.Abort(msg)
       
    91             for branch, newnb in finalheads.iteritems():
       
    92                 if 1 < newnb:
       
    93                     msg = _('push create more than 1 head on new branch "%s"' % branch)
       
    94                     raise error.Abort(msg)
       
    95         return oldvalidator(tr)
       
    96     tr.validator = validator
       
    97 handlecheckheads.params = frozenset()
       
    98 
       
    99 def _pushb2phases(orig, pushop, bundler):
       
   100     hascheck =  any(p.type == 'check:heads' for p in  bundler._parts)
       
   101     if pushop.outdatedphases and not hascheck:
       
   102         exchange._pushb2ctxcheckheads(pushop, bundler)
       
   103     return orig(pushop, bundler)
       
   104 
       
   105 
       
   106