mirror of
https://github.com/certbot/certbot.git
synced 2026-01-27 19:42:53 +03:00
Merge pull request #2767 from certbot/dialog-escape
NcursesDisplay.menu: treat ESC as cancel
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
"""Certbot display."""
|
||||
import logging
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
@@ -9,6 +10,9 @@ from certbot import interfaces
|
||||
from certbot import errors
|
||||
from certbot.display import completer
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
WIDTH = 72
|
||||
HEIGHT = 20
|
||||
|
||||
@@ -29,6 +33,9 @@ CANCEL = "cancel"
|
||||
HELP = "help"
|
||||
"""Display exit code when for when the user requests more help."""
|
||||
|
||||
ESC = "esc"
|
||||
"""Display exit code when the user hits Escape"""
|
||||
|
||||
|
||||
def _wrap_lines(msg):
|
||||
"""Format lines nicely to 80 chars.
|
||||
@@ -51,6 +58,24 @@ def _wrap_lines(msg):
|
||||
|
||||
return os.linesep.join(fixed_l)
|
||||
|
||||
|
||||
def _clean(dialog_result):
|
||||
"""Treat sundy python-dialog return codes as CANCEL
|
||||
|
||||
:param tuple dialog_result: (code, result)
|
||||
:returns: the argument but with unknown codes set to -1 (Error)
|
||||
:rtype: tuple
|
||||
"""
|
||||
code, result = dialog_result
|
||||
if code in (OK, HELP):
|
||||
return dialog_result
|
||||
elif code in (CANCEL, ESC):
|
||||
return (CANCEL, result)
|
||||
else:
|
||||
logger.debug("Surprising dialog return code %s", code)
|
||||
return (CANCEL, result)
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IDisplay)
|
||||
class NcursesDisplay(object):
|
||||
"""Ncurses-based display."""
|
||||
@@ -58,6 +83,7 @@ class NcursesDisplay(object):
|
||||
def __init__(self, width=WIDTH, height=HEIGHT):
|
||||
super(NcursesDisplay, self).__init__()
|
||||
self.dialog = dialog.Dialog()
|
||||
assert OK == self.dialog.DIALOG_OK, "What kind of absurdity is this?"
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
@@ -92,7 +118,7 @@ class NcursesDisplay(object):
|
||||
:param dict unused_kwargs: absorbs default / cli_args
|
||||
|
||||
:returns: tuple of the form (`code`, `index`) where
|
||||
`code` - int display exit code
|
||||
`code` - display exit code
|
||||
`int` - index of the selected item
|
||||
:rtype: tuple
|
||||
|
||||
@@ -111,7 +137,7 @@ class NcursesDisplay(object):
|
||||
# Can accept either tuples or just the actual choices
|
||||
if choices and isinstance(choices[0], tuple):
|
||||
# pylint: disable=star-args
|
||||
code, selection = self.dialog.menu(message, **menu_options)
|
||||
code, selection = _clean(self.dialog.menu(message, **menu_options))
|
||||
|
||||
# Return the selection index
|
||||
for i, choice in enumerate(choices):
|
||||
@@ -126,9 +152,9 @@ class NcursesDisplay(object):
|
||||
(str(i), choice) for i, choice in enumerate(choices, 1)
|
||||
]
|
||||
# pylint: disable=star-args
|
||||
code, index = self.dialog.menu(message, **menu_options)
|
||||
code, index = _clean(self.dialog.menu(message, **menu_options))
|
||||
|
||||
if code == CANCEL:
|
||||
if code == CANCEL or index == "":
|
||||
return code, -1
|
||||
|
||||
return code, int(index) - 1
|
||||
@@ -140,7 +166,7 @@ class NcursesDisplay(object):
|
||||
:param dict _kwargs: absorbs default / cli_args
|
||||
|
||||
:returns: tuple of the form (`code`, `string`) where
|
||||
`code` - int display exit code
|
||||
`code` - display exit code
|
||||
`string` - input entered by the user
|
||||
|
||||
"""
|
||||
@@ -148,7 +174,7 @@ class NcursesDisplay(object):
|
||||
# each section takes at least one line, plus extras if it's longer than self.width
|
||||
wordlines = [1 + (len(section) / self.width) for section in sections]
|
||||
height = 6 + sum(wordlines) + len(sections)
|
||||
return self.dialog.inputbox(message, width=self.width, height=height)
|
||||
return _clean(self.dialog.inputbox(message, width=self.width, height=height))
|
||||
|
||||
def yesno(self, message, yes_label="Yes", no_label="No", **unused_kwargs):
|
||||
"""Display a Yes/No dialog box.
|
||||
@@ -179,13 +205,13 @@ class NcursesDisplay(object):
|
||||
|
||||
|
||||
:returns: tuple of the form (`code`, `list_tags`) where
|
||||
`code` - int display exit code
|
||||
`code` - display exit code
|
||||
`list_tags` - list of str tags selected by the user
|
||||
|
||||
"""
|
||||
choices = [(tag, "", default_status) for tag in tags]
|
||||
return self.dialog.checklist(
|
||||
message, width=self.width, height=self.height, choices=choices)
|
||||
return _clean(self.dialog.checklist(
|
||||
message, width=self.width, height=self.height, choices=choices))
|
||||
|
||||
def directory_select(self, message, **unused_kwargs):
|
||||
"""Display a directory selection screen.
|
||||
@@ -193,14 +219,14 @@ class NcursesDisplay(object):
|
||||
:param str message: prompt to give the user
|
||||
|
||||
:returns: tuple of the form (`code`, `string`) where
|
||||
`code` - int display exit code
|
||||
`code` - display exit code
|
||||
`string` - input entered by the user
|
||||
|
||||
"""
|
||||
root_directory = os.path.abspath(os.sep)
|
||||
return self.dialog.dselect(
|
||||
return _clean(self.dialog.dselect(
|
||||
filepath=root_directory, width=self.width,
|
||||
height=self.height, help_button=True, title=message)
|
||||
height=self.height, help_button=True, title=message))
|
||||
|
||||
|
||||
@zope.interface.implementer(interfaces.IDisplay)
|
||||
@@ -355,7 +381,7 @@ class FileDisplay(object):
|
||||
:param str message: prompt to give the user
|
||||
|
||||
:returns: tuple of the form (`code`, `string`) where
|
||||
`code` - int display exit code
|
||||
`code` - display exit code
|
||||
`string` - input entered by the user
|
||||
|
||||
"""
|
||||
|
||||
@@ -96,6 +96,7 @@ class NcursesDisplayTest(unittest.TestCase):
|
||||
@mock.patch("certbot.display.util."
|
||||
"dialog.Dialog.inputbox")
|
||||
def test_input(self, mock_input):
|
||||
mock_input.return_value = (mock.MagicMock(), mock.MagicMock())
|
||||
self.displayer.input("message")
|
||||
self.assertEqual(mock_input.call_count, 1)
|
||||
|
||||
@@ -112,6 +113,7 @@ class NcursesDisplayTest(unittest.TestCase):
|
||||
@mock.patch("certbot.display.util."
|
||||
"dialog.Dialog.checklist")
|
||||
def test_checklist(self, mock_checklist):
|
||||
mock_checklist.return_value = (mock.MagicMock(), mock.MagicMock())
|
||||
self.displayer.checklist("message", TAGS)
|
||||
|
||||
choices = [
|
||||
@@ -125,6 +127,7 @@ class NcursesDisplayTest(unittest.TestCase):
|
||||
|
||||
@mock.patch("certbot.display.util.dialog.Dialog.dselect")
|
||||
def test_directory_select(self, mock_dselect):
|
||||
mock_dselect.return_value = (mock.MagicMock(), mock.MagicMock())
|
||||
self.displayer.directory_select("message")
|
||||
self.assertEqual(mock_dselect.call_count, 1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user