|
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 |