Mercurial > hg-stable
changeset 17209:5cd3e526ac37
checkheads: extract branchmap preprocessing
The checkheads function is far too complicated. This extract help to explicite
what part of the preprocessing are reused by the actual check.
This the first step toward a wider refactoring.
author | Pierre-Yves David <pierre-yves.david@logilab.fr> |
---|---|
date | Tue, 17 Jul 2012 18:21:49 +0200 |
parents | 8018f2340807 |
children | ec80ae982689 |
files | mercurial/discovery.py |
diffstat | 1 files changed, 79 insertions(+), 60 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/discovery.py Mon Jul 16 17:56:50 2012 +0200 +++ b/mercurial/discovery.py Tue Jul 17 18:21:49 2012 +0200 @@ -149,77 +149,96 @@ return og +def _branchmapsummary(repo, remote, outgoing): + """compute a summary of branch and heads status before and after push + + - oldmap: {'branch': [heads]} mapping for remote + - newmap: {'branch': [heads]} mapping for local + - unsynced: set of branch that have unsynced remote changes + - branches: set of all common branch pushed + - newbranches: list of plain new pushed branch + """ + cl = repo.changelog + + # A. Create set of branches involved in the push. + branches = set(repo[n].branch() for n in outgoing.missing) + remotemap = remote.branchmap() + newbranches = branches - set(remotemap) + branches.difference_update(newbranches) + + # B. Construct the initial oldmap and newmap dicts. + # They contain information about the remote heads before and + # after the push, respectively. + # Heads not found locally are not included in either dict, + # since they won't be affected by the push. + # unsynced contains all branches with incoming changesets. + oldmap = {} + newmap = {} + unsynced = set() + for branch in branches: + remotebrheads = remotemap[branch] + + prunedbrheads = [h for h in remotebrheads if h in cl.nodemap] + oldmap[branch] = prunedbrheads + newmap[branch] = list(prunedbrheads) + if len(remotebrheads) > len(prunedbrheads): + unsynced.add(branch) + + # C. Update newmap with outgoing changes. + # This will possibly add new heads and remove existing ones. + ctxgen = (repo[n] for n in outgoing.missing) + repo._updatebranchcache(newmap, ctxgen) + return oldmap, newmap, unsynced, branches, newbranches + +def _oldbranchmapsummary(repo, remoteheads, outgoing, inc=False): + """Compute branchmapsummary for repo without branchmap support""" + + cl = repo.changelog + # 1-4b. old servers: Check for new topological heads. + # Construct {old,new}map with branch = None (topological branch). + # (code based on _updatebranchcache) + oldheads = set(h for h in remoteheads if h in cl.nodemap) + # all nodes in outgoing.missing are children of either: + # - an element of oldheads + # - another element of outgoing.missing + # - nullrev + # This explains why the new head are very simple to compute. + r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing) + branches = set([None]) + newmap = {None: list(c.node() for c in r)} + oldmap = {None: oldheads} + unsynced = inc and branches or set() + return oldmap, newmap, unsynced, branches, set() + def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False): """Check that a push won't add any outgoing head raise Abort error and display ui message as needed. """ + # Check for each named branch if we're creating new remote heads. + # To be a remote head after push, node must be either: + # - unknown locally + # - a local outgoing head descended from update + # - a remote head that's known locally and not + # ancestral to an outgoing head if remoteheads == [nullid]: # remote is empty, nothing to check. return - cl = repo.changelog if remote.capable('branchmap'): - # Check for each named branch if we're creating new remote heads. - # To be a remote head after push, node must be either: - # - unknown locally - # - a local outgoing head descended from update - # - a remote head that's known locally and not - # ancestral to an outgoing head - - # 1. Create set of branches involved in the push. - branches = set(repo[n].branch() for n in outgoing.missing) - - # 2. Check for new branches on the remote. - remotemap = remote.branchmap() - newbranches = branches - set(remotemap) - if newbranches and not newbranch: # new branch requires --new-branch - branchnames = ', '.join(sorted(newbranches)) - raise util.Abort(_("push creates new remote branches: %s!") - % branchnames, - hint=_("use 'hg push --new-branch' to create" - " new remote branches")) - branches.difference_update(newbranches) + bms = _branchmapsummary(repo, remote, outgoing) + else: + bms = _oldbranchmapsummary(repo, remoteheads, outgoing, inc) + oldmap, newmap, unsynced, branches, newbranches = bms + # 1. Check for new branches on the remote. + if newbranches and not newbranch: # new branch requires --new-branch + branchnames = ', '.join(sorted(newbranches)) + raise util.Abort(_("push creates new remote branches: %s!") + % branchnames, + hint=_("use 'hg push --new-branch' to create" + " new remote branches")) - # 3. Construct the initial oldmap and newmap dicts. - # They contain information about the remote heads before and - # after the push, respectively. - # Heads not found locally are not included in either dict, - # since they won't be affected by the push. - # unsynced contains all branches with incoming changesets. - oldmap = {} - newmap = {} - unsynced = set() - for branch in branches: - remotebrheads = remotemap[branch] - prunedbrheads = [h for h in remotebrheads if h in cl.nodemap] - oldmap[branch] = prunedbrheads - newmap[branch] = list(prunedbrheads) - if len(remotebrheads) > len(prunedbrheads): - unsynced.add(branch) - - # 4. Update newmap with outgoing changes. - # This will possibly add new heads and remove existing ones. - ctxgen = (repo[n] for n in outgoing.missing) - repo._updatebranchcache(newmap, ctxgen) - - else: - # 1-4b. old servers: Check for new topological heads. - # Construct {old,new}map with branch = None (topological branch). - # (code based on _updatebranchcache) - oldheads = set(h for h in remoteheads if h in cl.nodemap) - # all nodes in outgoing.missing are children of either: - # - an element of oldheads - # - another element of outgoing.missing - # - nullrev - # This explains why the new head are very simple to compute. - r = repo.set('heads(%ln + %ln)', oldheads, outgoing.missing) - branches = set([None]) - newmap = {None: list(c.node() for c in r)} - oldmap = {None: oldheads} - unsynced = inc and branches or set() - - # 5. Check for new heads. + # 2. Check for new heads. # If there are more heads after the push than before, a suitable # error message, depending on unsynced status, is displayed. error = None