mirror of
https://github.com/certbot/certbot.git
synced 2026-06-07 07:42:08 -04:00
Merge branch 'cli' of https://github.com/kuba/lets-encrypt-preview into renewer
This commit is contained in:
commit
b30a8fbe90
5 changed files with 77 additions and 27 deletions
|
|
@ -239,7 +239,7 @@ def create_parser(plugins):
|
|||
help="Turn off confirmation screens, currently used for --revoke")
|
||||
add("-e", "--agree-tos", dest="tos", action="store_true",
|
||||
help="Skip the end user license agreement screen.")
|
||||
add("-t", "--text", dest="use_curses", action="store_false",
|
||||
add("-t", "--text", dest="text_mode", action="store_true",
|
||||
help="Use the text output instead of the curses UI.")
|
||||
|
||||
subparsers = parser.add_subparsers(metavar="SUBCOMMAND")
|
||||
|
|
@ -345,10 +345,10 @@ def main(args=sys.argv[1:]):
|
|||
config = configuration.NamespaceConfig(args)
|
||||
|
||||
# Displayer
|
||||
if args.use_curses:
|
||||
displayer = display_util.NcursesDisplay()
|
||||
else:
|
||||
if args.text_mode:
|
||||
displayer = display_util.FileDisplay(sys.stdout)
|
||||
else:
|
||||
displayer = display_util.NcursesDisplay()
|
||||
zope.component.provideUtility(displayer)
|
||||
|
||||
# Logging
|
||||
|
|
@ -356,7 +356,7 @@ def main(args=sys.argv[1:]):
|
|||
logger = logging.getLogger()
|
||||
logger.setLevel(level)
|
||||
logging.debug("Logging level set at %d", level)
|
||||
if args.use_curses:
|
||||
if not args.text_mode:
|
||||
logger.addHandler(log.DialogHandler())
|
||||
|
||||
logging.debug("Discovered plugins: %r", plugins)
|
||||
|
|
|
|||
|
|
@ -71,7 +71,11 @@ def pick_plugin(config, default, plugins, question, ifaces):
|
|||
|
||||
if len(prepared) > 1:
|
||||
logging.debug("Multiple candidate plugins: %s", prepared)
|
||||
return choose_plugin(prepared.values(), question).init()
|
||||
plugin_ep = choose_plugin(prepared.values(), question)
|
||||
if plugin_ep is None:
|
||||
return None
|
||||
else:
|
||||
return plugin_ep.init()
|
||||
elif len(prepared) == 1:
|
||||
plugin_ep = prepared.values()[0]
|
||||
logging.debug("Single candidate plugin: %s", plugin_ep)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ class PluginEntryPoint(object):
|
|||
PREFIX_FREE_DISTRIBUTIONS = ["letsencrypt"]
|
||||
"""Distributions for which prefix will be omitted."""
|
||||
|
||||
# this object is mutable, don't allow it to be hashed!
|
||||
__hash__ = None
|
||||
|
||||
def __init__(self, entry_point):
|
||||
self.name = self.entry_point_to_plugin_name(entry_point)
|
||||
self.plugin_cls = entry_point.load()
|
||||
|
|
@ -77,7 +80,7 @@ class PluginEntryPoint(object):
|
|||
def prepared(self):
|
||||
"""Has the plugin been prepared already?"""
|
||||
if not self.initialized:
|
||||
logging.debug(".prepared called on uninitialized %s", self)
|
||||
logging.debug(".prepared called on uninitialized %r", self)
|
||||
return self._prepared is not None
|
||||
|
||||
def prepare(self):
|
||||
|
|
@ -87,10 +90,10 @@ class PluginEntryPoint(object):
|
|||
try:
|
||||
self._initialized.prepare()
|
||||
except errors.LetsEncryptMisconfigurationError as error:
|
||||
logging.debug("Misconfigured %s: %s", self, error)
|
||||
logging.debug("Misconfigured %r: %s", self, error)
|
||||
self._prepared = error
|
||||
except errors.LetsEncryptNoInstallationError as error:
|
||||
logging.debug("No installation (%s): %s", self, error)
|
||||
logging.debug("No installation (%r): %s", self, error)
|
||||
self._prepared = error
|
||||
else:
|
||||
self._prepared = True
|
||||
|
|
@ -132,7 +135,7 @@ class PluginsRegistry(collections.Mapping):
|
|||
"""Plugins registry."""
|
||||
|
||||
def __init__(self, plugins):
|
||||
self.plugins = plugins
|
||||
self._plugins = plugins
|
||||
|
||||
@classmethod
|
||||
def find_all(cls):
|
||||
|
|
@ -147,28 +150,28 @@ class PluginsRegistry(collections.Mapping):
|
|||
if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):
|
||||
plugins[plugin_ep.name] = plugin_ep
|
||||
else: # pragma: no cover
|
||||
logging.warning("Plugin entry point %s does not provide "
|
||||
"IPluginFactory, skipping", plugin_ep)
|
||||
logging.warning(
|
||||
"%r does not provide IPluginFactory, skipping", plugin_ep)
|
||||
return cls(plugins)
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.plugins[name]
|
||||
return self._plugins[name]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.plugins)
|
||||
return iter(self._plugins)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.plugins)
|
||||
return len(self._plugins)
|
||||
|
||||
def init(self, config):
|
||||
"""Initialize all plugins in the registry."""
|
||||
return [plugin_ep.init(config) for plugin_ep
|
||||
in self.plugins.itervalues()]
|
||||
in self._plugins.itervalues()]
|
||||
|
||||
def filter(self, pred):
|
||||
"""Filter plugins based on predicate."""
|
||||
return type(self)(dict((name, plugin_ep) for name, plugin_ep
|
||||
in self.plugins.iteritems() if pred(plugin_ep)))
|
||||
in self._plugins.iteritems() if pred(plugin_ep)))
|
||||
|
||||
def ifaces(self, *ifaces_groups):
|
||||
"""Filter plugins based on interfaces."""
|
||||
|
|
@ -181,18 +184,41 @@ class PluginsRegistry(collections.Mapping):
|
|||
|
||||
def prepare(self):
|
||||
"""Prepare all plugins in the registry."""
|
||||
return [plugin_ep.prepare() for plugin_ep in self.plugins.itervalues()]
|
||||
return [plugin_ep.prepare() for plugin_ep in self._plugins.itervalues()]
|
||||
|
||||
def available(self):
|
||||
"""Filter plugins based on availability."""
|
||||
return self.filter(lambda p_ep: p_ep.available)
|
||||
# succefully prepared + misconfigured
|
||||
|
||||
def find_init(self, plugin):
|
||||
"""Find an initialized plugin.
|
||||
|
||||
This is particularly useful for finding a name for the plugin
|
||||
(although `.IPluginFactory.__call__` takes ``name`` as one of
|
||||
the arguments, ``IPlugin.name`` is not part of the interface)::
|
||||
|
||||
# plugin is an instance providing IPlugin, initialized
|
||||
# somewhere else in the code
|
||||
plugin_registry.find_init(plugin).name
|
||||
|
||||
Returns ``None`` if ``plugin`` is not found in the registry.
|
||||
|
||||
"""
|
||||
# use list instead of set beacse PluginEntryPoint is not hashable
|
||||
candidates = [plugin_ep for plugin_ep in self._plugins.itervalues()
|
||||
if plugin_ep.initialized and plugin_ep.init() is plugin]
|
||||
assert len(candidates) <= 1
|
||||
if candidates:
|
||||
return candidates[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return "{0}({1!r})".format(
|
||||
self.__class__.__name__, set(self.plugins.itervalues()))
|
||||
self.__class__.__name__, set(self._plugins.itervalues()))
|
||||
|
||||
def __str__(self):
|
||||
if not self.plugins:
|
||||
if not self._plugins:
|
||||
return "No plugins"
|
||||
return "\n\n".join(str(p_ep) for p_ep in self.plugins.itervalues())
|
||||
return "\n\n".join(str(p_ep) for p_ep in self._plugins.itervalues())
|
||||
|
|
|
|||
|
|
@ -194,16 +194,18 @@ class PluginsRegistryTest(unittest.TestCase):
|
|||
|
||||
def test_ifaces(self):
|
||||
self.plugin_ep.ifaces.return_value = True
|
||||
self.assertEqual(self.plugins, self.reg.ifaces().plugins)
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(self.plugins, self.reg.ifaces()._plugins)
|
||||
self.plugin_ep.ifaces.return_value = False
|
||||
self.assertEqual({}, self.reg.ifaces().plugins)
|
||||
self.assertEqual({}, self.reg.ifaces()._plugins)
|
||||
|
||||
def test_verify(self):
|
||||
self.plugin_ep.verify.return_value = True
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(
|
||||
self.plugins, self.reg.verify(mock.MagicMock()).plugins)
|
||||
self.plugins, self.reg.verify(mock.MagicMock())._plugins)
|
||||
self.plugin_ep.verify.return_value = False
|
||||
self.assertEqual({}, self.reg.verify(mock.MagicMock()).plugins)
|
||||
self.assertEqual({}, self.reg.verify(mock.MagicMock())._plugins)
|
||||
|
||||
def test_prepare(self):
|
||||
self.plugin_ep.prepare.return_value = "baz"
|
||||
|
|
@ -212,9 +214,16 @@ class PluginsRegistryTest(unittest.TestCase):
|
|||
|
||||
def test_available(self):
|
||||
self.plugin_ep.available = True
|
||||
self.assertEqual(self.plugins, self.reg.available().plugins)
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(self.plugins, self.reg.available()._plugins)
|
||||
self.plugin_ep.available = False
|
||||
self.assertEqual({}, self.reg.available().plugins)
|
||||
self.assertEqual({}, self.reg.available()._plugins)
|
||||
|
||||
def test_find_init(self):
|
||||
self.assertTrue(self.reg.find_init(mock.Mock()) is None)
|
||||
self.plugin_ep.initalized = True
|
||||
self.assertTrue(
|
||||
self.reg.find_init(self.plugin_ep.init()) is self.plugin_ep)
|
||||
|
||||
def test_repr(self):
|
||||
self.plugin_ep.__repr__ = lambda _: "PluginEntryPoint#mock"
|
||||
|
|
|
|||
|
|
@ -102,6 +102,17 @@ class PickPluginTest(unittest.TestCase):
|
|||
mock_choose.assert_called_once_with(
|
||||
[plugin_ep, plugin_ep], self.question)
|
||||
|
||||
def test_choose_plugin_none(self):
|
||||
self.reg.ifaces().verify().available.return_value = {
|
||||
"bar": None,
|
||||
"baz": None,
|
||||
}
|
||||
|
||||
with mock.patch("letsencrypt.client.display"
|
||||
".ops.choose_plugin") as mock_choose:
|
||||
mock_choose.return_value = None
|
||||
self.assertTrue(self._call() is None)
|
||||
|
||||
|
||||
class ConveniencePickPluginTest(unittest.TestCase):
|
||||
"""Tests for letsencrypt.client.display.ops.pick_*."""
|
||||
|
|
|
|||
Loading…
Reference in a new issue