sapling/edenscm/hgext/drop.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

121 lines
3.4 KiB
Python

# drop - allows the user to drop changeset from the middle of a stack
#
# Copyright 2017 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.
"""drop specified changeset from the stack
This command drops specified changeset from the stack.
For example, given changeset stack
o C
|
o B
|
o A
|
o master
execution of `hg drop -r B` command will result in the following stack
o C
|
o A
|
o master
If the changeset to drop has multiple children branching off of it,
all of them (including their descendants) will be rebased
onto the parent changeset. Dropping changeset which are a result of a merge
(have two parent changesets) is not supported.
Root changesets cannot be dropped.
"""
from edenscm.mercurial import cmdutil, error, extensions, phases, registrar, scmutil
from edenscm.mercurial.i18n import _
cmdtable = {}
command = registrar.command(cmdtable)
testedwith = "ships-with-fb-hgext"
def _checkextension(name, ui):
try:
return extensions.find(name)
except KeyError:
ui.warn(_("extension %s not found\n") % name)
return None
def _showrev(ui, repo, revid):
"""pretty print the changeset to drop"""
showopts = {
"template": "Dropping changeset "
'{shortest(node, 6)}{if(bookmarks, " ({bookmarks})")}'
": {desc|firstline}\n"
}
displayer = cmdutil.show_changeset(ui, repo, showopts)
displayer.show(repo[revid])
def extsetup(ui):
global rebasemod
rebasemod = _checkextension("rebase", ui)
@command("drop", [("r", "rev", [], _("revision to drop"))], _("hg drop [OPTION] [REV]"))
def drop(ui, repo, *revs, **opts):
"""drop changeset from stack
"""
if not rebasemod:
raise error.Abort(_("required extensions not detected"))
cmdutil.checkunfinished(repo)
cmdutil.bailifchanged(repo)
revs = scmutil.revrange(repo, list(revs) + opts.get("rev"))
if not revs:
raise error.Abort(_("no revision to drop was provided"))
# currently drop supports dropping only one changeset at a time
if len(revs) > 1:
raise error.Abort(_("only one revision can be dropped at a time"))
revid = revs.first()
changectx = repo[revid]
if changectx.phase() == phases.public:
raise error.Abort(_("public changeset which landed cannot be dropped"))
parents = repo.revs("parents(%s)", revid)
if len(parents) > 1:
raise error.Abort(_("merge changeset cannot be dropped"))
elif len(parents) == 0:
raise error.Abort(_("root changeset cannot be dropped"))
_showrev(ui, repo, revid)
descendants = repo.revs("(%d::) - %d", revid, revid)
parent = parents.first()
with repo.wlock():
with repo.lock():
with repo.transaction("drop"):
if len(descendants) > 0:
try:
rebasemod.rebase(ui, repo, dest=str(parent), rev=descendants)
except error.InterventionRequired:
ui.warn(
_(
"conflict occurred during drop: "
+ "please fix it by running "
+ "'hg rebase --continue', "
+ "and then re-run 'hg drop'\n"
)
)
raise
scmutil.cleanupnodes(repo, [changectx.node()], "drop")