1
0
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:
Brad Warren
2016-07-06 15:12:37 -07:00
committed by GitHub
2 changed files with 42 additions and 13 deletions

View File

@@ -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
"""

View File

@@ -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)