sapling/edenscm/hgext/amend/restack.py
Jun Wu 9dc21f8d0b codemod: import from the edenscm package
Summary:
D13853115 adds `edenscm/` to `sys.path` and code still uses `import mercurial`.
That has nasty problems if both `import mercurial` and
`import edenscm.mercurial` are used, because Python would think `mercurial.foo`
and `edenscm.mercurial.foo` are different modules so code like
`try: ... except mercurial.error.Foo: ...`, or `isinstance(x, mercurial.foo.Bar)`
would fail to handle the `edenscm.mercurial` version. There are also some
module-level states (ex. `extensions._extensions`) that would cause trouble if
they have multiple versions in a single process.

Change imports to use the `edenscm` so ideally the `mercurial` is no longer
imported at all. Add checks in extensions.py to catch unexpected extensions
importing modules from the old (wrong) locations when running tests.

Reviewed By: phillco

Differential Revision: D13868981

fbshipit-source-id: f4e2513766957fd81d85407994f7521a08e4de48
2019-01-29 17:25:32 -08:00

57 lines
2.3 KiB
Python

# restack.py - rebase to make a stack connected again
#
# Copyright 2013 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from edenscm.hgext import rebase
from edenscm.mercurial import commands, revsetlang
from edenscm.mercurial.i18n import _
def restack(ui, repo, rebaseopts=None):
"""Repair a situation in which one or more commits in a stack
have been obsoleted (thereby leaving their descendants in the stack
orphaned) by finding any such commits and rebasing their descendants
onto the latest version of each respective commit.
"""
rebaseopts = (rebaseopts or {}).copy()
# TODO: Remove config override after https://phab.mercurial-scm.org/D1063
config = {("experimental", "rebase.multidest"): True}
with ui.configoverride(config), repo.wlock(), repo.lock():
# Find drafts connected to the current stack via either changelog or
# obsolete graph. Note: "draft() & ::." is optimized by D441.
# 1. Connect drafts via changelog
revs = list(repo.revs("(draft() & ::.)::"))
if not revs:
# "." is probably public. Check its direct children.
revs = repo.revs("draft() & children(.)")
if not revs:
ui.status(_("nothing to restack\n"))
return 1
# 2. Connect revs via obsolete graph
revs = list(repo.revs("successors(%ld)+predecessors(%ld)", revs, revs))
# 3. Connect revs via changelog again to cover missing revs
revs = list(repo.revs("(draft() & ::%ld)::", revs))
rebaseopts["rev"] = [revsetlang.formatspec("%ld", revs)]
rebaseopts["dest"] = "_destrestack(SRC)"
rebase.rebase(ui, repo, **rebaseopts)
# Ensure that we always end up on the latest version of the
# current changeset. Usually, this will be taken care of
# by the rebase operation. However, in some cases (such as
# if we are on the precursor of the base changeset) the
# rebase will not update to the latest version, so we need
# to do this manually.
successor = repo.revs("successors(.) - .").last()
if successor is not None:
commands.update(ui, repo, rev=successor)