diff --git a/letsencrypt/client/cli.py b/letsencrypt/client/cli.py index e4150df7c..e77bef92d 100644 --- a/letsencrypt/client/cli.py +++ b/letsencrypt/client/cli.py @@ -82,7 +82,7 @@ def run(args, config, plugins): acc = _account_init(args, config) if acc is None: return None - + if args.configurator is not None and (args.installer is not None or args.authenticator is not None): return ("Either --configurator or --authenticator/--installer" @@ -171,53 +171,30 @@ def config_changes(args, config, plugins): client.config_changes(config) -def _print_plugins(plugins): - # TODO: this functions should use IDisplay rather than printing - - if not plugins: - print "No plugins found" - - for plugin_ep in plugins.itervalues(): - print "* {0}".format(plugin_ep.name) - print "Description: {0}".format(plugin_ep.plugin_cls.description) - print "Interfaces: {0}".format(", ".join( - iface.__name__ for iface in zope.interface.implementedBy( - plugin_ep.plugin_cls))) - print "Entry point: {0}".format(plugin_ep.entry_point) - - if plugin_ep.initialized: - print "Initialized: {0}".format(plugin_ep.init()) - - # if filtered == prepared: - #if isinstance(content, tuple) and content[1] is not None: - # print content[1] # error - - print # whitespace between plugins - - -def plugins_cmd(args, config, plugins): +def plugins_cmd(args, config, plugins): # TODO: Use IDiplay rathern than print """List plugins.""" logging.debug("Discovered plugins: %s", plugins) ifaces = [] if args.ifaces is None else args.ifaces - filtered = plugins.filter(*((iface,) for iface in ifaces)) - logging.debug("Filtered plugins: %s", filtered) + filtered = plugins.filter_ifaces(*((iface,) for iface in ifaces)) + logging.debug("Filtered plugins: %r", filtered) if not args.init and not args.prepare: - return _print_plugins(filtered) + print str(filtered) + return - for plugin_ep in filtered.itervalues(): - plugin_ep.init(config) - #verified = plugins_disco.verify_plugins(initialized, ifaces) - #logging.debug("Verified plugins: %s", initialized) + filtered.init(config) + verified = filtered.verify(ifaces) + logging.debug("Verified plugins: %r", verified) if not args.prepare: - return _print_plugins(filtered) + print str(verified) + return - available = plugins_disco.available_plugins(filtered) + verified.prepare() + available = verified.available() logging.debug("Prepared plugins: %s", available) - - _print_plugins(available) + print str(available) def read_file(filename): diff --git a/letsencrypt/client/display/ops.py b/letsencrypt/client/display/ops.py index 7b035ffd0..8ca534883 100644 --- a/letsencrypt/client/display/ops.py +++ b/letsencrypt/client/display/ops.py @@ -6,7 +6,7 @@ import zope.component from letsencrypt.client import interfaces from letsencrypt.client.display import util as display_util -from letsencrypt.client.plugins import disco as plugins_disco + # Define a helper function to avoid verbose code util = zope.component.getUtility # pylint: disable=invalid-name @@ -18,8 +18,8 @@ def choose_plugin(prepared, question): :param list prepared: """ - opts = [plugin_ep.name_with_description if not plugin_ep.misconfigured - else "%s (Misconfigured)" % plugin_ep.name_with_description + opts = [plugin_ep.name_with_description + + (" [Misconfigured]" if plugin_ep.misconfigured else "") for plugin_ep in prepared.itervalues()] while True: @@ -40,14 +40,15 @@ def choose_plugin(prepared, question): def _pick_plugin(config, default, plugins, question, ifaces): if default is not None: - filtered = {default: plugins[default]} + # throw more UX-friendly error if default not in plugins + filtered = plugins.filter(lambda p_ep: p_ep.name == default) else: - filtered = plugins.filter(ifaces) + filtered = plugins.filter_ifaces(ifaces) - for plugin_ep in plugins.itervalues(): - plugin_ep.init(config) - verified = plugins_disco.verify_plugins(filtered, ifaces) - prepared = plugins_disco.available_plugins(verified) + filtered.init(config) + verified = filtered.verify(ifaces) + filtered.prepare() + prepared = filtered.available() if len(prepared) > 1: logging.debug("Multiple candidate plugins: %s", prepared) diff --git a/letsencrypt/client/plugins/disco.py b/letsencrypt/client/plugins/disco.py index dec80afa9..a4557255e 100644 --- a/letsencrypt/client/plugins/disco.py +++ b/letsencrypt/client/plugins/disco.py @@ -96,6 +96,22 @@ class PluginEntryPoint(object): return False return True + def __str__(self): + lines = [ + "* {0}".format(self.name), + "Description: {0}".format(self.plugin_cls.description), + "Interfaces: {0}".format(", ".join( + iface.__name__ for iface in zope.interface.implementedBy( + self.plugin_cls))), + "Entry point: {0}".format(self.entry_point), + ] + + if self.initialized: + lines.append("Initialized: {0}".format(self.init())) + if self.prepared: + lines.append("Prep: {0}".format(self.prepare())) + + return "\n".join(lines) class PluginsRegistry(collections.Mapping): @@ -120,15 +136,34 @@ class PluginsRegistry(collections.Mapping): "IPluginFactory, skipping", plugin_ep) return cls(plugins) - def filter(self, *ifaces_groups): + def init(self, config): + """Initialize all plugins in the registry.""" + return [plugin_ep.init(config) for plugin_ep + 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))) + + def filter_ifaces(self, *ifaces_groups): """Filter plugins based on interfaces.""" - return type(self)(dict( - (name, plugin_ep) - for name, plugin_ep in self.plugins.iteritems() - if not ifaces_groups or any( + return self.filter(lambda plugin_ep: not ifaces_groups or any( all(iface.implementedBy(plugin_ep.plugin_cls) for iface in ifaces) - for ifaces in ifaces_groups))) + for ifaces in ifaces_groups)) + + def verify(self, ifaces): + """Filter plugins based on verification.""" + return self.filter(lambda p_ep: p_ep.verify(ifaces)) + + def prepare(self): + 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 __repr__(self): return "{0}({1!r})".format( @@ -143,18 +178,7 @@ class PluginsRegistry(collections.Mapping): def __len__(self): return len(self.plugins) - -def verify_plugins(initialized, ifaces): - """Verify plugin objects.""" - return dict((name, plugin_ep) for name, plugin_ep in initialized.iteritems() - if plugin_ep.verify(ifaces)) - - -def available_plugins(initialized): - """Prepare plugins and filter available.""" - prepared = {} - for name, plugin_ep in initialized.iteritems(): - plugin_ep.prepare() - if plugin_ep.available: - prepared[name] = plugin_ep - return prepared # succefully prepared + misconfigured + def __str__(self): + if not self.plugins: + return "No plugins" + return "\n\n".join(map(str, self.plugins.itervalues())) diff --git a/letsencrypt/client/plugins/disco_test.py b/letsencrypt/client/plugins/disco_test.py index dcfdb66f1..b55faba0c 100644 --- a/letsencrypt/client/plugins/disco_test.py +++ b/letsencrypt/client/plugins/disco_test.py @@ -85,8 +85,8 @@ class PluginsRegistryTest(unittest.TestCase): self.assertTrue(self.plugins["standalone"].plugin_cls is authenticator.StandaloneAuthenticator) - def test_filter(self): - filtered = self.plugins.filter() + def test_id_filter(self): + filtered = self.plugins.filter(lambda _: True) self.assertEqual(len(self.plugins), len(filtered)) def test_repr(self):