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

84 lines
2.8 KiB
Python

# nointerrupt.py - prevent mercurial from being ctrl-c'ed
#
# Copyright 2016 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.
"""warns but doesn't exit when the user first hits Ctrl+C
This extension shows a warning the first time a user hits Ctrl+C saying the
repository could end up in a bad state. If the user hits Ctrl+C a second time,
hg will exit as usual.
By default, this behavior only applies to commands that are explicitly
whitelisted for it. To whitelist a command (say, "commit"), use:
[nointerrupt]
attend-commit = true
To change the default behavior to have all commands instrumented, set config
option ``nointerrupt.default-attend`` to true, then use the same logic to
disable it for commands where it's not wanted - for instance, for "log":
[nointerrupt]
default-attend = true
attend-log = false
Finally, to customize the message shown on the first Ctrl+C, set it in
config option ``nointerrupt.message``.
"""
import signal
import sys
from edenscm.mercurial import cmdutil, commands, dispatch, extensions
def sigintprintwarninghandlerfactory(oldsiginthandler, msg):
def sigint(*args):
sys.stderr.write(msg)
signal.signal(signal.SIGINT, oldsiginthandler)
return sigint
def nointerruptcmd(orig, ui, options, cmd, cmdfunc):
# bail if not in interactive terminal
if ui.configbool("nointerrupt", "interactiveonly", True):
if not ui.fout.isatty() or ui.plain():
return orig(ui, options, cmd, cmdfunc)
cmds, _cmdtableentry = cmdutil.findcmd(cmd, commands.table)
if isinstance(_cmdtableentry[0], dispatch.cmdalias):
cmds.append(_cmdtableentry[0].cmdname)
shouldpreventinterrupt = ui.configbool("nointerrupt", "default-attend", False)
for cmd in cmds:
var = "attend-%s" % cmd
if ui.config("nointerrupt", var):
shouldpreventinterrupt = ui.configbool("nointerrupt", var)
break
if shouldpreventinterrupt:
oldsiginthandler = signal.getsignal(signal.SIGINT)
try:
msg = ui.config(
"nointerrupt",
"message",
"==========================\n"
"Interrupting Mercurial may leave your repo in a bad state.\n"
"If you really want to interrupt your current command, press\n"
"CTRL-C again.\n"
"==========================\n",
)
signal.signal(
signal.SIGINT, sigintprintwarninghandlerfactory(oldsiginthandler, msg)
)
except AttributeError:
pass
return orig(ui, options, cmd, cmdfunc)
def uisetup(ui):
extensions.wrapfunction(dispatch, "_runcommand", nointerruptcmd)