We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Ensure rename doesn't break third party plugins
There are a lot of third party plugins for Let's Encrypt (listed here: https://letsencrypt.readthedocs.org/en/latest/using.html#plugins)
It's possible that they reference things in such a way that changing the name or package of LE will break their compatibility with the client - we should ensure that they are unbroken


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `certbot/constants.py`
Content:
```
1 """Certbot constants."""
2 import os
3 import logging
4 
5 from acme import challenges
6 
7 
8 SETUPTOOLS_PLUGINS_ENTRY_POINT = "certbot.plugins"
9 """Setuptools entry point group name for plugins."""
10 
11 CLI_DEFAULTS = dict(
12     config_files=[
13         "/etc/letsencrypt/cli.ini",
14         # http://freedesktop.org/wiki/Software/xdg-user-dirs/
15         os.path.join(os.environ.get("XDG_CONFIG_HOME", "~/.config"),
16                      "letsencrypt", "cli.ini"),
17     ],
18     verbose_count=-(logging.WARNING / 10),
19     server="https://acme-v01.api.letsencrypt.org/directory",
20     rsa_key_size=2048,
21     rollback_checkpoints=1,
22     config_dir="/etc/letsencrypt",
23     work_dir="/var/lib/letsencrypt",
24     logs_dir="/var/log/letsencrypt",
25     no_verify_ssl=False,
26     http01_port=challenges.HTTP01Response.PORT,
27     tls_sni_01_port=challenges.TLSSNI01Response.PORT,
28 
29     auth_cert_path="./cert.pem",
30     auth_chain_path="./chain.pem",
31     strict_permissions=False,
32 )
33 STAGING_URI = "https://acme-staging.api.letsencrypt.org/directory"
34 
35 """Defaults for CLI flags and `.IConfig` attributes."""
36 
37 RENEWER_DEFAULTS = dict(
38     renewer_enabled="yes",
39     renew_before_expiry="30 days",
40     # This value should ensure that there is never a deployment delay by
41     # default.
42     deploy_before_expiry="99 years",
43 )
44 """Defaults for renewer script."""
45 
46 
47 ENHANCEMENTS = ["redirect", "http-header", "ocsp-stapling", "spdy"]
48 """List of possible :class:`certbot.interfaces.IInstaller`
49 enhancements.
50 
51 List of expected options parameters:
52 - redirect: None
53 - http-header: TODO
54 - ocsp-stapling: TODO
55 - spdy: TODO
56 
57 """
58 
59 ARCHIVE_DIR = "archive"
60 """Archive directory, relative to `IConfig.config_dir`."""
61 
62 CONFIG_DIRS_MODE = 0o755
63 """Directory mode for ``.IConfig.config_dir`` et al."""
64 
65 ACCOUNTS_DIR = "accounts"
66 """Directory where all accounts are saved."""
67 
68 BACKUP_DIR = "backups"
69 """Directory (relative to `IConfig.work_dir`) where backups are kept."""
70 
71 CSR_DIR = "csr"
72 """See `.IConfig.csr_dir`."""
73 
74 IN_PROGRESS_DIR = "IN_PROGRESS"
75 """Directory used before a permanent checkpoint is finalized (relative to
76 `IConfig.work_dir`)."""
77 
78 KEY_DIR = "keys"
79 """Directory (relative to `IConfig.config_dir`) where keys are saved."""
80 
81 LIVE_DIR = "live"
82 """Live directory, relative to `IConfig.config_dir`."""
83 
84 TEMP_CHECKPOINT_DIR = "temp_checkpoint"
85 """Temporary checkpoint directory (relative to `IConfig.work_dir`)."""
86 
87 RENEWAL_CONFIGS_DIR = "renewal"
88 """Renewal configs directory, relative to `IConfig.config_dir`."""
89 
90 RENEWER_CONFIG_FILENAME = "renewer.conf"
91 """Renewer config file name (relative to `IConfig.config_dir`)."""
92
```

Path: `certbot/plugins/disco.py`
Content:
```
1 """Utilities for plugins discovery and selection."""
2 import collections
3 import logging
4 import pkg_resources
5 
6 import zope.interface
7 import zope.interface.verify
8 
9 from certbot import constants
10 from certbot import errors
11 from certbot import interfaces
12 
13 
14 logger = logging.getLogger(__name__)
15 
16 
17 class PluginEntryPoint(object):
18     """Plugin entry point."""
19 
20     PREFIX_FREE_DISTRIBUTIONS = [
21         "certbot",
22         "certbot-apache",
23         "certbot-nginx",
24     ]
25     """Distributions for which prefix will be omitted."""
26 
27     # this object is mutable, don't allow it to be hashed!
28     __hash__ = None
29 
30     def __init__(self, entry_point):
31         self.name = self.entry_point_to_plugin_name(entry_point)
32         self.plugin_cls = entry_point.load()
33         self.entry_point = entry_point
34         self._initialized = None
35         self._prepared = None
36 
37     @classmethod
38     def entry_point_to_plugin_name(cls, entry_point):
39         """Unique plugin name for an ``entry_point``"""
40         if entry_point.dist.key in cls.PREFIX_FREE_DISTRIBUTIONS:
41             return entry_point.name
42         return entry_point.dist.key + ":" + entry_point.name
43 
44     @property
45     def description(self):
46         """Description of the plugin."""
47         return self.plugin_cls.description
48 
49     @property
50     def description_with_name(self):
51         """Description with name. Handy for UI."""
52         return "{0} ({1})".format(self.description, self.name)
53 
54     @property
55     def hidden(self):
56         """Should this plugin be hidden from UI?"""
57         return getattr(self.plugin_cls, "hidden", False)
58 
59     def ifaces(self, *ifaces_groups):
60         """Does plugin implements specified interface groups?"""
61         return not ifaces_groups or any(
62             all(iface.implementedBy(self.plugin_cls)
63                 for iface in ifaces)
64             for ifaces in ifaces_groups)
65 
66     @property
67     def initialized(self):
68         """Has the plugin been initialized already?"""
69         return self._initialized is not None
70 
71     def init(self, config=None):
72         """Memoized plugin inititialization."""
73         if not self.initialized:
74             self.entry_point.require()  # fetch extras!
75             self._initialized = self.plugin_cls(config, self.name)
76         return self._initialized
77 
78     def verify(self, ifaces):
79         """Verify that the plugin conforms to the specified interfaces."""
80         assert self.initialized
81         for iface in ifaces:  # zope.interface.providedBy(plugin)
82             try:
83                 zope.interface.verify.verifyObject(iface, self.init())
84             except zope.interface.exceptions.BrokenImplementation as error:
85                 if iface.implementedBy(self.plugin_cls):
86                     logger.debug(
87                         "%s implements %s but object does not verify: %s",
88                         self.plugin_cls, iface.__name__, error, exc_info=True)
89                 return False
90         return True
91 
92     @property
93     def prepared(self):
94         """Has the plugin been prepared already?"""
95         if not self.initialized:
96             logger.debug(".prepared called on uninitialized %r", self)
97         return self._prepared is not None
98 
99     def prepare(self):
100         """Memoized plugin preparation."""
101         assert self.initialized
102         if self._prepared is None:
103             try:
104                 self._initialized.prepare()
105             except errors.MisconfigurationError as error:
106                 logger.debug("Misconfigured %r: %s", self, error, exc_info=True)
107                 self._prepared = error
108             except errors.NoInstallationError as error:
109                 logger.debug(
110                     "No installation (%r): %s", self, error, exc_info=True)
111                 self._prepared = error
112             except errors.PluginError as error:
113                 logger.debug("Other error:(%r): %s", self, error, exc_info=True)
114                 self._prepared = error
115             else:
116                 self._prepared = True
117         return self._prepared
118 
119     @property
120     def misconfigured(self):
121         """Is plugin misconfigured?"""
122         return isinstance(self._prepared, errors.MisconfigurationError)
123 
124     @property
125     def problem(self):
126         """Return the Exception raised during plugin setup, or None if all is well"""
127         if isinstance(self._prepared, Exception):
128             return self._prepared
129         return None
130 
131     @property
132     def available(self):
133         """Is plugin available, i.e. prepared or misconfigured?"""
134         return self._prepared is True or self.misconfigured
135 
136     def __repr__(self):
137         return "PluginEntryPoint#{0}".format(self.name)
138 
139     def __str__(self):
140         lines = [
141             "* {0}".format(self.name),
142             "Description: {0}".format(self.plugin_cls.description),
143             "Interfaces: {0}".format(", ".join(
144                 iface.__name__ for iface in zope.interface.implementedBy(
145                     self.plugin_cls))),
146             "Entry point: {0}".format(self.entry_point),
147         ]
148 
149         if self.initialized:
150             lines.append("Initialized: {0}".format(self.init()))
151             if self.prepared:
152                 lines.append("Prep: {0}".format(self.prepare()))
153 
154         return "\n".join(lines)
155 
156 
157 class PluginsRegistry(collections.Mapping):
158     """Plugins registry."""
159 
160     def __init__(self, plugins):
161         self._plugins = plugins
162 
163     @classmethod
164     def find_all(cls):
165         """Find plugins using setuptools entry points."""
166         plugins = {}
167         for entry_point in pkg_resources.iter_entry_points(
168                 constants.SETUPTOOLS_PLUGINS_ENTRY_POINT):
169             plugin_ep = PluginEntryPoint(entry_point)
170             assert plugin_ep.name not in plugins, (
171                 "PREFIX_FREE_DISTRIBUTIONS messed up")
172             # providedBy | pylint: disable=no-member
173             if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):
174                 plugins[plugin_ep.name] = plugin_ep
175             else:  # pragma: no cover
176                 logger.warning(
177                     "%r does not provide IPluginFactory, skipping", plugin_ep)
178         return cls(plugins)
179 
180     def __getitem__(self, name):
181         return self._plugins[name]
182 
183     def __iter__(self):
184         return iter(self._plugins)
185 
186     def __len__(self):
187         return len(self._plugins)
188 
189     def init(self, config):
190         """Initialize all plugins in the registry."""
191         return [plugin_ep.init(config) for plugin_ep
192                 in self._plugins.itervalues()]
193 
194     def filter(self, pred):
195         """Filter plugins based on predicate."""
196         return type(self)(dict((name, plugin_ep) for name, plugin_ep
197                                in self._plugins.iteritems() if pred(plugin_ep)))
198 
199     def visible(self):
200         """Filter plugins based on visibility."""
201         return self.filter(lambda plugin_ep: not plugin_ep.hidden)
202 
203     def ifaces(self, *ifaces_groups):
204         """Filter plugins based on interfaces."""
205         # pylint: disable=star-args
206         return self.filter(lambda p_ep: p_ep.ifaces(*ifaces_groups))
207 
208     def verify(self, ifaces):
209         """Filter plugins based on verification."""
210         return self.filter(lambda p_ep: p_ep.verify(ifaces))
211 
212     def prepare(self):
213         """Prepare all plugins in the registry."""
214         return [plugin_ep.prepare() for plugin_ep in self._plugins.itervalues()]
215 
216     def available(self):
217         """Filter plugins based on availability."""
218         return self.filter(lambda p_ep: p_ep.available)
219         # succefully prepared + misconfigured
220 
221     def find_init(self, plugin):
222         """Find an initialized plugin.
223 
224         This is particularly useful for finding a name for the plugin
225         (although `.IPluginFactory.__call__` takes ``name`` as one of
226         the arguments, ``IPlugin.name`` is not part of the interface)::
227 
228           # plugin is an instance providing IPlugin, initialized
229           # somewhere else in the code
230           plugin_registry.find_init(plugin).name
231 
232         Returns ``None`` if ``plugin`` is not found in the registry.
233 
234         """
235         # use list instead of set because PluginEntryPoint is not hashable
236         candidates = [plugin_ep for plugin_ep in self._plugins.itervalues()
237                       if plugin_ep.initialized and plugin_ep.init() is plugin]
238         assert len(candidates) <= 1
239         if candidates:
240             return candidates[0]
241         else:
242             return None
243 
244     def __repr__(self):
245         return "{0}({1})".format(
246             self.__class__.__name__, ','.join(
247                 repr(p_ep) for p_ep in self._plugins.itervalues()))
248 
249     def __str__(self):
250         if not self._plugins:
251             return "No plugins"
252         return "\n\n".join(str(p_ep) for p_ep in self._plugins.itervalues())
253
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/certbot/constants.py b/certbot/constants.py
--- a/certbot/constants.py
+++ b/certbot/constants.py
@@ -8,6 +8,9 @@
 SETUPTOOLS_PLUGINS_ENTRY_POINT = "certbot.plugins"
 """Setuptools entry point group name for plugins."""
 
+OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT = "letsencrypt.plugins"
+"""Plugins Setuptools entry point before rename."""
+
 CLI_DEFAULTS = dict(
     config_files=[
         "/etc/letsencrypt/cli.ini",
diff --git a/certbot/plugins/disco.py b/certbot/plugins/disco.py
--- a/certbot/plugins/disco.py
+++ b/certbot/plugins/disco.py
@@ -1,5 +1,6 @@
 """Utilities for plugins discovery and selection."""
 import collections
+import itertools
 import logging
 import pkg_resources
 
@@ -164,8 +165,12 @@
     def find_all(cls):
         """Find plugins using setuptools entry points."""
         plugins = {}
-        for entry_point in pkg_resources.iter_entry_points(
-                constants.SETUPTOOLS_PLUGINS_ENTRY_POINT):
+        entry_points = itertools.chain(
+            pkg_resources.iter_entry_points(
+                constants.SETUPTOOLS_PLUGINS_ENTRY_POINT),
+            pkg_resources.iter_entry_points(
+                constants.OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT),)
+        for entry_point in entry_points:
             plugin_ep = PluginEntryPoint(entry_point)
             assert plugin_ep.name not in plugins, (
                 "PREFIX_FREE_DISTRIBUTIONS messed up")

{"golden_diff": "diff --git a/certbot/constants.py b/certbot/constants.py\n--- a/certbot/constants.py\n+++ b/certbot/constants.py\n@@ -8,6 +8,9 @@\n SETUPTOOLS_PLUGINS_ENTRY_POINT = \"certbot.plugins\"\n \"\"\"Setuptools entry point group name for plugins.\"\"\"\n \n+OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT = \"letsencrypt.plugins\"\n+\"\"\"Plugins Setuptools entry point before rename.\"\"\"\n+\n CLI_DEFAULTS = dict(\n     config_files=[\n         \"/etc/letsencrypt/cli.ini\",\ndiff --git a/certbot/plugins/disco.py b/certbot/plugins/disco.py\n--- a/certbot/plugins/disco.py\n+++ b/certbot/plugins/disco.py\n@@ -1,5 +1,6 @@\n \"\"\"Utilities for plugins discovery and selection.\"\"\"\n import collections\n+import itertools\n import logging\n import pkg_resources\n \n@@ -164,8 +165,12 @@\n     def find_all(cls):\n         \"\"\"Find plugins using setuptools entry points.\"\"\"\n         plugins = {}\n-        for entry_point in pkg_resources.iter_entry_points(\n-                constants.SETUPTOOLS_PLUGINS_ENTRY_POINT):\n+        entry_points = itertools.chain(\n+            pkg_resources.iter_entry_points(\n+                constants.SETUPTOOLS_PLUGINS_ENTRY_POINT),\n+            pkg_resources.iter_entry_points(\n+                constants.OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT),)\n+        for entry_point in entry_points:\n             plugin_ep = PluginEntryPoint(entry_point)\n             assert plugin_ep.name not in plugins, (\n                 \"PREFIX_FREE_DISTRIBUTIONS messed up\")\n", "issue": "Ensure rename doesn't break third party plugins\nThere are a lot of third party plugins for Let's Encrypt (listed here: https://letsencrypt.readthedocs.org/en/latest/using.html#plugins)\nIt's possible that they reference things in such a way that changing the name or package of LE will break their compatibility with the client - we should ensure that they are unbroken\n\n", "before_files": [{"content": "\"\"\"Certbot constants.\"\"\"\nimport os\nimport logging\n\nfrom acme import challenges\n\n\nSETUPTOOLS_PLUGINS_ENTRY_POINT = \"certbot.plugins\"\n\"\"\"Setuptools entry point group name for plugins.\"\"\"\n\nCLI_DEFAULTS = dict(\n    config_files=[\n        \"/etc/letsencrypt/cli.ini\",\n        # http://freedesktop.org/wiki/Software/xdg-user-dirs/\n        os.path.join(os.environ.get(\"XDG_CONFIG_HOME\", \"~/.config\"),\n                     \"letsencrypt\", \"cli.ini\"),\n    ],\n    verbose_count=-(logging.WARNING / 10),\n    server=\"https://acme-v01.api.letsencrypt.org/directory\",\n    rsa_key_size=2048,\n    rollback_checkpoints=1,\n    config_dir=\"/etc/letsencrypt\",\n    work_dir=\"/var/lib/letsencrypt\",\n    logs_dir=\"/var/log/letsencrypt\",\n    no_verify_ssl=False,\n    http01_port=challenges.HTTP01Response.PORT,\n    tls_sni_01_port=challenges.TLSSNI01Response.PORT,\n\n    auth_cert_path=\"./cert.pem\",\n    auth_chain_path=\"./chain.pem\",\n    strict_permissions=False,\n)\nSTAGING_URI = \"https://acme-staging.api.letsencrypt.org/directory\"\n\n\"\"\"Defaults for CLI flags and `.IConfig` attributes.\"\"\"\n\nRENEWER_DEFAULTS = dict(\n    renewer_enabled=\"yes\",\n    renew_before_expiry=\"30 days\",\n    # This value should ensure that there is never a deployment delay by\n    # default.\n    deploy_before_expiry=\"99 years\",\n)\n\"\"\"Defaults for renewer script.\"\"\"\n\n\nENHANCEMENTS = [\"redirect\", \"http-header\", \"ocsp-stapling\", \"spdy\"]\n\"\"\"List of possible :class:`certbot.interfaces.IInstaller`\nenhancements.\n\nList of expected options parameters:\n- redirect: None\n- http-header: TODO\n- ocsp-stapling: TODO\n- spdy: TODO\n\n\"\"\"\n\nARCHIVE_DIR = \"archive\"\n\"\"\"Archive directory, relative to `IConfig.config_dir`.\"\"\"\n\nCONFIG_DIRS_MODE = 0o755\n\"\"\"Directory mode for ``.IConfig.config_dir`` et al.\"\"\"\n\nACCOUNTS_DIR = \"accounts\"\n\"\"\"Directory where all accounts are saved.\"\"\"\n\nBACKUP_DIR = \"backups\"\n\"\"\"Directory (relative to `IConfig.work_dir`) where backups are kept.\"\"\"\n\nCSR_DIR = \"csr\"\n\"\"\"See `.IConfig.csr_dir`.\"\"\"\n\nIN_PROGRESS_DIR = \"IN_PROGRESS\"\n\"\"\"Directory used before a permanent checkpoint is finalized (relative to\n`IConfig.work_dir`).\"\"\"\n\nKEY_DIR = \"keys\"\n\"\"\"Directory (relative to `IConfig.config_dir`) where keys are saved.\"\"\"\n\nLIVE_DIR = \"live\"\n\"\"\"Live directory, relative to `IConfig.config_dir`.\"\"\"\n\nTEMP_CHECKPOINT_DIR = \"temp_checkpoint\"\n\"\"\"Temporary checkpoint directory (relative to `IConfig.work_dir`).\"\"\"\n\nRENEWAL_CONFIGS_DIR = \"renewal\"\n\"\"\"Renewal configs directory, relative to `IConfig.config_dir`.\"\"\"\n\nRENEWER_CONFIG_FILENAME = \"renewer.conf\"\n\"\"\"Renewer config file name (relative to `IConfig.config_dir`).\"\"\"\n", "path": "certbot/constants.py"}, {"content": "\"\"\"Utilities for plugins discovery and selection.\"\"\"\nimport collections\nimport logging\nimport pkg_resources\n\nimport zope.interface\nimport zope.interface.verify\n\nfrom certbot import constants\nfrom certbot import errors\nfrom certbot import interfaces\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PluginEntryPoint(object):\n    \"\"\"Plugin entry point.\"\"\"\n\n    PREFIX_FREE_DISTRIBUTIONS = [\n        \"certbot\",\n        \"certbot-apache\",\n        \"certbot-nginx\",\n    ]\n    \"\"\"Distributions for which prefix will be omitted.\"\"\"\n\n    # this object is mutable, don't allow it to be hashed!\n    __hash__ = None\n\n    def __init__(self, entry_point):\n        self.name = self.entry_point_to_plugin_name(entry_point)\n        self.plugin_cls = entry_point.load()\n        self.entry_point = entry_point\n        self._initialized = None\n        self._prepared = None\n\n    @classmethod\n    def entry_point_to_plugin_name(cls, entry_point):\n        \"\"\"Unique plugin name for an ``entry_point``\"\"\"\n        if entry_point.dist.key in cls.PREFIX_FREE_DISTRIBUTIONS:\n            return entry_point.name\n        return entry_point.dist.key + \":\" + entry_point.name\n\n    @property\n    def description(self):\n        \"\"\"Description of the plugin.\"\"\"\n        return self.plugin_cls.description\n\n    @property\n    def description_with_name(self):\n        \"\"\"Description with name. Handy for UI.\"\"\"\n        return \"{0} ({1})\".format(self.description, self.name)\n\n    @property\n    def hidden(self):\n        \"\"\"Should this plugin be hidden from UI?\"\"\"\n        return getattr(self.plugin_cls, \"hidden\", False)\n\n    def ifaces(self, *ifaces_groups):\n        \"\"\"Does plugin implements specified interface groups?\"\"\"\n        return not ifaces_groups or any(\n            all(iface.implementedBy(self.plugin_cls)\n                for iface in ifaces)\n            for ifaces in ifaces_groups)\n\n    @property\n    def initialized(self):\n        \"\"\"Has the plugin been initialized already?\"\"\"\n        return self._initialized is not None\n\n    def init(self, config=None):\n        \"\"\"Memoized plugin inititialization.\"\"\"\n        if not self.initialized:\n            self.entry_point.require()  # fetch extras!\n            self._initialized = self.plugin_cls(config, self.name)\n        return self._initialized\n\n    def verify(self, ifaces):\n        \"\"\"Verify that the plugin conforms to the specified interfaces.\"\"\"\n        assert self.initialized\n        for iface in ifaces:  # zope.interface.providedBy(plugin)\n            try:\n                zope.interface.verify.verifyObject(iface, self.init())\n            except zope.interface.exceptions.BrokenImplementation as error:\n                if iface.implementedBy(self.plugin_cls):\n                    logger.debug(\n                        \"%s implements %s but object does not verify: %s\",\n                        self.plugin_cls, iface.__name__, error, exc_info=True)\n                return False\n        return True\n\n    @property\n    def prepared(self):\n        \"\"\"Has the plugin been prepared already?\"\"\"\n        if not self.initialized:\n            logger.debug(\".prepared called on uninitialized %r\", self)\n        return self._prepared is not None\n\n    def prepare(self):\n        \"\"\"Memoized plugin preparation.\"\"\"\n        assert self.initialized\n        if self._prepared is None:\n            try:\n                self._initialized.prepare()\n            except errors.MisconfigurationError as error:\n                logger.debug(\"Misconfigured %r: %s\", self, error, exc_info=True)\n                self._prepared = error\n            except errors.NoInstallationError as error:\n                logger.debug(\n                    \"No installation (%r): %s\", self, error, exc_info=True)\n                self._prepared = error\n            except errors.PluginError as error:\n                logger.debug(\"Other error:(%r): %s\", self, error, exc_info=True)\n                self._prepared = error\n            else:\n                self._prepared = True\n        return self._prepared\n\n    @property\n    def misconfigured(self):\n        \"\"\"Is plugin misconfigured?\"\"\"\n        return isinstance(self._prepared, errors.MisconfigurationError)\n\n    @property\n    def problem(self):\n        \"\"\"Return the Exception raised during plugin setup, or None if all is well\"\"\"\n        if isinstance(self._prepared, Exception):\n            return self._prepared\n        return None\n\n    @property\n    def available(self):\n        \"\"\"Is plugin available, i.e. prepared or misconfigured?\"\"\"\n        return self._prepared is True or self.misconfigured\n\n    def __repr__(self):\n        return \"PluginEntryPoint#{0}\".format(self.name)\n\n    def __str__(self):\n        lines = [\n            \"* {0}\".format(self.name),\n            \"Description: {0}\".format(self.plugin_cls.description),\n            \"Interfaces: {0}\".format(\", \".join(\n                iface.__name__ for iface in zope.interface.implementedBy(\n                    self.plugin_cls))),\n            \"Entry point: {0}\".format(self.entry_point),\n        ]\n\n        if self.initialized:\n            lines.append(\"Initialized: {0}\".format(self.init()))\n            if self.prepared:\n                lines.append(\"Prep: {0}\".format(self.prepare()))\n\n        return \"\\n\".join(lines)\n\n\nclass PluginsRegistry(collections.Mapping):\n    \"\"\"Plugins registry.\"\"\"\n\n    def __init__(self, plugins):\n        self._plugins = plugins\n\n    @classmethod\n    def find_all(cls):\n        \"\"\"Find plugins using setuptools entry points.\"\"\"\n        plugins = {}\n        for entry_point in pkg_resources.iter_entry_points(\n                constants.SETUPTOOLS_PLUGINS_ENTRY_POINT):\n            plugin_ep = PluginEntryPoint(entry_point)\n            assert plugin_ep.name not in plugins, (\n                \"PREFIX_FREE_DISTRIBUTIONS messed up\")\n            # providedBy | pylint: disable=no-member\n            if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):\n                plugins[plugin_ep.name] = plugin_ep\n            else:  # pragma: no cover\n                logger.warning(\n                    \"%r does not provide IPluginFactory, skipping\", plugin_ep)\n        return cls(plugins)\n\n    def __getitem__(self, name):\n        return self._plugins[name]\n\n    def __iter__(self):\n        return iter(self._plugins)\n\n    def __len__(self):\n        return len(self._plugins)\n\n    def init(self, config):\n        \"\"\"Initialize all plugins in the registry.\"\"\"\n        return [plugin_ep.init(config) for plugin_ep\n                in self._plugins.itervalues()]\n\n    def filter(self, pred):\n        \"\"\"Filter plugins based on predicate.\"\"\"\n        return type(self)(dict((name, plugin_ep) for name, plugin_ep\n                               in self._plugins.iteritems() if pred(plugin_ep)))\n\n    def visible(self):\n        \"\"\"Filter plugins based on visibility.\"\"\"\n        return self.filter(lambda plugin_ep: not plugin_ep.hidden)\n\n    def ifaces(self, *ifaces_groups):\n        \"\"\"Filter plugins based on interfaces.\"\"\"\n        # pylint: disable=star-args\n        return self.filter(lambda p_ep: p_ep.ifaces(*ifaces_groups))\n\n    def verify(self, ifaces):\n        \"\"\"Filter plugins based on verification.\"\"\"\n        return self.filter(lambda p_ep: p_ep.verify(ifaces))\n\n    def prepare(self):\n        \"\"\"Prepare all plugins in the registry.\"\"\"\n        return [plugin_ep.prepare() for plugin_ep in self._plugins.itervalues()]\n\n    def available(self):\n        \"\"\"Filter plugins based on availability.\"\"\"\n        return self.filter(lambda p_ep: p_ep.available)\n        # succefully prepared + misconfigured\n\n    def find_init(self, plugin):\n        \"\"\"Find an initialized plugin.\n\n        This is particularly useful for finding a name for the plugin\n        (although `.IPluginFactory.__call__` takes ``name`` as one of\n        the arguments, ``IPlugin.name`` is not part of the interface)::\n\n          # plugin is an instance providing IPlugin, initialized\n          # somewhere else in the code\n          plugin_registry.find_init(plugin).name\n\n        Returns ``None`` if ``plugin`` is not found in the registry.\n\n        \"\"\"\n        # use list instead of set because PluginEntryPoint is not hashable\n        candidates = [plugin_ep for plugin_ep in self._plugins.itervalues()\n                      if plugin_ep.initialized and plugin_ep.init() is plugin]\n        assert len(candidates) <= 1\n        if candidates:\n            return candidates[0]\n        else:\n            return None\n\n    def __repr__(self):\n        return \"{0}({1})\".format(\n            self.__class__.__name__, ','.join(\n                repr(p_ep) for p_ep in self._plugins.itervalues()))\n\n    def __str__(self):\n        if not self._plugins:\n            return \"No plugins\"\n        return \"\\n\\n\".join(str(p_ep) for p_ep in self._plugins.itervalues())\n", "path": "certbot/plugins/disco.py"}], "after_files": [{"content": "\"\"\"Certbot constants.\"\"\"\nimport os\nimport logging\n\nfrom acme import challenges\n\n\nSETUPTOOLS_PLUGINS_ENTRY_POINT = \"certbot.plugins\"\n\"\"\"Setuptools entry point group name for plugins.\"\"\"\n\nOLD_SETUPTOOLS_PLUGINS_ENTRY_POINT = \"letsencrypt.plugins\"\n\"\"\"Plugins Setuptools entry point before rename.\"\"\"\n\nCLI_DEFAULTS = dict(\n    config_files=[\n        \"/etc/letsencrypt/cli.ini\",\n        # http://freedesktop.org/wiki/Software/xdg-user-dirs/\n        os.path.join(os.environ.get(\"XDG_CONFIG_HOME\", \"~/.config\"),\n                     \"letsencrypt\", \"cli.ini\"),\n    ],\n    verbose_count=-(logging.WARNING / 10),\n    server=\"https://acme-v01.api.letsencrypt.org/directory\",\n    rsa_key_size=2048,\n    rollback_checkpoints=1,\n    config_dir=\"/etc/letsencrypt\",\n    work_dir=\"/var/lib/letsencrypt\",\n    logs_dir=\"/var/log/letsencrypt\",\n    no_verify_ssl=False,\n    http01_port=challenges.HTTP01Response.PORT,\n    tls_sni_01_port=challenges.TLSSNI01Response.PORT,\n\n    auth_cert_path=\"./cert.pem\",\n    auth_chain_path=\"./chain.pem\",\n    strict_permissions=False,\n)\nSTAGING_URI = \"https://acme-staging.api.letsencrypt.org/directory\"\n\n\"\"\"Defaults for CLI flags and `.IConfig` attributes.\"\"\"\n\nRENEWER_DEFAULTS = dict(\n    renewer_enabled=\"yes\",\n    renew_before_expiry=\"30 days\",\n    # This value should ensure that there is never a deployment delay by\n    # default.\n    deploy_before_expiry=\"99 years\",\n)\n\"\"\"Defaults for renewer script.\"\"\"\n\n\nENHANCEMENTS = [\"redirect\", \"http-header\", \"ocsp-stapling\", \"spdy\"]\n\"\"\"List of possible :class:`certbot.interfaces.IInstaller`\nenhancements.\n\nList of expected options parameters:\n- redirect: None\n- http-header: TODO\n- ocsp-stapling: TODO\n- spdy: TODO\n\n\"\"\"\n\nARCHIVE_DIR = \"archive\"\n\"\"\"Archive directory, relative to `IConfig.config_dir`.\"\"\"\n\nCONFIG_DIRS_MODE = 0o755\n\"\"\"Directory mode for ``.IConfig.config_dir`` et al.\"\"\"\n\nACCOUNTS_DIR = \"accounts\"\n\"\"\"Directory where all accounts are saved.\"\"\"\n\nBACKUP_DIR = \"backups\"\n\"\"\"Directory (relative to `IConfig.work_dir`) where backups are kept.\"\"\"\n\nCSR_DIR = \"csr\"\n\"\"\"See `.IConfig.csr_dir`.\"\"\"\n\nIN_PROGRESS_DIR = \"IN_PROGRESS\"\n\"\"\"Directory used before a permanent checkpoint is finalized (relative to\n`IConfig.work_dir`).\"\"\"\n\nKEY_DIR = \"keys\"\n\"\"\"Directory (relative to `IConfig.config_dir`) where keys are saved.\"\"\"\n\nLIVE_DIR = \"live\"\n\"\"\"Live directory, relative to `IConfig.config_dir`.\"\"\"\n\nTEMP_CHECKPOINT_DIR = \"temp_checkpoint\"\n\"\"\"Temporary checkpoint directory (relative to `IConfig.work_dir`).\"\"\"\n\nRENEWAL_CONFIGS_DIR = \"renewal\"\n\"\"\"Renewal configs directory, relative to `IConfig.config_dir`.\"\"\"\n\nRENEWER_CONFIG_FILENAME = \"renewer.conf\"\n\"\"\"Renewer config file name (relative to `IConfig.config_dir`).\"\"\"\n", "path": "certbot/constants.py"}, {"content": "\"\"\"Utilities for plugins discovery and selection.\"\"\"\nimport collections\nimport itertools\nimport logging\nimport pkg_resources\n\nimport zope.interface\nimport zope.interface.verify\n\nfrom certbot import constants\nfrom certbot import errors\nfrom certbot import interfaces\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass PluginEntryPoint(object):\n    \"\"\"Plugin entry point.\"\"\"\n\n    PREFIX_FREE_DISTRIBUTIONS = [\n        \"certbot\",\n        \"certbot-apache\",\n        \"certbot-nginx\",\n    ]\n    \"\"\"Distributions for which prefix will be omitted.\"\"\"\n\n    # this object is mutable, don't allow it to be hashed!\n    __hash__ = None\n\n    def __init__(self, entry_point):\n        self.name = self.entry_point_to_plugin_name(entry_point)\n        self.plugin_cls = entry_point.load()\n        self.entry_point = entry_point\n        self._initialized = None\n        self._prepared = None\n\n    @classmethod\n    def entry_point_to_plugin_name(cls, entry_point):\n        \"\"\"Unique plugin name for an ``entry_point``\"\"\"\n        if entry_point.dist.key in cls.PREFIX_FREE_DISTRIBUTIONS:\n            return entry_point.name\n        return entry_point.dist.key + \":\" + entry_point.name\n\n    @property\n    def description(self):\n        \"\"\"Description of the plugin.\"\"\"\n        return self.plugin_cls.description\n\n    @property\n    def description_with_name(self):\n        \"\"\"Description with name. Handy for UI.\"\"\"\n        return \"{0} ({1})\".format(self.description, self.name)\n\n    @property\n    def hidden(self):\n        \"\"\"Should this plugin be hidden from UI?\"\"\"\n        return getattr(self.plugin_cls, \"hidden\", False)\n\n    def ifaces(self, *ifaces_groups):\n        \"\"\"Does plugin implements specified interface groups?\"\"\"\n        return not ifaces_groups or any(\n            all(iface.implementedBy(self.plugin_cls)\n                for iface in ifaces)\n            for ifaces in ifaces_groups)\n\n    @property\n    def initialized(self):\n        \"\"\"Has the plugin been initialized already?\"\"\"\n        return self._initialized is not None\n\n    def init(self, config=None):\n        \"\"\"Memoized plugin inititialization.\"\"\"\n        if not self.initialized:\n            self.entry_point.require()  # fetch extras!\n            self._initialized = self.plugin_cls(config, self.name)\n        return self._initialized\n\n    def verify(self, ifaces):\n        \"\"\"Verify that the plugin conforms to the specified interfaces.\"\"\"\n        assert self.initialized\n        for iface in ifaces:  # zope.interface.providedBy(plugin)\n            try:\n                zope.interface.verify.verifyObject(iface, self.init())\n            except zope.interface.exceptions.BrokenImplementation as error:\n                if iface.implementedBy(self.plugin_cls):\n                    logger.debug(\n                        \"%s implements %s but object does not verify: %s\",\n                        self.plugin_cls, iface.__name__, error, exc_info=True)\n                return False\n        return True\n\n    @property\n    def prepared(self):\n        \"\"\"Has the plugin been prepared already?\"\"\"\n        if not self.initialized:\n            logger.debug(\".prepared called on uninitialized %r\", self)\n        return self._prepared is not None\n\n    def prepare(self):\n        \"\"\"Memoized plugin preparation.\"\"\"\n        assert self.initialized\n        if self._prepared is None:\n            try:\n                self._initialized.prepare()\n            except errors.MisconfigurationError as error:\n                logger.debug(\"Misconfigured %r: %s\", self, error, exc_info=True)\n                self._prepared = error\n            except errors.NoInstallationError as error:\n                logger.debug(\n                    \"No installation (%r): %s\", self, error, exc_info=True)\n                self._prepared = error\n            except errors.PluginError as error:\n                logger.debug(\"Other error:(%r): %s\", self, error, exc_info=True)\n                self._prepared = error\n            else:\n                self._prepared = True\n        return self._prepared\n\n    @property\n    def misconfigured(self):\n        \"\"\"Is plugin misconfigured?\"\"\"\n        return isinstance(self._prepared, errors.MisconfigurationError)\n\n    @property\n    def problem(self):\n        \"\"\"Return the Exception raised during plugin setup, or None if all is well\"\"\"\n        if isinstance(self._prepared, Exception):\n            return self._prepared\n        return None\n\n    @property\n    def available(self):\n        \"\"\"Is plugin available, i.e. prepared or misconfigured?\"\"\"\n        return self._prepared is True or self.misconfigured\n\n    def __repr__(self):\n        return \"PluginEntryPoint#{0}\".format(self.name)\n\n    def __str__(self):\n        lines = [\n            \"* {0}\".format(self.name),\n            \"Description: {0}\".format(self.plugin_cls.description),\n            \"Interfaces: {0}\".format(\", \".join(\n                iface.__name__ for iface in zope.interface.implementedBy(\n                    self.plugin_cls))),\n            \"Entry point: {0}\".format(self.entry_point),\n        ]\n\n        if self.initialized:\n            lines.append(\"Initialized: {0}\".format(self.init()))\n            if self.prepared:\n                lines.append(\"Prep: {0}\".format(self.prepare()))\n\n        return \"\\n\".join(lines)\n\n\nclass PluginsRegistry(collections.Mapping):\n    \"\"\"Plugins registry.\"\"\"\n\n    def __init__(self, plugins):\n        self._plugins = plugins\n\n    @classmethod\n    def find_all(cls):\n        \"\"\"Find plugins using setuptools entry points.\"\"\"\n        plugins = {}\n        entry_points = itertools.chain(\n            pkg_resources.iter_entry_points(\n                constants.SETUPTOOLS_PLUGINS_ENTRY_POINT),\n            pkg_resources.iter_entry_points(\n                constants.OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT),)\n        for entry_point in entry_points:\n            plugin_ep = PluginEntryPoint(entry_point)\n            assert plugin_ep.name not in plugins, (\n                \"PREFIX_FREE_DISTRIBUTIONS messed up\")\n            # providedBy | pylint: disable=no-member\n            if interfaces.IPluginFactory.providedBy(plugin_ep.plugin_cls):\n                plugins[plugin_ep.name] = plugin_ep\n            else:  # pragma: no cover\n                logger.warning(\n                    \"%r does not provide IPluginFactory, skipping\", plugin_ep)\n        return cls(plugins)\n\n    def __getitem__(self, name):\n        return self._plugins[name]\n\n    def __iter__(self):\n        return iter(self._plugins)\n\n    def __len__(self):\n        return len(self._plugins)\n\n    def init(self, config):\n        \"\"\"Initialize all plugins in the registry.\"\"\"\n        return [plugin_ep.init(config) for plugin_ep\n                in self._plugins.itervalues()]\n\n    def filter(self, pred):\n        \"\"\"Filter plugins based on predicate.\"\"\"\n        return type(self)(dict((name, plugin_ep) for name, plugin_ep\n                               in self._plugins.iteritems() if pred(plugin_ep)))\n\n    def visible(self):\n        \"\"\"Filter plugins based on visibility.\"\"\"\n        return self.filter(lambda plugin_ep: not plugin_ep.hidden)\n\n    def ifaces(self, *ifaces_groups):\n        \"\"\"Filter plugins based on interfaces.\"\"\"\n        # pylint: disable=star-args\n        return self.filter(lambda p_ep: p_ep.ifaces(*ifaces_groups))\n\n    def verify(self, ifaces):\n        \"\"\"Filter plugins based on verification.\"\"\"\n        return self.filter(lambda p_ep: p_ep.verify(ifaces))\n\n    def prepare(self):\n        \"\"\"Prepare all plugins in the registry.\"\"\"\n        return [plugin_ep.prepare() for plugin_ep in self._plugins.itervalues()]\n\n    def available(self):\n        \"\"\"Filter plugins based on availability.\"\"\"\n        return self.filter(lambda p_ep: p_ep.available)\n        # succefully prepared + misconfigured\n\n    def find_init(self, plugin):\n        \"\"\"Find an initialized plugin.\n\n        This is particularly useful for finding a name for the plugin\n        (although `.IPluginFactory.__call__` takes ``name`` as one of\n        the arguments, ``IPlugin.name`` is not part of the interface)::\n\n          # plugin is an instance providing IPlugin, initialized\n          # somewhere else in the code\n          plugin_registry.find_init(plugin).name\n\n        Returns ``None`` if ``plugin`` is not found in the registry.\n\n        \"\"\"\n        # use list instead of set because PluginEntryPoint is not hashable\n        candidates = [plugin_ep for plugin_ep in self._plugins.itervalues()\n                      if plugin_ep.initialized and plugin_ep.init() is plugin]\n        assert len(candidates) <= 1\n        if candidates:\n            return candidates[0]\n        else:\n            return None\n\n    def __repr__(self):\n        return \"{0}({1})\".format(\n            self.__class__.__name__, ','.join(\n                repr(p_ep) for p_ep in self._plugins.itervalues()))\n\n    def __str__(self):\n        if not self._plugins:\n            return \"No plugins\"\n        return \"\\n\\n\".join(str(p_ep) for p_ep in self._plugins.itervalues())\n", "path": "certbot/plugins/disco.py"}]}