##// END OF EJS Templates
bundlerepo: properly handle hidden linkrev in manifestlog (issue4945)...
bundlerepo: properly handle hidden linkrev in manifestlog (issue4945) The bundlerepository have to do some special magic to handle linkrev of the bundled manifest. That logic was done from a repoview and obsolescence marker affecting bundled changeset could lead to a crash. We now ensure we operate on unfiltered repository.

File last commit:

r28189:fac3a24b default
r28221:7a8c4484 stable
Show More
destutil.py
220 lines | 7.9 KiB | text/x-python | PythonLexer
Pierre-Yves David
update: move default destination computation to a function...
r26569 # destutil.py - Mercurial utility function for command destination
#
# Copyright Matt Mackall <mpm@selenic.com> and other
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
destutil: use absolute_import
r27333 from __future__ import absolute_import
Pierre-Yves David
update: move default destination computation to a function...
r26569 from .i18n import _
from . import (
Pierre-Yves David
destupdate: also include bookmark related logic...
r26641 bookmarks,
Pierre-Yves David
update: move default destination computation to a function...
r26569 error,
obsolete,
)
Pierre-Yves David
destupdate: extract validation logic...
r26720 def _destupdatevalidate(repo, rev, clean, check):
"""validate that the destination comply to various rules
This exists as its own function to help wrapping from extensions."""
wc = repo[None]
p1 = wc.p1()
if not clean:
# Check that the update is linear.
#
# Mercurial do not allow update-merge for non linear pattern
# (that would be technically possible but was considered too confusing
# for user a long time ago)
#
# See mercurial.merge.update for details
if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
dirty = wc.dirty(missing=True)
foreground = obsolete.foreground(repo, [p1.node()])
if not repo[rev].node() in foreground:
if dirty:
msg = _("uncommitted changes")
hint = _("commit and merge, or update --clean to"
" discard changes")
raise error.UpdateAbort(msg, hint=hint)
elif not check: # destination is not a descendant.
msg = _("not a linear update")
hint = _("merge or update --check to force update")
raise error.UpdateAbort(msg, hint=hint)
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 def _destupdateobs(repo, clean, check):
"""decide of an update destination from obsolescence markers"""
Pierre-Yves David
update: move default destination computation to a function...
r26569 node = None
wc = repo[None]
p1 = wc.p1()
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 movemark = None
Pierre-Yves David
update: move default destination computation to a function...
r26569
if p1.obsolete() and not p1.children():
# allow updating to successors
successors = obsolete.successorssets(repo, p1.node())
# behavior of certain cases is as follows,
#
# divergent changesets: update to highest rev, similar to what
# is currently done when there are more than one head
# (i.e. 'tip')
#
# replaced changesets: same as divergent except we know there
# is no conflict
#
# pruned changeset: no update is done; though, we could
# consider updating to the first non-obsolete parent,
# similar to what is current done for 'hg prune'
if successors:
# flatten the list here handles both divergent (len > 1)
# and the usual case (len = 1)
successors = [n for sub in successors for n in sub]
# get the max revision for the given successors set,
# i.e. the 'tip' of a set
node = repo.revs('max(%ln)', successors).first()
Pierre-Yves David
destupdate: move obsolete handling first...
r26722 if bookmarks.isactivewdirparent(repo):
movemark = repo['.'].node()
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 return node, movemark, None
Pierre-Yves David
destupdate: extract logic based on bookmarks in its own function...
r26724 def _destupdatebook(repo, clean, check):
"""decide on an update destination from active bookmark"""
# we also move the active bookmark, if any
activemark = None
node, movemark = bookmarks.calculateupdate(repo.ui, repo, None)
if node is not None:
activemark = node
return node, movemark, activemark
Pierre-Yves David
destupdate: extract logic based on branch in its own function...
r26725 def _destupdatebranch(repo, clean, check):
"""decide on an update destination from current branch"""
wc = repo[None]
movemark = node = None
try:
node = repo.branchtip(wc.branch())
if bookmarks.isactivewdirparent(repo):
movemark = repo['.'].node()
except error.RepoLookupError:
if wc.branch() == 'default': # no default branch!
node = repo.lookup('tip') # update to tip
else:
raise error.Abort(_("branch %s not found") % wc.branch())
return node, movemark, None
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 # order in which each step should be evalutated
# steps are run until one finds a destination
destupdatesteps = ['evolution', 'bookmark', 'branch']
# mapping to ease extension overriding steps.
destupdatestepmap = {'evolution': _destupdateobs,
'bookmark': _destupdatebook,
'branch': _destupdatebranch,
}
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723 def destupdate(repo, clean=False, check=False):
"""destination for bare update operation
return (rev, movemark, activemark)
- rev: the revision to update to,
- movemark: node to move the active bookmark from
(cf bookmark.calculate update),
- activemark: a bookmark to activate at the end of the update.
"""
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 node = movemark = activemark = None
Pierre-Yves David
destupdate: extract logic based on obsolescence marker in its own function...
r26723
Pierre-Yves David
destupdate: have a generic and extensible way to run each step...
r26726 for step in destupdatesteps:
node, movemark, activemark = destupdatestepmap[step](repo, clean, check)
if node is not None:
break
Pierre-Yves David
destupdate: move the check related to the "clean" logic in the function...
r26628 rev = repo[node].rev()
Pierre-Yves David
destupdate: extract validation logic...
r26720 _destupdatevalidate(repo, rev, clean, check)
Pierre-Yves David
destupdate: move the check related to the "clean" logic in the function...
r26628
Pierre-Yves David
destupdate: also include bookmark related logic...
r26641 return rev, movemark, activemark
Pierre-Yves David
destutil: move default merge destination into a function...
r26714
Pierre-Yves David
destmerge: extract logic based on bookmark into its own function...
r26727 def _destmergebook(repo):
"""find merge destination in the active bookmark case"""
node = None
bmheads = repo.bookmarkheads(repo._activebookmark)
curhead = repo[repo._activebookmark].node()
if len(bmheads) == 2:
if curhead == bmheads[0]:
node = bmheads[1]
else:
node = bmheads[0]
elif len(bmheads) > 2:
raise error.Abort(_("multiple matching bookmarks to merge - "
"please merge with an explicit rev or bookmark"),
hint=_("run 'hg heads' to see all heads"))
elif len(bmheads) <= 1:
raise error.Abort(_("no matching bookmark to merge - "
"please merge with an explicit rev or bookmark"),
hint=_("run 'hg heads' to see all heads"))
assert node is not None
return node
Pierre-Yves David
destmerge: extract logic based on branch heads in its own function...
r26728 def _destmergebranch(repo):
"""find merge destination based on branch heads"""
node = None
branch = repo[None].branch()
bheads = repo.branchheads(branch)
nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
if len(nbhs) > 2:
raise error.Abort(_("branch '%s' has %d heads - "
"please merge with an explicit rev")
% (branch, len(bheads)),
hint=_("run 'hg heads .' to see heads"))
parent = repo.dirstate.p1()
if len(nbhs) <= 1:
if len(bheads) > 1:
raise error.Abort(_("heads are bookmarked - "
"please merge with an explicit rev"),
hint=_("run 'hg heads' to see all heads"))
if len(repo.heads()) > 1:
raise error.Abort(_("branch '%s' has one head - "
"please merge with an explicit rev")
% branch,
hint=_("run 'hg heads' to see all heads"))
msg, hint = _('nothing to merge'), None
if parent != repo.lookup(branch):
hint = _("use 'hg update' instead")
raise error.Abort(msg, hint=hint)
if parent not in bheads:
raise error.Abort(_('working directory not at a head revision'),
hint=_("use 'hg update' or merge with an "
"explicit revision"))
if parent == nbhs[0]:
node = nbhs[-1]
else:
node = nbhs[0]
assert node is not None
return node
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 def destmerge(repo):
if repo._activebookmark:
Pierre-Yves David
destmerge: extract logic based on bookmark into its own function...
r26727 node = _destmergebook(repo)
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 else:
Pierre-Yves David
destmerge: extract logic based on branch heads in its own function...
r26728 node = _destmergebranch(repo)
Pierre-Yves David
destutil: move default merge destination into a function...
r26714 return repo[node].rev()
Gregory Szorc
histedit: pick an appropriate base changeset by default (BC)...
r27262
histeditdefaultrevset = 'reverse(only(.) and not public() and not ::merge())'
def desthistedit(ui, repo):
"""Default base revision to edit for `hg histedit`."""
Gregory Szorc
destutil: use scmutil.revrange for desthistedit (issue5001)...
r27559 # Avoid cycle: scmutil -> revset -> destutil
from . import scmutil
Gregory Szorc
histedit: pick an appropriate base changeset by default (BC)...
r27262 default = ui.config('histedit', 'defaultrev', histeditdefaultrevset)
if default:
Gregory Szorc
destutil: use scmutil.revrange for desthistedit (issue5001)...
r27559 revs = scmutil.revrange(repo, [default])
Gregory Szorc
histedit: pick an appropriate base changeset by default (BC)...
r27262 if revs:
# The revset supplied by the user may not be in ascending order nor
# take the first revision. So do this manually.
revs.sort()
return revs.first()
return None