From 78be30d4579f22ac9896de5ae0b2b1d76d8c1c6c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 13 Oct 2015 14:38:31 -0700 Subject: [PATCH 01/92] Basic support for --apache and --nginx - Also begin to clean up the code that integrates --configurator, --installer, and --authenticator inputs. --- letsencrypt/cli.py | 65 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 64cba508d..5c74e1ea9 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -304,31 +304,54 @@ def _auth_from_domains(le_client, config, domains, plugins): return lineage +class ConfiguratorError(TypeError): + pass + +def set_configurator(previously, now): + """Setting configurators multiple ways is okay, as long as they all agree""" + if previously: + if previously != now: + raise ConfiguratorError, "Too many flags setting configurators/installers/authenticators %s -> %s" % (`previously`,`now`) + return now + +def pick_configurator(args, config, plugins, verb): + """Figure out which configurator we're going to use""" + installer = authenticator = args.configurator + print "args.configurator", args.configurator + installer = set_configurator(installer, args.installer) + authenticator = set_configurator(authenticator, args.authenticator) + print "installer", installer + if args.nginx: + installer = set_configurator(installer, nginx) + authenticator = set_configurator(authenticator, nginx) + if args.apache: + installer = set_configurator(installer, apache) + authenticator = set_configurator(authenticator, apache) + + if authenticator == installer: + # TODO: this assumes that user doesn't want to pick authenticator + # and installer separately... + authenticator = installer = display_ops.pick_configurator(config, args.installer, plugins) + #print "ainstaller", installer + else: + installer = display_ops.pick_installer(config, installer, plugins) + authenticator = display_ops.pick_authenticator(config, authenticator, plugins) + #print "binstaller", installer + + if installer is None or authenticator is None: + #print installer, authenticator + raise ConfiguratorError, "Configurator could not be determined" + return installer, authenticator + # TODO: Make run as close to auth + install as possible # Possible difficulties: args.csr was hacked into auth def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-locals """Obtain a certificate and install.""" - # Begin authenticator and installer setup - if args.configurator is not None and (args.installer is not None or - args.authenticator is not None): - return ("Either --configurator or --authenticator/--installer" - "pair, but not both, is allowed") - - if args.authenticator is not None or args.installer is not None: - installer = display_ops.pick_installer( - config, args.installer, plugins) - authenticator = display_ops.pick_authenticator( - config, args.authenticator, plugins) - else: - # TODO: this assumes that user doesn't want to pick authenticator - # and installer separately... - authenticator = installer = display_ops.pick_configurator( - config, args.configurator, plugins) - - if installer is None or authenticator is None: - return "Configurator could not be determined" - # End authenticator and installer setup + try: + installer, authenticator = pick_configurator(args, config, plugins, "run") + except ConfiguratorError, e: + return e.message domains = _find_domains(args, installer) @@ -656,6 +679,8 @@ def create_parser(plugins, args): None, "-t", "--text", dest="text_mode", action="store_true", help="Use the text output instead of the curses UI.") helpful.add(None, "-m", "--email", help=config_help("email")) + helpful.add(None, "--apache", help="Obtain and install certs using Apache") + helpful.add(None, "--nginx", help="Obtain and install certs using Nginx") # positional arg shadows --domains, instead of appending, and # --domains is useful, because it can be stored in config #for subparser in parser_run, parser_auth, parser_install: From 29ee633dede35807bb0f972239fb3f9145c6a0d9 Mon Sep 17 00:00:00 2001 From: Luke Rogers Date: Thu, 15 Oct 2015 14:12:38 +1300 Subject: [PATCH 02/92] Tidy up a list in the readme. Just capitalising a few things. --- README.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index 43ecd413c..4040ca284 100644 --- a/README.rst +++ b/README.rst @@ -76,23 +76,23 @@ server automatically!:: Current Features ---------------- -* web servers supported: +* Supports multiple web servers: - apache/2.x (tested and working on Ubuntu Linux) - nginx/0.8.48+ (under development) - - standalone (runs its own webserver to prove you control the domain) + - standalone (runs it's own simple webserver to prove you control a domain) -* the private key is generated locally on your system -* can talk to the Let's Encrypt (demo) CA or optionally to other ACME - compliant services -* can get domain-validated (DV) certificates -* can revoke certificates -* adjustable RSA key bitlength (2048 (default), 4096, ...) -* optionally can install a http->https redirect, so your site effectively +* The private key is generated locally on your system. +* Can talk to the Let's Encrypt (demo) CA or optionally to other ACME + compliant services. +* Can get domain-validated (DV) certificates. +* Can revoke certificates. +* Adjustable RSA key bit-length (2048 (default), 4096, ...). +* Can optionally install a http -> https redirect, so your site effectively runs https only (Apache only) -* fully automated -* configuration changes are logged and can be reverted using the CLI -* text and ncurses UI +* Fully automated. +* Configuration changes are logged and can be reverted. +* Text and ncurses UI. * Free and Open Source Software, made with Python. From 9bde3b7084635588c73c2c8d7451ffd12a2932bc Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 16 Oct 2015 10:34:29 -0700 Subject: [PATCH 03/92] Support for --apache and --nginx now working. - Along with much better error messages for misconfigured plugins --- letsencrypt/cli.py | 83 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 5c74e1ea9..af0f58378 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -314,33 +314,66 @@ def set_configurator(previously, now): raise ConfiguratorError, "Too many flags setting configurators/installers/authenticators %s -> %s" % (`previously`,`now`) return now -def pick_configurator(args, config, plugins, verb): +def diagnose_configurator_problem(cfg_type, requested): + """ + Raise the most helpful error message about a plugin being unavailable + @cfg_type -- "installer" or "authenticator" + @requested -- which plugin the user wanted + """ + plugins = plugins_disco.PluginsRegistry.find_all() + + if requested: + if requested not in plugins: + msg = "The requested " + requested + " plugin does not appear to be installed" + raise ConfiguratorError, msg + else: + msg = "The " + requested + " plugin is not working; there may be problems " + msg += "with your existing configuration" + raise ConfiguratorError, msg + raise ConfiguratorError, "Installer could not be determined or is not installed" + + + +def choose_configurator_plugins(args, config, plugins, verb): """Figure out which configurator we're going to use""" - installer = authenticator = args.configurator - print "args.configurator", args.configurator - installer = set_configurator(installer, args.installer) - authenticator = set_configurator(authenticator, args.authenticator) - print "installer", installer + + # Which plugins do we need? + need_inst = need_auth = (verb == "run") + if verb == "auth": + need_auth = True + if verb == "install": + need_install = True + + # Which plugins did the user request? + req_inst = req_auth = args.configurator + req_inst = set_configurator(req_inst, args.installer) + req_auth = set_configurator(req_auth, args.authenticator) if args.nginx: - installer = set_configurator(installer, nginx) - authenticator = set_configurator(authenticator, nginx) + req_inst = set_configurator(req_inst, "nginx") + req_auth = set_configurator(req_auth, "nginx") if args.apache: - installer = set_configurator(installer, apache) - authenticator = set_configurator(authenticator, apache) + req_inst = set_configurator(req_inst, "apache") + req_auth = set_configurator(req_auth, "apache") - if authenticator == installer: - # TODO: this assumes that user doesn't want to pick authenticator - # and installer separately... - authenticator = installer = display_ops.pick_configurator(config, args.installer, plugins) - #print "ainstaller", installer + logger.debug("Requested authenticator %s and installer %s" % (req_auth, req_inst)) + + # Try to meet the user's request and/or ask them to pick plugins + if verb == "run" and req_auth == req_inst: + # Unless the user has explicitly asked for different auth/install, + # only consider offering a single choice + authenticator = installer = display_ops.pick_configurator(config, req_inst, plugins) else: - installer = display_ops.pick_installer(config, installer, plugins) - authenticator = display_ops.pick_authenticator(config, authenticator, plugins) - #print "binstaller", installer + if need_inst: + installer = display_ops.pick_installer(config, req_inst, plugins) + if need_auth: + authenticator = display_ops.pick_authenticator(config, req_auth, plugins) + logger.debug("Selected authenticator %s and installer %s" % (authenticator, installer)) + + if need_inst and not installer: + diagnose_configurator_problem("installer", req_inst) + if need_auth and not authenticator: + diagnose_configurator_problem("authenticator", req_auth) - if installer is None or authenticator is None: - #print installer, authenticator - raise ConfiguratorError, "Configurator could not be determined" return installer, authenticator @@ -349,7 +382,7 @@ def pick_configurator(args, config, plugins, verb): def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-locals """Obtain a certificate and install.""" try: - installer, authenticator = pick_configurator(args, config, plugins, "run") + installer, authenticator = choose_configurator_plugins(args, config, plugins, "run") except ConfiguratorError, e: return e.message @@ -679,8 +712,10 @@ def create_parser(plugins, args): None, "-t", "--text", dest="text_mode", action="store_true", help="Use the text output instead of the curses UI.") helpful.add(None, "-m", "--email", help=config_help("email")) - helpful.add(None, "--apache", help="Obtain and install certs using Apache") - helpful.add(None, "--nginx", help="Obtain and install certs using Nginx") + helpful.add(None, "--apache", action="store_true", + help="Obtain and install certs using Apache") + helpful.add(None, "--nginx", action="store_true", + help="Obtain and install certs using Nginx") # positional arg shadows --domains, instead of appending, and # --domains is useful, because it can be stored in config #for subparser in parser_run, parser_auth, parser_install: From 3d6ecc114b5cf11c29ed96a23655153f864079d4 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 16 Oct 2015 10:41:05 -0700 Subject: [PATCH 04/92] lintmonster --- letsencrypt/cli.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index af0f58378..f8675b3b4 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -304,14 +304,15 @@ def _auth_from_domains(le_client, config, domains, plugins): return lineage -class ConfiguratorError(TypeError): +class ConfiguratorError(TypeError): # pylint: disable=missing-docstring pass def set_configurator(previously, now): """Setting configurators multiple ways is okay, as long as they all agree""" if previously: if previously != now: - raise ConfiguratorError, "Too many flags setting configurators/installers/authenticators %s -> %s" % (`previously`,`now`) + msg = "Too many flags setting configurators/installers/authenticators %s -> %s" + raise ConfiguratorError, msg % (`previously`, `now`) return now def diagnose_configurator_problem(cfg_type, requested): @@ -330,7 +331,7 @@ def diagnose_configurator_problem(cfg_type, requested): msg = "The " + requested + " plugin is not working; there may be problems " msg += "with your existing configuration" raise ConfiguratorError, msg - raise ConfiguratorError, "Installer could not be determined or is not installed" + raise ConfiguratorError, cfg_type + " could not be determined or is not installed" @@ -342,7 +343,7 @@ def choose_configurator_plugins(args, config, plugins, verb): if verb == "auth": need_auth = True if verb == "install": - need_install = True + need_inst = True # Which plugins did the user request? req_inst = req_auth = args.configurator @@ -355,7 +356,7 @@ def choose_configurator_plugins(args, config, plugins, verb): req_inst = set_configurator(req_inst, "apache") req_auth = set_configurator(req_auth, "apache") - logger.debug("Requested authenticator %s and installer %s" % (req_auth, req_inst)) + logger.debug("Requested authenticator %s and installer %s", req_auth, req_inst) # Try to meet the user's request and/or ask them to pick plugins if verb == "run" and req_auth == req_inst: @@ -367,7 +368,7 @@ def choose_configurator_plugins(args, config, plugins, verb): installer = display_ops.pick_installer(config, req_inst, plugins) if need_auth: authenticator = display_ops.pick_authenticator(config, req_auth, plugins) - logger.debug("Selected authenticator %s and installer %s" % (authenticator, installer)) + logger.debug("Selected authenticator %s and installer %s", authenticator, installer) if need_inst and not installer: diagnose_configurator_problem("installer", req_inst) From dcf8ea4e97e63fafe0e9ddf75ca6e72a69a0b040 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 16 Oct 2015 17:38:17 -0700 Subject: [PATCH 05/92] Logic for setting configurators assumed they were really being set (They might not be) --- letsencrypt/cli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index f8675b3b4..77480f69f 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -309,6 +309,9 @@ class ConfiguratorError(TypeError): # pylint: disable=missing-docstring def set_configurator(previously, now): """Setting configurators multiple ways is okay, as long as they all agree""" + if now is None: + # we're not actually setting anything + return previously if previously: if previously != now: msg = "Too many flags setting configurators/installers/authenticators %s -> %s" From 36432e35f728d28d4f772f3f139558325bf80545 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 16 Oct 2015 18:19:22 -0700 Subject: [PATCH 06/92] keep cover happy --- letsencrypt/tests/cli_test.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index f690e77f9..42faad245 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -15,6 +15,7 @@ from letsencrypt import errors from letsencrypt.tests import renewer_test from letsencrypt.tests import test_util +from letsencrypt.plugins import disco CSR = test_util.vector_path('csr.der') @@ -75,7 +76,6 @@ class CLITest(unittest.TestCase): output.truncate(0) self.assertRaises(SystemExit, self._call_stdout, ['-h', 'nginx']) out = output.getvalue() - from letsencrypt.plugins import disco if "nginx" in disco.PluginsRegistry.find_all(): # may be false while building distributions without plugins self.assertTrue("--nginx-ctl" in out) @@ -93,6 +93,20 @@ class CLITest(unittest.TestCase): from letsencrypt import cli self.assertTrue(cli.USAGE in out) + def test_configurator_selection(self): + output = StringIO.StringIO() + plugins = disco.PluginsRegistry.find_all() + if "apache" in plugins: + + with mock.patch('letsencrypt.cli.sys.stdout', new=output): + self.assertRaises(SystemExit, self._call_stdout, + ['--agree-eula', '--apache', '--authenticator', 'standalone']) + #import sys + #sys.stderr.write(repr(self._call_stdout(['--agree-eula', '--apache', '--authenticator', 'standalone']))) + out = output.getvalue() + self.assertTrue("Too many flags setting" in out) + # TODO add tests with a broken plugin, a missing plugin, etc + def test_rollback(self): _, _, _, client = self._call(['rollback']) self.assertEqual(1, client.rollback.call_count) From 57e15c52d7895431740b4b868c614f62ef519e16 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 16 Oct 2015 18:28:38 -0700 Subject: [PATCH 07/92] Test actually works now :) --- letsencrypt/tests/cli_test.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 42faad245..830a73956 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -97,15 +97,11 @@ class CLITest(unittest.TestCase): output = StringIO.StringIO() plugins = disco.PluginsRegistry.find_all() if "apache" in plugins: - - with mock.patch('letsencrypt.cli.sys.stdout', new=output): - self.assertRaises(SystemExit, self._call_stdout, - ['--agree-eula', '--apache', '--authenticator', 'standalone']) - #import sys - #sys.stderr.write(repr(self._call_stdout(['--agree-eula', '--apache', '--authenticator', 'standalone']))) - out = output.getvalue() - self.assertTrue("Too many flags setting" in out) - # TODO add tests with a broken plugin, a missing plugin, etc + from letsencrypt import cli + args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] + ret, _, _, _ = self._call(args) + self.assertTrue("Too many flags setting" in ret) + # TODO add tests with a broken plugin, a missing plugin, etc def test_rollback(self): _, _, _, client = self._call(['rollback']) From f0faf91b822cac464f2e963d8160f6ebb36de032 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Fri, 16 Oct 2015 18:34:57 -0700 Subject: [PATCH 08/92] lint! --- letsencrypt/tests/cli_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 830a73956..4ab912ad4 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -94,10 +94,8 @@ class CLITest(unittest.TestCase): self.assertTrue(cli.USAGE in out) def test_configurator_selection(self): - output = StringIO.StringIO() plugins = disco.PluginsRegistry.find_all() if "apache" in plugins: - from letsencrypt import cli args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] ret, _, _, _ = self._call(args) self.assertTrue("Too many flags setting" in ret) From 28a837ada74ae6103dd8a8f38346581b88a71319 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sat, 17 Oct 2015 12:04:39 +0000 Subject: [PATCH 09/92] Use PEM for Account.id generation (fixes #1012). This is a breaking change, already existing /etc/letsencrypt/accounts will cause the client raise errors.AccountStorageError ("Account ids mismatch ..."). Simple fix: start over by `rm -rf /etc/letsencrypt`. In a long run it's a better solution that bumping to `cryptography>=0.9`... --- letsencrypt/account.py | 2 +- letsencrypt/tests/account_test.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/letsencrypt/account.py b/letsencrypt/account.py index 81d31b831..c41b10c4a 100644 --- a/letsencrypt/account.py +++ b/letsencrypt/account.py @@ -56,7 +56,7 @@ class Account(object): # pylint: disable=too-few-public-methods self.id = hashlib.md5( self.key.key.public_key().public_bytes( - encoding=serialization.Encoding.DER, + encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) ).hexdigest() # Implementation note: Email? Multiple accounts can have the diff --git a/letsencrypt/tests/account_test.py b/letsencrypt/tests/account_test.py index 4e2fdb122..9452a74f3 100644 --- a/letsencrypt/tests/account_test.py +++ b/letsencrypt/tests/account_test.py @@ -45,16 +45,16 @@ class AccountTest(unittest.TestCase): def test_id(self): self.assertEqual( - self.acc.id, "2ba35a3bdf380ed76a5ac9e740568395") + self.acc.id, "bca5889f66457d5b62fbba7b25f9ab6f") def test_slug(self): self.assertEqual( - self.acc.slug, "test.letsencrypt.org@2015-07-04T14:04:10Z (2ba3)") + self.acc.slug, "test.letsencrypt.org@2015-07-04T14:04:10Z (bca5)") def test_repr(self): self.assertEqual( repr(self.acc), - "") + "") class ReportNewAccountTest(unittest.TestCase): From 8d4f414e09c0c1adb89c1b802932ad67775f423a Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 12:47:05 -0700 Subject: [PATCH 10/92] Move ConfiguratorError to errors.py --- letsencrypt/cli.py | 13 +++++-------- letsencrypt/errors.py | 2 ++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 9a0dd9108..a1fe27e08 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -304,9 +304,6 @@ def _auth_from_domains(le_client, config, domains, plugins): return lineage -class ConfiguratorError(TypeError): # pylint: disable=missing-docstring - pass - def set_configurator(previously, now): """Setting configurators multiple ways is okay, as long as they all agree""" if now is None: @@ -315,7 +312,7 @@ def set_configurator(previously, now): if previously: if previously != now: msg = "Too many flags setting configurators/installers/authenticators %s -> %s" - raise ConfiguratorError, msg % (`previously`, `now`) + raise errors.ConfiguratorError, msg % (`previously`, `now`) return now def diagnose_configurator_problem(cfg_type, requested): @@ -329,12 +326,12 @@ def diagnose_configurator_problem(cfg_type, requested): if requested: if requested not in plugins: msg = "The requested " + requested + " plugin does not appear to be installed" - raise ConfiguratorError, msg + raise errors.ConfiguratorError, msg else: msg = "The " + requested + " plugin is not working; there may be problems " msg += "with your existing configuration" - raise ConfiguratorError, msg - raise ConfiguratorError, cfg_type + " could not be determined or is not installed" + raise errors.ConfiguratorError, msg + raise errors.ConfiguratorError, cfg_type + " could not be determined or is not installed" @@ -387,7 +384,7 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo """Obtain a certificate and install.""" try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "run") - except ConfiguratorError, e: + except errors.ConfiguratorError, e: return e.message domains = _find_domains(args, installer) diff --git a/letsencrypt/errors.py b/letsencrypt/errors.py index ba0601d29..def8fc20d 100644 --- a/letsencrypt/errors.py +++ b/letsencrypt/errors.py @@ -24,6 +24,8 @@ class SubprocessError(Error): class CertStorageError(Error): """Generic `.CertStorage` error.""" +class ConfiguratorError(Error): + """A problem with plugin/configurator selection or setup""" # Auth Handler Errors class AuthorizationError(Error): From f7bfb5ba8d6e3cf47e2ce5c11fd49aedfecbd912 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 12:54:56 -0700 Subject: [PATCH 11/92] Sphinxify docstrings, plugins plumbing --- letsencrypt/cli.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index a1fe27e08..4f619b03a 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -315,13 +315,16 @@ def set_configurator(previously, now): raise errors.ConfiguratorError, msg % (`previously`, `now`) return now -def diagnose_configurator_problem(cfg_type, requested): +def diagnose_configurator_problem(cfg_type, requested, plugins): """ Raise the most helpful error message about a plugin being unavailable - @cfg_type -- "installer" or "authenticator" - @requested -- which plugin the user wanted + + :param string cfg_type: either "installer" or "authenticator" + :param string requested: the plugin that was requested + :param PluginRegistry plugins: available plugins + + :raises error.ConfiguratorError if there was a problem """ - plugins = plugins_disco.PluginsRegistry.find_all() if requested: if requested not in plugins: @@ -336,7 +339,11 @@ def diagnose_configurator_problem(cfg_type, requested): def choose_configurator_plugins(args, config, plugins, verb): - """Figure out which configurator we're going to use""" + """ + Figure out which configurator we're going to use + + :raises error.ConfiguratorError if there was a problem + """ # Which plugins do we need? need_inst = need_auth = (verb == "run") @@ -371,9 +378,9 @@ def choose_configurator_plugins(args, config, plugins, verb): logger.debug("Selected authenticator %s and installer %s", authenticator, installer) if need_inst and not installer: - diagnose_configurator_problem("installer", req_inst) + diagnose_configurator_problem("installer", req_inst, plugins) if need_auth and not authenticator: - diagnose_configurator_problem("authenticator", req_auth) + diagnose_configurator_problem("authenticator", req_auth, plugins) return installer, authenticator From a841c4fc5d2b1a8b1b308e556de1ecc12400ebe3 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 13:13:00 -0700 Subject: [PATCH 12/92] More nits --- letsencrypt/cli.py | 7 +++---- letsencrypt/tests/cli_test.py | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 4f619b03a..289b14554 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -328,11 +328,11 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): if requested: if requested not in plugins: - msg = "The requested " + requested + " plugin does not appear to be installed" + msg = "The requested {0} plugin does not appear to be installed".format(requested) raise errors.ConfiguratorError, msg else: - msg = "The " + requested + " plugin is not working; there may be problems " - msg += "with your existing configuration" + msg = ("The {0} plugin is not working; there may be problems with " + "your existing configuration").format(requested) raise errors.ConfiguratorError, msg raise errors.ConfiguratorError, cfg_type + " could not be determined or is not installed" @@ -362,7 +362,6 @@ def choose_configurator_plugins(args, config, plugins, verb): if args.apache: req_inst = set_configurator(req_inst, "apache") req_auth = set_configurator(req_auth, "apache") - logger.debug("Requested authenticator %s and installer %s", req_auth, req_inst) # Try to meet the user's request and/or ask them to pick plugins diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 4ab912ad4..d31bfaff4 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -13,9 +13,10 @@ from letsencrypt import account from letsencrypt import configuration from letsencrypt import errors +from letsencrypt.plugins import disco + from letsencrypt.tests import renewer_test from letsencrypt.tests import test_util -from letsencrypt.plugins import disco CSR = test_util.vector_path('csr.der') From 0c2fe1002d7ee40235bde68056105f53094158fe Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Sat, 17 Oct 2015 13:36:29 -0700 Subject: [PATCH 13/92] Added notAfter and notBefore to crypto_util --- letsencrypt/crypto_util.py | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/letsencrypt/crypto_util.py b/letsencrypt/crypto_util.py index 61aa8b0db..337bcd14c 100644 --- a/letsencrypt/crypto_util.py +++ b/letsencrypt/crypto_util.py @@ -8,6 +8,7 @@ import logging import os import OpenSSL +import pyrfc3339 import zope.component from acme import crypto_util as acme_crypto_util @@ -276,3 +277,48 @@ def dump_pyopenssl_chain(chain, filetype=OpenSSL.crypto.FILETYPE_PEM): # assumes that OpenSSL.crypto.dump_certificate includes ending # newline character return "".join(_dump_cert(cert) for cert in chain) + + +def notBefore(cert_path): + """When does the cert at cert_path start being valid? + + :param str cert_path: path to a cert in PEM format + + :returns: the notBefore value from the cert at cert_path + :rtype: :class:`datetime.datetime` + + """ + return _notAfterBefore(cert_path, OpenSSL.crypto.X509.get_notBefore) + + +def notAfter(cert_path): + """When does the cert at cert_path stop being valid? + + :param str cert_path: path to a cert in PEM format + + :returns: the notAfter value from the cert at cert_path + :rtype: :class:`datetime.datetime` + + """ + return _notAfterBefore(cert_path, OpenSSL.crypto.X509.get_notAfter) + + +def _notAfterBefore(cert_path, method): + """Internal helper function for finding notbefore/notafter. + + :param str cert_path: path to a cert in PEM format + :param function method: one of ``OpenSSL.crypto.X509.get_notBefore`` + or ``OpenSSL.crypto.X509.get_notAfter`` + + :returns: the notBefore value from the cert at cert_path + :rtype: :class:`datetime.datetime` + + """ + with open(cert_path) as f: + x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, + f.read()) + timestamp = method(x509) + reformatted_timestamp = [timestamp[0:4], "-", timestamp[4:6], "-", + timestamp[6:8], "T", timestamp[8:10], ":", + timestamp[10:12], ":", timestamp[12:]] + return pyrfc3339.parse("".join(reformatted_timestamp)) From 7c92db095f9f828fb4085c0d18236cc808461ed1 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 13:43:49 -0700 Subject: [PATCH 14/92] Use new selection logic for "auth" Also: why was auth selecting installers? --- letsencrypt/cli.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 289b14554..6e65d4c0d 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -419,15 +419,14 @@ def auth(args, config, plugins): # supplied, check if CSR matches given domains? return "--domains and --csr are mutually exclusive" - authenticator = display_ops.pick_authenticator( - config, args.authenticator, plugins) - if authenticator is None: - return "Authenticator could not be determined" + try: + installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") + except errors.ConfiguratorError, e: + return e.message - if args.installer is not None: - installer = display_ops.pick_installer(config, args.installer, plugins) - else: - installer = None + installer = None # we're doing auth! + if args.installer: + return "Specifying an installer doesn't make sense in auth mode!" # TODO: Handle errors from _init_le_client? le_client = _init_le_client(args, config, authenticator, installer) From 2adcce6b3d6386a087ef76462d8a0c221ceb30b5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Sat, 17 Oct 2015 13:53:22 -0700 Subject: [PATCH 15/92] Delete code in storage.py --- letsencrypt/storage.py | 48 ++----------------------------- letsencrypt/tests/renewer_test.py | 21 -------------- 2 files changed, 3 insertions(+), 66 deletions(-) diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index 8a0f4829e..12411ffb4 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -5,10 +5,8 @@ import re import time import configobj -import OpenSSL import parsedatetime import pytz -import pyrfc3339 from letsencrypt import constants from letsencrypt import crypto_util @@ -381,47 +379,6 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes for kind in ALL_FOUR: self._update_link_to(kind, version) - def _notafterbefore(self, method, version): - """Internal helper function for finding notbefore/notafter.""" - if version is None: - target = self.current_target("cert") - else: - target = self.version("cert", version) - pem = open(target).read() - x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, - pem) - i = method(x509) - return pyrfc3339.parse(i[0:4] + "-" + i[4:6] + "-" + i[6:8] + "T" + - i[8:10] + ":" + i[10:12] + ":" + i[12:]) - - def notbefore(self, version=None): - """When does the specified cert version start being valid? - - (If no version is specified, use the current version.) - - :param int version: the desired version number - - :returns: the notBefore value from the specified cert version in - this lineage - :rtype: :class:`datetime.datetime` - - """ - return self._notafterbefore(lambda x509: x509.get_notBefore(), version) - - def notafter(self, version=None): - """When does the specified cert version stop being valid? - - (If no version is specified, use the current version.) - - :param int version: the desired version number - - :returns: the notAfter value from the specified cert version in - this lineage - :rtype: :class:`datetime.datetime` - - """ - return self._notafterbefore(lambda x509: x509.get_notAfter(), version) - def names(self, version=None): """What are the subject names of this certificate? @@ -470,7 +427,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes interval = self.configuration.get("deploy_before_expiry", "5 days") autodeploy_interval = parse_time_interval(interval) - expiry = self.notafter() + expiry = crypto_util.notAfter(self.current_target("cert")) now = datetime.datetime.utcnow().replace(tzinfo=pytz.UTC) remaining = expiry - now if remaining < autodeploy_interval: @@ -537,7 +494,8 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes # Renewals on the basis of expiry time interval = self.configuration.get("renew_before_expiry", "10 days") autorenew_interval = parse_time_interval(interval) - expiry = self.notafter(self.latest_common_version()) + expiry = crypto_util.notAfter(self.version( + "cert", self.latest_common_version())) now = datetime.datetime.utcnow().replace(tzinfo=pytz.UTC) remaining = expiry - now if remaining < autorenew_interval: diff --git a/letsencrypt/tests/renewer_test.py b/letsencrypt/tests/renewer_test.py index 1e434b79e..297bbd1b1 100644 --- a/letsencrypt/tests/renewer_test.py +++ b/letsencrypt/tests/renewer_test.py @@ -7,7 +7,6 @@ import unittest import configobj import mock -import pytz from letsencrypt import configuration from letsencrypt import errors @@ -349,26 +348,6 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertEqual(self.test_rc.names(12), ["example.com", "www.example.com"]) - def _test_notafterbefore(self, function, timestamp): - test_cert = test_util.load_vector("cert.pem") - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert12.pem"), self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write(test_cert) - desired_time = datetime.datetime.utcfromtimestamp(timestamp) - desired_time = desired_time.replace(tzinfo=pytz.UTC) - for result in (function(), function(12)): - self.assertEqual(result, desired_time) - self.assertEqual(result.utcoffset(), datetime.timedelta(0)) - - def test_notbefore(self): - self._test_notafterbefore(self.test_rc.notbefore, 1418337285) - # 2014-12-11 22:34:45+00:00 = Unix time 1418337285 - - def test_notafter(self): - self._test_notafterbefore(self.test_rc.notafter, 1418942085) - # 2014-12-18 22:34:45+00:00 = Unix time 1418942085 - @mock.patch("letsencrypt.storage.datetime") def test_time_interval_judgments(self, mock_datetime): """Test should_autodeploy() and should_autorenew() on the basis From b4b6d64ac6f15b3b7a759f0cf4c056d4bd05a2e2 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Sat, 17 Oct 2015 13:54:24 -0700 Subject: [PATCH 16/92] Removed lies about return value --- letsencrypt/crypto_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/crypto_util.py b/letsencrypt/crypto_util.py index 337bcd14c..f897ec852 100644 --- a/letsencrypt/crypto_util.py +++ b/letsencrypt/crypto_util.py @@ -310,7 +310,7 @@ def _notAfterBefore(cert_path, method): :param function method: one of ``OpenSSL.crypto.X509.get_notBefore`` or ``OpenSSL.crypto.X509.get_notAfter`` - :returns: the notBefore value from the cert at cert_path + :returns: the notBefore or notAfter value from the cert at cert_path :rtype: :class:`datetime.datetime` """ From f4f6b98f31f43094778018ecebf9b3db3a61ba13 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 13:57:52 -0700 Subject: [PATCH 17/92] Use new plugin selection logic for install --- letsencrypt/cli.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 6e65d4c0d..6287611a5 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -334,8 +334,8 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): msg = ("The {0} plugin is not working; there may be problems with " "your existing configuration").format(requested) raise errors.ConfiguratorError, msg - raise errors.ConfiguratorError, cfg_type + " could not be determined or is not installed" - + raise errors.ConfiguratorError, + "{0} could not be determined or is not installed".format(cfg_type) def choose_configurator_plugins(args, config, plugins, verb): @@ -349,8 +349,14 @@ def choose_configurator_plugins(args, config, plugins, verb): need_inst = need_auth = (verb == "run") if verb == "auth": need_auth = True + if args.installer: + msg = "Specifying an installer doesn't make sense in auth mode" + raise errors.ConfiguratorError, msg if verb == "install": need_inst = True + if args.authenticator: + msg = "Specifying an authenticator doesn't make sense in install mode" + raise errors.ConfiguratorError, msg # Which plugins did the user request? req_inst = req_auth = args.configurator @@ -421,13 +427,10 @@ def auth(args, config, plugins): try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") + installer = None # we're doing auth! except errors.ConfiguratorError, e: return e.message - installer = None # we're doing auth! - if args.installer: - return "Specifying an installer doesn't make sense in auth mode!" - # TODO: Handle errors from _init_le_client? le_client = _init_le_client(args, config, authenticator, installer) @@ -446,9 +449,16 @@ def auth(args, config, plugins): def install(args, config, plugins): """Install a previously obtained cert in a server.""" # XXX: Update for renewer/RenewableCert - installer = display_ops.pick_installer(config, args.installer, plugins) - if installer is None: - return "Installer could not be determined" + + try: + installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") + authenticator = None # we're doing install! + except errors.ConfiguratorError, e: + return e.message + + if args.authenticator: + return "Specifying an authenticator doesn't make sense in install mode!" + domains = _find_domains(args, installer) le_client = _init_le_client( args, config, authenticator=None, installer=installer) From c89e192ee70cc709f5d45829d86d5257052d3cbd Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 14:01:54 -0700 Subject: [PATCH 18/92] Concision is beautiful --- letsencrypt/cli.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 6287611a5..aff70cca3 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -29,7 +29,6 @@ from letsencrypt import configuration from letsencrypt import constants from letsencrypt import client from letsencrypt import crypto_util -from letsencrypt import errors from letsencrypt import interfaces from letsencrypt import le_util from letsencrypt import log @@ -38,6 +37,7 @@ from letsencrypt import storage from letsencrypt.display import util as display_util from letsencrypt.display import ops as display_ops +from letsencrypt.errors import Error, ConfiguratorError, CertStorageError from letsencrypt.plugins import disco as plugins_disco @@ -92,7 +92,7 @@ def _find_domains(args, installer): domains = args.domains if not domains: - raise errors.Error("Please specify --domains, or --installer that " + raise Error("Please specify --domains, or --installer that " "will help in domain names autodiscovery") return domains @@ -145,9 +145,9 @@ def _determine_account(args, config): try: acc, acme = client.register( config, account_storage, tos_cb=_tos_cb) - except errors.Error as error: + except Error as error: logger.debug(error, exc_info=True) - raise errors.Error( + raise Error( "Unable to register an account with ACME server") args.account = acc.id @@ -185,7 +185,7 @@ def _find_duplicative_certs(domains, config, renew_config): rc_config.filename = full_path candidate_lineage = storage.RenewableCert( rc_config, config_opts=None, cli_config=cli_config) - except (configobj.ConfigObjError, errors.CertStorageError, IOError): + except (configobj.ConfigObjError, CertStorageError, IOError): logger.warning("Renewal configuration file %s is broken. " "Skipping.", full_path) continue @@ -257,7 +257,7 @@ def _treat_as_renewal(config, domains): br=os.linesep ), reporter_util.HIGH_PRIORITY) - raise errors.Error( + raise Error( "User did not use proper CLI and would like " "to reinvoke the client.") @@ -298,7 +298,7 @@ def _auth_from_domains(le_client, config, domains, plugins): # TREAT AS NEW REQUEST lineage = le_client.obtain_and_enroll_certificate(domains, plugins) if not lineage: - raise errors.Error("Certificate could not be obtained") + raise Error("Certificate could not be obtained") _report_new_cert(lineage.cert) @@ -312,7 +312,7 @@ def set_configurator(previously, now): if previously: if previously != now: msg = "Too many flags setting configurators/installers/authenticators %s -> %s" - raise errors.ConfiguratorError, msg % (`previously`, `now`) + raise ConfiguratorError, msg % (`previously`, `now`) return now def diagnose_configurator_problem(cfg_type, requested, plugins): @@ -329,13 +329,12 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): if requested: if requested not in plugins: msg = "The requested {0} plugin does not appear to be installed".format(requested) - raise errors.ConfiguratorError, msg + raise ConfiguratorError, msg else: msg = ("The {0} plugin is not working; there may be problems with " "your existing configuration").format(requested) - raise errors.ConfiguratorError, msg - raise errors.ConfiguratorError, - "{0} could not be determined or is not installed".format(cfg_type) + raise ConfiguratorError, msg + raise ConfiguratorError, "{0} could not be determined or is not installed".format(cfg_type) def choose_configurator_plugins(args, config, plugins, verb): @@ -350,13 +349,12 @@ def choose_configurator_plugins(args, config, plugins, verb): if verb == "auth": need_auth = True if args.installer: - msg = "Specifying an installer doesn't make sense in auth mode" - raise errors.ConfiguratorError, msg + raise ConfiguratorError, "Specifying an installer doesn't make sense in auth mode" if verb == "install": need_inst = True if args.authenticator: msg = "Specifying an authenticator doesn't make sense in install mode" - raise errors.ConfiguratorError, msg + raise ConfiguratorError, msg # Which plugins did the user request? req_inst = req_auth = args.configurator @@ -396,7 +394,7 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo """Obtain a certificate and install.""" try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "run") - except errors.ConfiguratorError, e: + except ConfiguratorError, e: return e.message domains = _find_domains(args, installer) @@ -428,7 +426,7 @@ def auth(args, config, plugins): try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") installer = None # we're doing auth! - except errors.ConfiguratorError, e: + except ConfiguratorError, e: return e.message # TODO: Handle errors from _init_le_client? @@ -453,7 +451,7 @@ def install(args, config, plugins): try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") authenticator = None # we're doing install! - except errors.ConfiguratorError, e: + except ConfiguratorError, e: return e.message if args.authenticator: @@ -992,7 +990,7 @@ def _handle_exception(exc_type, exc_value, trace, args): sys.exit("".join( traceback.format_exception(exc_type, exc_value, trace))) - if issubclass(exc_type, errors.Error): + if issubclass(exc_type, Error): sys.exit(exc_value) else: # Tell the user a bit about what happened, without overwhelming @@ -1056,7 +1054,7 @@ def main(cli_args=sys.argv[1:]): eula = pkg_resources.resource_string("letsencrypt", "EULA") if not zope.component.getUtility(interfaces.IDisplay).yesno( eula, "Agree", "Cancel"): - raise errors.Error("Must agree to TOS") + raise Error("Must agree to TOS") if not os.geteuid() == 0: logger.warning( From 82499edbd6b82ee4b9e8b5adfc9979f18c5d1975 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Sat, 17 Oct 2015 14:16:24 -0700 Subject: [PATCH 19/92] Added tests to crypto_util --- letsencrypt/tests/crypto_util_test.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/letsencrypt/tests/crypto_util_test.py b/letsencrypt/tests/crypto_util_test.py index 2e04c748a..f0b8c0e4d 100644 --- a/letsencrypt/tests/crypto_util_test.py +++ b/letsencrypt/tests/crypto_util_test.py @@ -15,6 +15,7 @@ from letsencrypt.tests import test_util RSA256_KEY = test_util.load_vector('rsa256_key.pem') RSA512_KEY = test_util.load_vector('rsa512_key.pem') +CERT_PATH = test_util.vector_path('cert.pem') CERT = test_util.load_vector('cert.pem') SAN_CERT = test_util.load_vector('cert-san.pem') @@ -232,5 +233,23 @@ class CertLoaderTest(unittest.TestCase): pyopenssl_load_certificate(bad_cert_data) +class NotBeforeTest(unittest.TestCase): + """Tests for letsencrypt.crypto_util.notBefore""" + + def test_notBefore(self): + from letsencrypt.crypto_util import notBefore + self.assertEqual(notBefore(CERT_PATH).isoformat(), + '2014-12-11T22:34:45+00:00') + + +class NotAfterTest(unittest.TestCase): + """Tests for letsencrypt.crypto_util.notAfter""" + + def test_notAfter(self): + from letsencrypt.crypto_util import notAfter + self.assertEqual(notAfter(CERT_PATH).isoformat(), + '2014-12-18T22:34:45+00:00') + + if __name__ == '__main__': unittest.main() # pragma: no cover From 4996e9b678478fd26198febaa9b536d5f694c261 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sat, 17 Oct 2015 14:28:38 -0700 Subject: [PATCH 20/92] Installers are actually useful in auth mode --- letsencrypt/cli.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index aff70cca3..cdad7d99c 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -348,8 +348,6 @@ def choose_configurator_plugins(args, config, plugins, verb): need_inst = need_auth = (verb == "run") if verb == "auth": need_auth = True - if args.installer: - raise ConfiguratorError, "Specifying an installer doesn't make sense in auth mode" if verb == "install": need_inst = True if args.authenticator: @@ -424,8 +422,8 @@ def auth(args, config, plugins): return "--domains and --csr are mutually exclusive" try: + # installers are used in auth mode to determine domain names installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") - installer = None # we're doing auth! except ConfiguratorError, e: return e.message @@ -449,8 +447,7 @@ def install(args, config, plugins): # XXX: Update for renewer/RenewableCert try: - installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") - authenticator = None # we're doing install! + installer, _ = choose_configurator_plugins(args, config, plugins, "auth") except ConfiguratorError, e: return e.message @@ -903,7 +900,7 @@ def _plugins_parsing(helpful, plugins): helpful.add( "plugins", "-a", "--authenticator", help="Authenticator plugin name.") helpful.add( - "plugins", "-i", "--installer", help="Installer plugin name.") + "plugins", "-i", "--installer", help="Installer plugin name (also used to find domains).") helpful.add( "plugins", "--configurator", help="Name of the plugin that is " "both an authenticator and an installer. Should not be used " From 975ffc51033fc15bf627f92046b6b543fdb17d36 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Sat, 17 Oct 2015 14:48:24 -0700 Subject: [PATCH 21/92] Updated cli and cli_test --- letsencrypt/cli.py | 12 +++++------- letsencrypt/tests/cli_test.py | 29 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 477cb653f..39fc721c7 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -269,9 +269,13 @@ def _treat_as_renewal(config, domains): def _report_new_cert(cert_path): """Reports the creation of a new certificate to the user.""" + expiry = crypto_util.notAfter(cert_path).date() reporter_util = zope.component.getUtility(interfaces.IReporter) reporter_util.add_message("Congratulations! Your certificate has been " - "saved at {0}.".format(cert_path), + "saved at {0} and will expire on {1}. To obtain " + "a new version of the certificate in the " + "future, simply run Let's Encrypt again.".format( + cert_path, expiry), reporter_util.MEDIUM_PRIORITY) @@ -301,12 +305,6 @@ def _auth_from_domains(le_client, config, domains, plugins): raise errors.Error("Certificate could not be obtained") _report_new_cert(lineage.cert) - reporter_util = zope.component.getUtility(interfaces.IReporter) - reporter_util.add_message( - "Your certificate will expire on {0}. To obtain a new version of the " - "certificate in the future, simply run this client again.".format( - lineage.notafter().date()), - reporter_util.MEDIUM_PRIORITY) return lineage diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index a3efd9d40..548e23972 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -119,18 +119,23 @@ class CLITest(unittest.TestCase): ret, _, _, _ = self._call(['-a', 'bad_auth', 'auth']) self.assertEqual(ret, 'Authenticator could not be determined') + @mock.patch('letsencrypt.crypto_util.notAfter') @mock.patch('letsencrypt.cli.zope.component.getUtility') - def test_auth_new_request_success(self, mock_get_utility): + def test_auth_new_request_success(self, mock_get_utility, mock_notAfter): cert_path = '/etc/letsencrypt/live/foo.bar' + date = '1970-01-01' + mock_notAfter().date.return_value = date + mock_lineage = mock.MagicMock(cert=cert_path) mock_client = mock.MagicMock() mock_client.obtain_and_enroll_certificate.return_value = mock_lineage self._auth_new_request_common(mock_client) self.assertEqual( mock_client.obtain_and_enroll_certificate.call_count, 1) - msg = mock_get_utility().add_message.call_args_list[0][0][0] - self.assertTrue(cert_path in msg) - self.assertEqual(mock_get_utility().add_message.call_count, 2) + self.assertTrue( + cert_path in mock_get_utility().add_message.call_args[0][0]) + self.assertTrue( + date in mock_get_utility().add_message.call_args[0][0]) def test_auth_new_request_failure(self): mock_client = mock.MagicMock() @@ -150,6 +155,7 @@ class CLITest(unittest.TestCase): @mock.patch('letsencrypt.cli._init_le_client') def test_auth_renewal(self, mock_init, mock_renewal, mock_get_utility): cert_path = '/etc/letsencrypt/live/foo.bar' + mock_lineage = mock.MagicMock(cert=cert_path) mock_cert = mock.MagicMock(body='body') mock_key = mock.MagicMock(pem='pem_key') @@ -165,19 +171,24 @@ class CLITest(unittest.TestCase): self.assertEqual(mock_lineage.save_successor.call_count, 1) mock_lineage.update_all_links_to.assert_called_once_with( mock_lineage.latest_common_version()) - msg = mock_get_utility().add_message.call_args_list[0][0][0] - self.assertTrue(cert_path in msg) - self.assertEqual(mock_get_utility().add_message.call_count, 2) + self.assertTrue( + cert_path in mock_get_utility().add_message.call_args[0][0]) + @mock.patch('letsencrypt.crypto_util.notAfter') @mock.patch('letsencrypt.cli.display_ops.pick_installer') @mock.patch('letsencrypt.cli.zope.component.getUtility') @mock.patch('letsencrypt.cli._init_le_client') - def test_auth_csr(self, mock_init, mock_get_utility, mock_pick_installer): + def test_auth_csr(self, mock_init, mock_get_utility, + mock_pick_installer, mock_notAfter): cert_path = '/etc/letsencrypt/live/foo.bar' + date = '1970-01-01' + mock_notAfter().date.return_value = date + mock_client = mock.MagicMock() mock_client.obtain_certificate_from_csr.return_value = ('certr', 'chain') mock_init.return_value = mock_client + installer = 'installer' self._call( ['-a', 'standalone', '-i', installer, 'auth', '--csr', CSR, @@ -187,6 +198,8 @@ class CLITest(unittest.TestCase): 'certr', 'chain', cert_path, '/') self.assertTrue( cert_path in mock_get_utility().add_message.call_args[0][0]) + self.assertTrue( + date in mock_get_utility().add_message.call_args[0][0]) @mock.patch('letsencrypt.cli.sys') def test_handle_exception(self, mock_sys): From e2e7acf4c4ff5c74a7f0098245b6702b38abaaf7 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Sat, 17 Oct 2015 16:30:54 -0700 Subject: [PATCH 22/92] Use actual CSR path --- letsencrypt/cli.py | 4 ++-- letsencrypt/tests/cli_test.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 39fc721c7..da6bbeeab 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -377,9 +377,9 @@ def auth(args, config, plugins): if args.csr is not None: certr, chain = le_client.obtain_certificate_from_csr(le_util.CSR( file=args.csr[0], data=args.csr[1], form="der")) - le_client.save_certificate( + cert_path, _ = le_client.save_certificate( certr, chain, args.cert_path, args.chain_path) - _report_new_cert(args.cert_path) + _report_new_cert(cert_path) else: domains = _find_domains(args, installer) _auth_from_domains(le_client, config, domains, plugins) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 548e23972..870359824 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -187,6 +187,7 @@ class CLITest(unittest.TestCase): mock_client = mock.MagicMock() mock_client.obtain_certificate_from_csr.return_value = ('certr', 'chain') + mock_client.save_certificate.return_value = cert_path, None mock_init.return_value = mock_client installer = 'installer' From d6345a47c51cd94f56fc6c6a3d04634cfdefc823 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sun, 18 Oct 2015 02:34:24 -0700 Subject: [PATCH 23/92] Fix some bugs & immprove test cases --- letsencrypt/cli.py | 3 ++- letsencrypt/tests/cli_test.py | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index cdad7d99c..4cbfb8a2a 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -367,12 +367,13 @@ def choose_configurator_plugins(args, config, plugins, verb): logger.debug("Requested authenticator %s and installer %s", req_auth, req_inst) # Try to meet the user's request and/or ask them to pick plugins + authenticator = installer = None if verb == "run" and req_auth == req_inst: # Unless the user has explicitly asked for different auth/install, # only consider offering a single choice authenticator = installer = display_ops.pick_configurator(config, req_inst, plugins) else: - if need_inst: + if need_inst or req_inst: installer = display_ops.pick_installer(config, req_inst, plugins) if need_auth: authenticator = display_ops.pick_authenticator(config, req_auth, plugins) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index d31bfaff4..ccc57cb8c 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -96,11 +96,12 @@ class CLITest(unittest.TestCase): def test_configurator_selection(self): plugins = disco.PluginsRegistry.find_all() + args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] + ret, _, _, _ = self._call(args) if "apache" in plugins: - args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] - ret, _, _, _ = self._call(args) self.assertTrue("Too many flags setting" in ret) - # TODO add tests with a broken plugin, a missing plugin, etc + else: + self.assertTrue("The requested apache plugin does not" in ret) def test_rollback(self): _, _, _, client = self._call(['rollback']) @@ -126,7 +127,7 @@ class CLITest(unittest.TestCase): self.assertEqual(ret, '--domains and --csr are mutually exclusive') ret, _, _, _ = self._call(['-a', 'bad_auth', 'auth']) - self.assertEqual(ret, 'Authenticator could not be determined') + self.assertEqual(ret, 'The requested bad_auth plugin does not appear to be installed') @mock.patch('letsencrypt.cli.zope.component.getUtility') def test_auth_new_request_success(self, mock_get_utility): From 995c1dfb83eba73d3dbffe22adbdeb801aa520b3 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sun, 18 Oct 2015 11:05:46 -0700 Subject: [PATCH 24/92] More sphinxiness, more clarity --- letsencrypt/cli.py | 2 +- letsencrypt/tests/cli_test.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 4cbfb8a2a..4c4692675 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -323,7 +323,7 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): :param string requested: the plugin that was requested :param PluginRegistry plugins: available plugins - :raises error.ConfiguratorError if there was a problem + :raises error.ConfiguratorError: if there was a problem """ if requested: diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index ccc57cb8c..ee847b234 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -98,10 +98,13 @@ class CLITest(unittest.TestCase): plugins = disco.PluginsRegistry.find_all() args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] ret, _, _, _ = self._call(args) + # TODO replace these cases with .mockery to test both paths regardless + # of what's actually installed if "apache" in plugins: self.assertTrue("Too many flags setting" in ret) else: - self.assertTrue("The requested apache plugin does not" in ret) + self.assertTrue("The requested apache plugin does not appear" in ret) + def test_rollback(self): _, _, _, client = self._call(['rollback']) From 63f4f113608cde95e2ab190ea2e3063655a965e5 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Sun, 18 Oct 2015 11:05:58 -0700 Subject: [PATCH 25/92] Test "install --nginx" w/ misconfiguration --- letsencrypt/tests/cli_test.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index ee847b234..d246f1a9a 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -105,6 +105,15 @@ class CLITest(unittest.TestCase): else: self.assertTrue("The requested apache plugin does not appear" in ret) + # Sending nginx a non-existent conf dir will simulate misconfiguration + args = ["install", "--nginx", "--cert-path", "/tmp/blah", "--key-path", "/tmp/blah", + "--nginx-server-root", "/nonexistent/thing"] + ret, _, _, _ = self._call(args) + + if "nginx" in plugins: + self.assertTrue("The nginx plugin is not working" in ret) + else: + self.assertTrue("The requested nginx plugin does not appear" in ret) def test_rollback(self): _, _, _, client = self._call(['rollback']) From bb17863ebe44d8ddbdbf48d7d266787fb59e0a6e Mon Sep 17 00:00:00 2001 From: schumaml Date: Mon, 19 Oct 2015 10:19:21 +0200 Subject: [PATCH 26/92] Adjusted Docker user guide link --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 0a781431a..5e7852a12 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -85,4 +85,4 @@ and follow the instructions. Your new cert will be available in ``/etc/letsencrypt/certs``. .. _Docker: https://docker.com -.. _`install Docker`: https://docs.docker.com/docker/userguide/ +.. _`install Docker`: https://docs.docker.com/userguide/ From e05073c33eebd377f2ce76478bc4d8a28fef78ca Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 10:37:39 -0700 Subject: [PATCH 27/92] debugging --- letsencrypt/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 4c4692675..047d2ae15 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -394,6 +394,7 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "run") except ConfiguratorError, e: + logger.warn("Exiting with message {0}".format(e.message)) return e.message domains = _find_domains(args, installer) From 6e69e584027087bde10b739b3d8bcee7b3b04b59 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 12:03:11 -0700 Subject: [PATCH 28/92] Make more tests run regardless of local plugin state --- letsencrypt/cli.py | 32 ++++++++++++++++++-------------- letsencrypt/errors.py | 5 ++--- letsencrypt/tests/cli_test.py | 30 ++++++++++++++++-------------- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 047d2ae15..2883acd1c 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -37,7 +37,7 @@ from letsencrypt import storage from letsencrypt.display import util as display_util from letsencrypt.display import ops as display_ops -from letsencrypt.errors import Error, ConfiguratorError, CertStorageError +from letsencrypt.errors import Error, PluginSelectionError, CertStorageError from letsencrypt.plugins import disco as plugins_disco @@ -312,7 +312,7 @@ def set_configurator(previously, now): if previously: if previously != now: msg = "Too many flags setting configurators/installers/authenticators %s -> %s" - raise ConfiguratorError, msg % (`previously`, `now`) + raise PluginSelectionError, msg % (`previously`, `now`) return now def diagnose_configurator_problem(cfg_type, requested, plugins): @@ -323,25 +323,25 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): :param string requested: the plugin that was requested :param PluginRegistry plugins: available plugins - :raises error.ConfiguratorError: if there was a problem + :raises error.PluginSelectionError: if there was a problem """ if requested: if requested not in plugins: msg = "The requested {0} plugin does not appear to be installed".format(requested) - raise ConfiguratorError, msg + raise PluginSelectionError, msg else: msg = ("The {0} plugin is not working; there may be problems with " "your existing configuration").format(requested) - raise ConfiguratorError, msg - raise ConfiguratorError, "{0} could not be determined or is not installed".format(cfg_type) + raise PluginSelectionError, msg + raise PluginSelectionError, "{0} could not be determined or is not installed".format(cfg_type) def choose_configurator_plugins(args, config, plugins, verb): """ Figure out which configurator we're going to use - :raises error.ConfiguratorError if there was a problem + :raises error.PluginSelectionError if there was a problem """ # Which plugins do we need? @@ -352,7 +352,7 @@ def choose_configurator_plugins(args, config, plugins, verb): need_inst = True if args.authenticator: msg = "Specifying an authenticator doesn't make sense in install mode" - raise ConfiguratorError, msg + raise PluginSelectionError, msg # Which plugins did the user request? req_inst = req_auth = args.configurator @@ -393,8 +393,7 @@ def run(args, config, plugins): # pylint: disable=too-many-branches,too-many-lo """Obtain a certificate and install.""" try: installer, authenticator = choose_configurator_plugins(args, config, plugins, "run") - except ConfiguratorError, e: - logger.warn("Exiting with message {0}".format(e.message)) + except PluginSelectionError, e: return e.message domains = _find_domains(args, installer) @@ -426,7 +425,7 @@ def auth(args, config, plugins): try: # installers are used in auth mode to determine domain names installer, authenticator = choose_configurator_plugins(args, config, plugins, "auth") - except ConfiguratorError, e: + except PluginSelectionError, e: return e.message # TODO: Handle errors from _init_le_client? @@ -450,7 +449,7 @@ def install(args, config, plugins): try: installer, _ = choose_configurator_plugins(args, config, plugins, "auth") - except ConfiguratorError, e: + except PluginSelectionError, e: return e.message if args.authenticator: @@ -1007,6 +1006,8 @@ def _handle_exception(exc_type, exc_value, trace, args): traceback.format_exception(exc_type, exc_value, trace))) +# this copy of plugins can be mocked out +plugins_testable = plugins_disco.PluginsRegistry.find_all() def main(cli_args=sys.argv[1:]): """Command line argument parsing and main script execution.""" sys.excepthook = functools.partial(_handle_exception, args=None) @@ -1066,8 +1067,11 @@ def main(cli_args=sys.argv[1:]): # "{0}Root is required to run letsencrypt. Please use sudo.{0}" # .format(os.linesep)) - return args.func(args, config, plugins) + return args.func(args, config, plugins_testable) if __name__ == "__main__": - sys.exit(main()) # pragma: no cover + err_string = main() + if err_string: + logger.warn("Exiting with message %s", err_string) + sys.exit(err_string) # pragma: no cover diff --git a/letsencrypt/errors.py b/letsencrypt/errors.py index def8fc20d..fd737bc81 100644 --- a/letsencrypt/errors.py +++ b/letsencrypt/errors.py @@ -24,9 +24,6 @@ class SubprocessError(Error): class CertStorageError(Error): """Generic `.CertStorage` error.""" -class ConfiguratorError(Error): - """A problem with plugin/configurator selection or setup""" - # Auth Handler Errors class AuthorizationError(Error): """Authorization error.""" @@ -67,6 +64,8 @@ class DvsniError(DvAuthError): class PluginError(Error): """Let's Encrypt Plugin error.""" +class PluginSelectionError(Error): + """A problem with plugin/configurator selection or setup""" class NoInstallationError(PluginError): """Let's Encrypt No Installation error.""" diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index d246f1a9a..e42ca3e92 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -95,24 +95,26 @@ class CLITest(unittest.TestCase): self.assertTrue(cli.USAGE in out) def test_configurator_selection(self): - plugins = disco.PluginsRegistry.find_all() + real_plugins = disco.PluginsRegistry.find_all() args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] - ret, _, _, _ = self._call(args) - # TODO replace these cases with .mockery to test both paths regardless - # of what's actually installed - if "apache" in plugins: + + with mock.patch('letsencrypt.cli.plugins_testable') as plugins: + plugins.return_value = {"apache": True, "nginx": True} + ret, _, _, _ = self._call(args) self.assertTrue("Too many flags setting" in ret) - else: - self.assertTrue("The requested apache plugin does not appear" in ret) - # Sending nginx a non-existent conf dir will simulate misconfiguration - args = ["install", "--nginx", "--cert-path", "/tmp/blah", "--key-path", "/tmp/blah", - "--nginx-server-root", "/nonexistent/thing"] - ret, _, _, _ = self._call(args) - - if "nginx" in plugins: + if "nginx" in real_plugins: + # Sending nginx a non-existent conf dir will simulate misconfiguration + # (we can only do that if letsencrypt-nginx is actually present) + args = ["install", "--nginx", "--cert-path", "/tmp/blah", "--key-path", "/tmp/blah", + "--nginx-server-root", "/nonexistent/thing"] + ret, _, _, _ = self._call(args) self.assertTrue("The nginx plugin is not working" in ret) - else: + + # But we can pretend that nginx is uninstalled, even if it is + with mock.patch('letsencrypt.cli.plugins_testable') as plugins: + plugins.return_value = {} + ret, _, _, _ = self._call(args) self.assertTrue("The requested nginx plugin does not appear" in ret) def test_rollback(self): From 39ae9bdf43c27aaa16886bfd63db965415a4718c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 12:06:39 -0700 Subject: [PATCH 29/92] Document a somewhat cryptic function --- letsencrypt/cli.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 2883acd1c..dad486c2c 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -305,7 +305,12 @@ def _auth_from_domains(le_client, config, domains, plugins): return lineage def set_configurator(previously, now): - """Setting configurators multiple ways is okay, as long as they all agree""" + """ + Setting configurators multiple ways is okay, as long as they all agree + + :param string previously: previously identified request for the installer/authenticator + :param string requested: the request currently being processed + """ if now is None: # we're not actually setting anything return previously From 26e703779468dedc556d0fc67dac079cd68d8306 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 12:15:11 -0700 Subject: [PATCH 30/92] Fix a mock type error --- letsencrypt/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index dad486c2c..4368db7f7 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1012,7 +1012,7 @@ def _handle_exception(exc_type, exc_value, trace, args): # this copy of plugins can be mocked out -plugins_testable = plugins_disco.PluginsRegistry.find_all() +plugins_testable = plugins_disco.PluginsRegistry.find_all def main(cli_args=sys.argv[1:]): """Command line argument parsing and main script execution.""" sys.excepthook = functools.partial(_handle_exception, args=None) @@ -1072,7 +1072,7 @@ def main(cli_args=sys.argv[1:]): # "{0}Root is required to run letsencrypt. Please use sudo.{0}" # .format(os.linesep)) - return args.func(args, config, plugins_testable) + return args.func(args, config, plugins_testable()) if __name__ == "__main__": From 98c74ddd14cbcd227934d92f0e508f46df12b94c Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 19 Oct 2015 12:26:59 -0700 Subject: [PATCH 31/92] Removed no_simple_http_tls --- letsencrypt/plugins/webroot.py | 3 +-- letsencrypt/tests/renewer_test.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/letsencrypt/plugins/webroot.py b/letsencrypt/plugins/webroot.py index ed8991bc5..f11325f57 100644 --- a/letsencrypt/plugins/webroot.py +++ b/letsencrypt/plugins/webroot.py @@ -72,8 +72,7 @@ to serve all files under specified web root ({0}).""" return os.path.join(self.full_root, achall.chall.encode("token")) def _perform_single(self, achall): - response, validation = achall.gen_response_and_validation( - tls=(not self.config.no_simple_http_tls)) + response, validation = achall.gen_response_and_validation(tls=False) path = self._path_for_achall(achall) logger.debug("Attempting to save validation to %s", path) with open(path, "w") as validation_file: diff --git a/letsencrypt/tests/renewer_test.py b/letsencrypt/tests/renewer_test.py index 1e434b79e..3077be25d 100644 --- a/letsencrypt/tests/renewer_test.py +++ b/letsencrypt/tests/renewer_test.py @@ -48,7 +48,6 @@ class BaseRenewableCertTest(unittest.TestCase): config_dir=self.tempdir, work_dir=self.tempdir, logs_dir=self.tempdir, - no_simple_http_tls=False, ) ) From eac513d73b204c6f31c807b53851f4d65ece0497 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 17:21:47 -0700 Subject: [PATCH 32/92] Offer more specific help if no installer is present Fixes: #896 --- letsencrypt/cli.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 4368db7f7..5f4f8102a 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -334,12 +334,21 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): if requested: if requested not in plugins: msg = "The requested {0} plugin does not appear to be installed".format(requested) - raise PluginSelectionError, msg else: msg = ("The {0} plugin is not working; there may be problems with " "your existing configuration").format(requested) - raise PluginSelectionError, msg - raise PluginSelectionError, "{0} could not be determined or is not installed".format(cfg_type) + elif cfg_type == "installer": + if os.path.exists("/etc/debian_version"): + # Debian... installers are at least possible + msg = ('No installers seem to be present and working on your system; ' + 'fix that or try running letsencrypt with the "auth" command') + else: + # XXX update this logic as we make progress on #788 and nginx support + msg = ('No installers are available on your OS yet; try running ' + '"letsencrypt-auto auth" to get a cert you can install manually') + else: + msg = "{0} could not be determined or is not installed".format(cfg_type) + raise PluginSelectionError, msg def choose_configurator_plugins(args, config, plugins, verb): From 484e8ef6fece5d94f7d98bc955cd12b79dff13ad Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:11:05 -0700 Subject: [PATCH 33/92] Not trying to mock out plugins just yet --- letsencrypt/tests/cli_test.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index e42ca3e92..93947c2f1 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -103,20 +103,15 @@ class CLITest(unittest.TestCase): ret, _, _, _ = self._call(args) self.assertTrue("Too many flags setting" in ret) + args = ["install", "--nginx", "--cert-path", "/tmp/blah", "--key-path", "/tmp/blah", + "--nginx-server-root", "/nonexistent/thing", "-d", + "example.com", "--debug"] if "nginx" in real_plugins: # Sending nginx a non-existent conf dir will simulate misconfiguration # (we can only do that if letsencrypt-nginx is actually present) - args = ["install", "--nginx", "--cert-path", "/tmp/blah", "--key-path", "/tmp/blah", - "--nginx-server-root", "/nonexistent/thing"] ret, _, _, _ = self._call(args) self.assertTrue("The nginx plugin is not working" in ret) - # But we can pretend that nginx is uninstalled, even if it is - with mock.patch('letsencrypt.cli.plugins_testable') as plugins: - plugins.return_value = {} - ret, _, _, _ = self._call(args) - self.assertTrue("The requested nginx plugin does not appear" in ret) - def test_rollback(self): _, _, _, client = self._call(['rollback']) self.assertEqual(1, client.rollback.call_count) From a643289662fd90e029760788dd6916d360be178f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 19 Oct 2015 19:13:48 -0700 Subject: [PATCH 34/92] Updated todos --- letsencrypt/auth_handler.py | 6 ++---- letsencrypt/client.py | 2 -- letsencrypt/renewer.py | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/letsencrypt/auth_handler.py b/letsencrypt/auth_handler.py index b27a569f6..2da053f8c 100644 --- a/letsencrypt/auth_handler.py +++ b/letsencrypt/auth_handler.py @@ -153,10 +153,8 @@ class AuthHandler(object): """ active_achalls = [] for achall, resp in itertools.izip(achalls, resps): - # XXX: make sure that all achalls, including those - # corresponding to None or False returned from - # Authenticator are removed from the queue and thus avoid - # infinite loop + # This line needs to be outside of the if block below to + # ensure failed challenges are cleaned up correctly active_achalls.append(achall) # Don't send challenges for None and False authenticator responses diff --git a/letsencrypt/client.py b/letsencrypt/client.py index 3e32ab015..732bdcf03 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -329,8 +329,6 @@ class Client(object): with error_handler.ErrorHandler(self.installer.recovery_routine): for dom in domains: - # TODO: Provide a fullchain reference for installers like - # nginx that want it self.installer.deploy_cert( domain=dom, cert_path=os.path.abspath(cert_path), key_path=os.path.abspath(privkey_path), diff --git a/letsencrypt/renewer.py b/letsencrypt/renewer.py index 1efc2920b..33492f344 100644 --- a/letsencrypt/renewer.py +++ b/letsencrypt/renewer.py @@ -95,7 +95,7 @@ def renew(cert, old_version): sans = crypto_util.get_sans_from_cert(f.read()) new_certr, new_chain, new_key, _ = le_client.obtain_certificate(sans) if new_chain: - # XXX: Assumes that there was no key change. We need logic + # XXX: Assumes that there was a key change. We need logic # for figuring out whether there was or not. Probably # best is to have obtain_certificate return None for # new_key if the old key is to be used (since save_successor @@ -180,7 +180,6 @@ def main(config=None, cli_args=sys.argv[1:]): rc_config = configobj.ConfigObj(cli_config.renewer_config_file) rc_config.merge(configobj.ConfigObj( os.path.join(cli_config.renewal_configs_dir, i))) - # TODO: this is a dirty hack! rc_config.filename = os.path.join(cli_config.renewal_configs_dir, i) try: # TODO: Before trying to initialize the RenewableCert object, From eeeb66e58a3f8c475cf5f95c5b9aa04a371dd581 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:15:11 -0700 Subject: [PATCH 35/92] document -d domain Closes: #285 #787 we may want to implement the other thing soon, but for now documenting what we have --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 5f4f8102a..6af6a45c6 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -50,7 +50,7 @@ logger = logging.getLogger(__name__) # This is the stub to include in help generated by argparse SHORT_USAGE = """ - letsencrypt [SUBCOMMAND] [options] [domains] + letsencrypt [SUBCOMMAND] [options] [-d domain] [-d domain] ... The Let's Encrypt agent can obtain and install HTTPS/TLS/SSL certificates. By default, it will attempt to use a webserver both for obtaining and installing From 6460a3b50ef3b14f5ad2d2fc98a0ae683e131c6f Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:27:36 -0700 Subject: [PATCH 36/92] Dial back the "authenticator doesn't make sense in install mode" message Since it was breaking integration tests --- letsencrypt/cli.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 6af6a45c6..dd0623757 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -365,8 +365,7 @@ def choose_configurator_plugins(args, config, plugins, verb): if verb == "install": need_inst = True if args.authenticator: - msg = "Specifying an authenticator doesn't make sense in install mode" - raise PluginSelectionError, msg + logger.warn("Specifying an authenticator doesn't make sense in install mode") # Which plugins did the user request? req_inst = req_auth = args.configurator From 72589bcae3506d71d5f85250edbb3ef9756a9828 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:31:09 -0700 Subject: [PATCH 37/92] Lint --- letsencrypt/cli.py | 1 - 1 file changed, 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index dd0623757..fb564c630 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -307,7 +307,6 @@ def _auth_from_domains(le_client, config, domains, plugins): def set_configurator(previously, now): """ Setting configurators multiple ways is okay, as long as they all agree - :param string previously: previously identified request for the installer/authenticator :param string requested: the request currently being processed """ From e384a1fe2857e53abfabbe03175ed52b7af61575 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:35:53 -0700 Subject: [PATCH 38/92] Catch some excessive policing of installers --- letsencrypt/cli.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index fb564c630..f0e1d3a4d 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -464,9 +464,6 @@ def install(args, config, plugins): except PluginSelectionError, e: return e.message - if args.authenticator: - return "Specifying an authenticator doesn't make sense in install mode!" - domains = _find_domains(args, installer) le_client = _init_le_client( args, config, authenticator=None, installer=installer) From 51ed2b681f87b1eb29088dd48718a54f401e4855 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:41:37 -0700 Subject: [PATCH 39/92] We're not mocking out plugins So we don't need infrastructure for it --- letsencrypt/cli.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index f0e1d3a4d..54168ef87 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1015,8 +1015,6 @@ def _handle_exception(exc_type, exc_value, trace, args): traceback.format_exception(exc_type, exc_value, trace))) -# this copy of plugins can be mocked out -plugins_testable = plugins_disco.PluginsRegistry.find_all def main(cli_args=sys.argv[1:]): """Command line argument parsing and main script execution.""" sys.excepthook = functools.partial(_handle_exception, args=None) @@ -1076,7 +1074,7 @@ def main(cli_args=sys.argv[1:]): # "{0}Root is required to run letsencrypt. Please use sudo.{0}" # .format(os.linesep)) - return args.func(args, config, plugins_testable()) + return args.func(args, config, plugins) if __name__ == "__main__": From 363dffd8a644ae42bed9689b133ceda42f78f034 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Mon, 19 Oct 2015 19:51:02 -0700 Subject: [PATCH 40/92] Comment out a test that requires slightly doubtful infrastructure --- letsencrypt/tests/cli_test.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 93947c2f1..2b8be5b1e 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -98,10 +98,13 @@ class CLITest(unittest.TestCase): real_plugins = disco.PluginsRegistry.find_all() args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] - with mock.patch('letsencrypt.cli.plugins_testable') as plugins: - plugins.return_value = {"apache": True, "nginx": True} - ret, _, _, _ = self._call(args) - self.assertTrue("Too many flags setting" in ret) + # This needed two calls to find_all(), which we're avoiding for now + # because of possible side effects: + # https://github.com/letsencrypt/letsencrypt/commit/51ed2b681f87b1eb29088dd48718a54f401e4855 + #with mock.patch('letsencrypt.cli.plugins_testable') as plugins: + # plugins.return_value = {"apache": True, "nginx": True} + # ret, _, _, _ = self._call(args) + # self.assertTrue("Too many flags setting" in ret) args = ["install", "--nginx", "--cert-path", "/tmp/blah", "--key-path", "/tmp/blah", "--nginx-server-root", "/nonexistent/thing", "-d", From adcb0052a16f8268b29ca550916563f4c84e1f79 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 00:30:44 -0700 Subject: [PATCH 41/92] Implement --standalone as specified. Closes #1036 --- letsencrypt/cli.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 208d629b5..1ece941ae 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -382,6 +382,8 @@ def choose_configurator_plugins(args, config, plugins, verb): if args.apache: req_inst = set_configurator(req_inst, "apache") req_auth = set_configurator(req_auth, "apache") + if args.standalone: + req_auth = set_configurator(req_auth, "standalone") logger.debug("Requested authenticator %s and installer %s", req_auth, req_inst) # Try to meet the user's request and/or ask them to pick plugins @@ -636,8 +638,12 @@ class HelpfulArgumentParser(object): self.verb = token return reordered - self.verb = "run" - return args + ["run"] + if "--standalone" in args and "--installer" not in args and "-i" not in args: + self.verb = "auth" + return args + ["auth"] + else: + self.verb = "run" + return args + ["run"] def prescan_for_flag(self, flag, possible_arguments): """Checks cli input for flags. @@ -744,6 +750,8 @@ def create_parser(plugins, args): help="Obtain and install certs using Apache") helpful.add(None, "--nginx", action="store_true", help="Obtain and install certs using Nginx") + helpful.add(None, "--standalone`", action="store_true", + help='Obtain certs using a "standalone" webserver on port 443.') # positional arg shadows --domains, instead of appending, and # --domains is useful, because it can be stored in config #for subparser in parser_run, parser_auth, parser_install: From c61efc0c7694f1465bdc2ff313300b53877adcee Mon Sep 17 00:00:00 2001 From: Giovanni Toraldo Date: Tue, 20 Oct 2015 10:00:58 +0200 Subject: [PATCH 42/92] Fix docker run command in using.rst --- docs/using.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using.rst b/docs/using.rst index 5e7852a12..879ea49c4 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -76,7 +76,7 @@ server that the domain your requesting a cert for resolves to, .. code-block:: shell - sudo docker auth -it --rm -p 443:443 --name letsencrypt \ + sudo docker run -it --rm -p 443:443 --name letsencrypt \ -v "/etc/letsencrypt:/etc/letsencrypt" \ -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \ quay.io/letsencrypt/letsencrypt:latest auth From 54a738492b67ac6764499783b1448aa3b058ae73 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 01:22:04 -0700 Subject: [PATCH 43/92] Fix typo --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 1ece941ae..eba5e8685 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -750,7 +750,7 @@ def create_parser(plugins, args): help="Obtain and install certs using Apache") helpful.add(None, "--nginx", action="store_true", help="Obtain and install certs using Nginx") - helpful.add(None, "--standalone`", action="store_true", + helpful.add(None, "--standalone", action="store_true", help='Obtain certs using a "standalone" webserver on port 443.') # positional arg shadows --domains, instead of appending, and # --domains is useful, because it can be stored in config From 82e3620b5aa44d0607ad444581c38b405c14b8d7 Mon Sep 17 00:00:00 2001 From: Faerbit Date: Tue, 20 Oct 2015 14:28:52 +0200 Subject: [PATCH 44/92] Added needed flag to pacman invocation to only install packages that are not already installed. --- bootstrap/archlinux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/archlinux.sh b/bootstrap/archlinux.sh index 6de7c23d4..884262f0b 100755 --- a/bootstrap/archlinux.sh +++ b/bootstrap/archlinux.sh @@ -3,7 +3,7 @@ # "python-virtualenv" is Python3, but "python2-virtualenv" provides # only "virtualenv2" binary, not "virtualenv" necessary in # ./bootstrap/dev/_common_venv.sh -pacman -S \ +pacman -S --needed \ git \ python2 \ python-virtualenv \ From efe51e02becf50a686eb8d3ed9c9bc128850909a Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 10:34:31 -0700 Subject: [PATCH 45/92] Explain the --standalone change in defaults --- letsencrypt/cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index eba5e8685..b79ec7ae4 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -751,7 +751,8 @@ def create_parser(plugins, args): helpful.add(None, "--nginx", action="store_true", help="Obtain and install certs using Nginx") helpful.add(None, "--standalone", action="store_true", - help='Obtain certs using a "standalone" webserver on port 443.') + help=('Obtain certs using a "standalone" webserver. ' + 'Changes the default "run" command to "auth".') # positional arg shadows --domains, instead of appending, and # --domains is useful, because it can be stored in config #for subparser in parser_run, parser_auth, parser_install: From 2c4d4a81692fbd05320493c3cc0d19f05d75013a Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 10:35:17 -0700 Subject: [PATCH 46/92] "letsencrypt everything" is not yet implemented :/ --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index b79ec7ae4..237d1741c 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -60,7 +60,7 @@ the cert. """ # altogether USAGE = SHORT_USAGE + """Major SUBCOMMANDS are: - (default) everything Obtain & install a cert in your current webserver + (default) run Obtain & install a cert in your current webserver auth Authenticate & obtain cert, but do not install it install Install a previously obtained cert in a server revoke Revoke a previously obtained certificate From 719cbdb4884d9559fa95fb0ac3a61356cf927b0c Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 10:58:47 -0700 Subject: [PATCH 47/92] --apache etc should be documented in the "plugins" section --- letsencrypt/cli.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 237d1741c..fb6f74937 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -71,7 +71,8 @@ Choice of server for authentication/installation: --apache Use the Apache plugin for authentication & installation --nginx Use the Nginx plugin for authentication & installation - --standalone Run a standalone HTTPS server (for authentication only) + --standalone Run a standalone webserver (for authentication only, changes + the default command to "auth") OR: --authenticator standalone --installer nginx @@ -746,13 +747,6 @@ def create_parser(plugins, args): None, "-t", "--text", dest="text_mode", action="store_true", help="Use the text output instead of the curses UI.") helpful.add(None, "-m", "--email", help=config_help("email")) - helpful.add(None, "--apache", action="store_true", - help="Obtain and install certs using Apache") - helpful.add(None, "--nginx", action="store_true", - help="Obtain and install certs using Nginx") - helpful.add(None, "--standalone", action="store_true", - help=('Obtain certs using a "standalone" webserver. ' - 'Changes the default "run" command to "auth".') # positional arg shadows --domains, instead of appending, and # --domains is useful, because it can be stored in config #for subparser in parser_run, parser_auth, parser_install: @@ -865,7 +859,6 @@ def _create_subparsers(helpful): "--checkpoints", type=int, metavar="N", default=flag_default("rollback_checkpoints"), help="Revert configuration N number of checkpoints.") - helpful.add("plugins", "--init", action="store_true", help="Initialize plugins.") helpful.add("plugins", @@ -930,6 +923,15 @@ def _plugins_parsing(helpful, plugins): "plugins", "--configurator", help="Name of the plugin that is " "both an authenticator and an installer. Should not be used " "together with --authenticator or --installer.") + helpful.add("plugins", "--apache", action="store_true", + help="Obtain and install certs using Apache") + helpful.add("plugins", "--nginx", action="store_true", + help="Obtain and install certs using Nginx") + helpful.add("plugins", "--standalone", action="store_true", + help=('Obtain certs using a "standalone" webserver. ' + 'Changes the default "run" command to "auth".')) + + # things should not be reorder past/pre this comment: # plugins_group should be displayed in --help before plugin From aa4641b3b0cfaa387f38b51aa28f2559bd8c2ad0 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Tue, 20 Oct 2015 19:33:27 +0000 Subject: [PATCH 48/92] --agree-dev-preview `git grep -i eula` to the rescue --- DISCLAIMER | 1 + Dockerfile-dev | 2 +- EULA | 1 - MANIFEST.in | 2 +- examples/dev-cli.ini | 2 +- letsencrypt/{EULA => DISCLAIMER} | 0 letsencrypt/cli.py | 12 ++++++------ letsencrypt/tests/cli_test.py | 7 ++++--- tests/integration/_common.sh | 2 +- 9 files changed, 15 insertions(+), 14 deletions(-) create mode 120000 DISCLAIMER delete mode 120000 EULA rename letsencrypt/{EULA => DISCLAIMER} (100%) diff --git a/DISCLAIMER b/DISCLAIMER new file mode 120000 index 000000000..e580554ff --- /dev/null +++ b/DISCLAIMER @@ -0,0 +1 @@ +letsencrypt/DISCLAIMER \ No newline at end of file diff --git a/Dockerfile-dev b/Dockerfile-dev index 2fe1a818d..daa8e9af0 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -32,7 +32,7 @@ RUN /opt/letsencrypt/src/ubuntu.sh && \ # the above is not likely to change, so by putting it further up the # Dockerfile we make sure we cache as much as possible -COPY setup.py README.rst CHANGES.rst MANIFEST.in requirements.txt EULA linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/letsencrypt/src/ +COPY setup.py README.rst CHANGES.rst MANIFEST.in requirements.txt DISCLAIMER linter_plugin.py tox.cover.sh tox.ini pep8.travis.sh .pep8 .pylintrc /opt/letsencrypt/src/ # all above files are necessary for setup.py, however, package source # code directory has to be copied separately to a subdirectory... diff --git a/EULA b/EULA deleted file mode 120000 index 4a6da286e..000000000 --- a/EULA +++ /dev/null @@ -1 +0,0 @@ -letsencrypt/EULA \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index e421e0cd7..dfec1c3c9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,6 +4,6 @@ include CHANGES.rst include CONTRIBUTING.md include LICENSE.txt include linter_plugin.py -include letsencrypt/EULA +include letsencrypt/DISCLAIMER recursive-include docs * recursive-include letsencrypt/tests/testdata * diff --git a/examples/dev-cli.ini b/examples/dev-cli.ini index 085d4bfcc..2ea5d247d 100644 --- a/examples/dev-cli.ini +++ b/examples/dev-cli.ini @@ -8,7 +8,7 @@ email = foo@example.com domains = example.com text = True -agree-eula = True +agree-dev-preview = True agree-tos = True debug = True # Unfortunately, it's not possible to specify "verbose" multiple times diff --git a/letsencrypt/EULA b/letsencrypt/DISCLAIMER similarity index 100% rename from letsencrypt/EULA rename to letsencrypt/DISCLAIMER diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 280ddc751..9090839a6 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -763,8 +763,8 @@ def create_parser(plugins, args): help="Select renewal by default when domains are a superset of a " "a previously attained cert") helpful.add( - "automation", "--agree-eula", dest="eula", action="store_true", - help="Agree to the Let's Encrypt Developer Preview EULA") + "automation", "--agree-dev-preview", action="store_true", + help="Agree to the Let's Encrypt Developer Preview Disclaimer") helpful.add( "automation", "--agree-tos", dest="tos", action="store_true", help="Agree to the Let's Encrypt Subscriber Agreement") @@ -1060,11 +1060,11 @@ def main(cli_args=sys.argv[1:]): zope.component.provideUtility(report) atexit.register(report.atexit_print_messages) - # TODO: remove developer EULA prompt for the launch - if not config.eula: - eula = pkg_resources.resource_string("letsencrypt", "EULA") + # TODO: remove developer preview prompt for the launch + if not config.agree_dev_preview: + disclaimer = pkg_resources.resource_string("letsencrypt", "DISCLAIMER") if not zope.component.getUtility(interfaces.IDisplay).yesno( - eula, "Agree", "Cancel"): + disclaimer, "Agree", "Cancel"): raise Error("Must agree to TOS") if not os.geteuid() == 0: diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 4522ccbf4..9d9164f24 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -38,7 +38,7 @@ class CLITest(unittest.TestCase): from letsencrypt import cli args = ['--text', '--config-dir', self.config_dir, '--work-dir', self.work_dir, '--logs-dir', self.logs_dir, - '--agree-eula'] + args + '--agree-dev-preview'] + args with mock.patch('letsencrypt.cli.sys.stdout') as stdout: with mock.patch('letsencrypt.cli.sys.stderr') as stderr: with mock.patch('letsencrypt.cli.client') as client: @@ -53,7 +53,7 @@ class CLITest(unittest.TestCase): from letsencrypt import cli args = ['--text', '--config-dir', self.config_dir, '--work-dir', self.work_dir, '--logs-dir', self.logs_dir, - '--agree-eula'] + args + '--agree-dev-preview'] + args with mock.patch('letsencrypt.cli.sys.stderr') as stderr: with mock.patch('letsencrypt.cli.client') as client: ret = cli.main(args) @@ -96,7 +96,8 @@ class CLITest(unittest.TestCase): def test_configurator_selection(self): real_plugins = disco.PluginsRegistry.find_all() - args = ['--agree-eula', '--apache', '--authenticator', 'standalone'] + args = ['--agree-dev-preview', '--apache', + '--authenticator', 'standalone'] # This needed two calls to find_all(), which we're avoiding for now # because of possible side effects: diff --git a/tests/integration/_common.sh b/tests/integration/_common.sh index ab645f6d6..1dffaa4e3 100755 --- a/tests/integration/_common.sh +++ b/tests/integration/_common.sh @@ -20,7 +20,7 @@ letsencrypt_test () { --manual-test-mode \ $store_flags \ --text \ - --agree-eula \ + --agree-dev-preview \ --agree-tos \ --email "" \ --renew-by-default \ From 11495c582022558845446dcd89abf404bd3367bb Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Tue, 20 Oct 2015 20:16:12 +0000 Subject: [PATCH 49/92] Better logging for start/stop acme.standalone servers. --- acme/acme/standalone.py | 1 + letsencrypt/plugins/standalone.py | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/acme/acme/standalone.py b/acme/acme/standalone.py index 97e52fa9f..b0d8f08bd 100644 --- a/acme/acme/standalone.py +++ b/acme/acme/standalone.py @@ -55,6 +55,7 @@ class ACMEServerMixin: # pylint: disable=old-style-class def serve_forever2(self): """Serve forever, until other thread calls `shutdown2`.""" + logger.debug("Starting server at %s:%d...", *self.socket.getsockname()) while not self._stopped: self.handle_request() diff --git a/letsencrypt/plugins/standalone.py b/letsencrypt/plugins/standalone.py index 3ad823e9c..d548b2162 100644 --- a/letsencrypt/plugins/standalone.py +++ b/letsencrypt/plugins/standalone.py @@ -72,13 +72,12 @@ class ServerManager(object): except socket.error as error: raise errors.StandaloneBindError(error, port) - # if port == 0, then random free port on OS is taken - # pylint: disable=no-member - host, real_port = server.socket.getsockname() thread = threading.Thread(target=server.serve_forever2) - logger.debug("Starting server at %s:%d", host, real_port) thread.start() + # if port == 0, then random free port on OS is taken + # pylint: disable=no-member + _, real_port = server.socket.getsockname() self._instances[real_port] = self._Instance(server, thread) return server @@ -89,6 +88,8 @@ class ServerManager(object): """ instance = self._instances[port] + logger.debug("Stopping server at %s:%d...", + *instance.server.socket.getsockname()) instance.server.shutdown2() instance.thread.join() del self._instances[port] From aa67b83b382a1e8969cfc7438d9d4a042f925017 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Tue, 20 Oct 2015 20:22:38 +0000 Subject: [PATCH 50/92] debug log version --- letsencrypt/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 9090839a6..e10bed2e9 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -1042,6 +1042,7 @@ def main(cli_args=sys.argv[1:]): args.logs_dir, 0o700, os.geteuid(), "--strict-permissions" in cli_args) setup_logging(args, _cli_log_handler, logfile='letsencrypt.log') + logger.debug("letsencrypt version: %s", letsencrypt.__version__) # do not log `args`, as it contains sensitive data (e.g. revoke --key)! logger.debug("Arguments: %r", cli_args) logger.debug("Discovered plugins: %r", plugins) From 738684d43708ce43c7c5d3ae430aeceba09357b4 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 13:28:56 -0700 Subject: [PATCH 51/92] Revert to "run" as the default in all cases --- letsencrypt/cli.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index fb6f74937..e9c78437a 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -71,8 +71,8 @@ Choice of server for authentication/installation: --apache Use the Apache plugin for authentication & installation --nginx Use the Nginx plugin for authentication & installation - --standalone Run a standalone webserver (for authentication only, changes - the default command to "auth") + --standalone Run a standalone webserver for authentication + OR: --authenticator standalone --installer nginx @@ -639,12 +639,8 @@ class HelpfulArgumentParser(object): self.verb = token return reordered - if "--standalone" in args and "--installer" not in args and "-i" not in args: - self.verb = "auth" - return args + ["auth"] - else: - self.verb = "run" - return args + ["run"] + self.verb = "run" + return args + ["run"] def prescan_for_flag(self, flag, possible_arguments): """Checks cli input for flags. From e52922b11e0f519048a28e70db21610f81ac09df Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Tue, 20 Oct 2015 20:44:18 +0000 Subject: [PATCH 52/92] Fix getsockname usage with IPv6 --- acme/acme/standalone.py | 3 ++- acme/acme/standalone_test.py | 4 ++-- letsencrypt/plugins/standalone.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/acme/acme/standalone.py b/acme/acme/standalone.py index b0d8f08bd..49759bc07 100644 --- a/acme/acme/standalone.py +++ b/acme/acme/standalone.py @@ -55,7 +55,8 @@ class ACMEServerMixin: # pylint: disable=old-style-class def serve_forever2(self): """Serve forever, until other thread calls `shutdown2`.""" - logger.debug("Starting server at %s:%d...", *self.socket.getsockname()) + logger.debug("Starting server at %s:%d...", + *self.socket.getsockname()[:2]) while not self._stopped: self.handle_request() diff --git a/acme/acme/standalone_test.py b/acme/acme/standalone_test.py index 5dd6c2952..349581a3d 100644 --- a/acme/acme/standalone_test.py +++ b/acme/acme/standalone_test.py @@ -101,8 +101,8 @@ class DVSNIServerTest(unittest.TestCase): self.assertFalse(self.server._stopped) def test_dvsni(self): - cert = crypto_util.probe_sni( - b'localhost', *self.server.socket.getsockname()) + host, port = self.server.socket.getsockname()[:2] + cert = crypto_util.probe_sni(b'localhost', host=host, port=port) self.assertEqual(jose.ComparableX509(cert), jose.ComparableX509(self.certs[b'localhost'][1])) diff --git a/letsencrypt/plugins/standalone.py b/letsencrypt/plugins/standalone.py index d548b2162..d4dddc7f6 100644 --- a/letsencrypt/plugins/standalone.py +++ b/letsencrypt/plugins/standalone.py @@ -77,7 +77,7 @@ class ServerManager(object): # if port == 0, then random free port on OS is taken # pylint: disable=no-member - _, real_port = server.socket.getsockname() + real_port = server.socket.getsockname()[1] self._instances[real_port] = self._Instance(server, thread) return server @@ -89,7 +89,7 @@ class ServerManager(object): """ instance = self._instances[port] logger.debug("Stopping server at %s:%d...", - *instance.server.socket.getsockname()) + *instance.server.socket.getsockname()[:2]) instance.server.shutdown2() instance.thread.join() del self._instances[port] From dde3e685f00ee919177e8d1c9d395b4a885656fc Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 13:49:44 -0700 Subject: [PATCH 53/92] Fix stray --standalone help And a few layout nits --- letsencrypt/cli.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index e9c78437a..4303e158b 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -72,8 +72,7 @@ Choice of server for authentication/installation: --apache Use the Apache plugin for authentication & installation --nginx Use the Nginx plugin for authentication & installation --standalone Run a standalone webserver for authentication - - OR: +OR: --authenticator standalone --installer nginx More detailed help: @@ -924,10 +923,7 @@ def _plugins_parsing(helpful, plugins): helpful.add("plugins", "--nginx", action="store_true", help="Obtain and install certs using Nginx") helpful.add("plugins", "--standalone", action="store_true", - help=('Obtain certs using a "standalone" webserver. ' - 'Changes the default "run" command to "auth".')) - - + help=("Obtain certs using a "standalone" webserver.") # things should not be reorder past/pre this comment: # plugins_group should be displayed in --help before plugin From 05293cd59714be5a650381ca6bf335aa5fd10111 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 14:01:29 -0700 Subject: [PATCH 54/92] typosquash --- letsencrypt/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 4303e158b..54bdb7285 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -72,7 +72,7 @@ Choice of server for authentication/installation: --apache Use the Apache plugin for authentication & installation --nginx Use the Nginx plugin for authentication & installation --standalone Run a standalone webserver for authentication -OR: + OR: --authenticator standalone --installer nginx More detailed help: @@ -923,7 +923,7 @@ def _plugins_parsing(helpful, plugins): helpful.add("plugins", "--nginx", action="store_true", help="Obtain and install certs using Nginx") helpful.add("plugins", "--standalone", action="store_true", - help=("Obtain certs using a "standalone" webserver.") + help="Obtain certs using a "standalone" webserver.") # things should not be reorder past/pre this comment: # plugins_group should be displayed in --help before plugin From b01bf571ca4c8c34bcffa47f3c2bb70339f05429 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 14:02:34 -0700 Subject: [PATCH 55/92] more typos --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 54bdb7285..6e2f8749b 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -923,7 +923,7 @@ def _plugins_parsing(helpful, plugins): helpful.add("plugins", "--nginx", action="store_true", help="Obtain and install certs using Nginx") helpful.add("plugins", "--standalone", action="store_true", - help="Obtain certs using a "standalone" webserver.") + help='Obtain certs using a "standalone" webserver.') # things should not be reorder past/pre this comment: # plugins_group should be displayed in --help before plugin From e7182848a0b222f23b7c621b92830f881bcffa89 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Tue, 20 Oct 2015 14:04:58 -0700 Subject: [PATCH 56/92] Keep @bmw's sense of aesthetics happy :) --- letsencrypt/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 6e2f8749b..923fcbae7 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -72,7 +72,7 @@ Choice of server for authentication/installation: --apache Use the Apache plugin for authentication & installation --nginx Use the Nginx plugin for authentication & installation --standalone Run a standalone webserver for authentication - OR: + OR: --authenticator standalone --installer nginx More detailed help: From 424f4f08b950037b112cd186cfe11e38ecf4a162 Mon Sep 17 00:00:00 2001 From: Sharif Nassar Date: Tue, 20 Oct 2015 22:24:58 -0700 Subject: [PATCH 57/92] Make ./pep8.travis.sh run cleanly 98% whitespace. --- .../letsencrypt_apache/configurator.py | 2 +- .../configurators/apache/common.py | 2 +- .../letsencrypt_nginx/configurator.py | 2 +- .../tests/configurator_test.py | 33 ++++++++++--------- letsencrypt/cli.py | 10 +++--- letsencrypt/errors.py | 3 ++ 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/letsencrypt-apache/letsencrypt_apache/configurator.py b/letsencrypt-apache/letsencrypt_apache/configurator.py index de69af91c..d376fe4b6 100644 --- a/letsencrypt-apache/letsencrypt_apache/configurator.py +++ b/letsencrypt-apache/letsencrypt_apache/configurator.py @@ -165,7 +165,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): temp_install(self.mod_ssl_conf) def deploy_cert(self, domain, cert_path, key_path, - chain_path=None, fullchain_path=None): # pylint: disable=unused-argument + chain_path=None, fullchain_path=None): # pylint: disable=unused-argument """Deploys certificate to specified virtual host. Currently tries to find the last directives to deploy the cert in diff --git a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/common.py b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/common.py index 5f183b611..5fef8c47f 100644 --- a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/common.py +++ b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/common.py @@ -176,7 +176,7 @@ class Proxy(configurators_common.Proxy): return {"example.com"} def deploy_cert(self, domain, cert_path, key_path, chain_path=None, - fullchain_path=None): + fullchain_path=None): """Installs cert""" cert_path, key_path, chain_path = self.copy_certs_and_keys( cert_path, key_path, chain_path) diff --git a/letsencrypt-nginx/letsencrypt_nginx/configurator.py b/letsencrypt-nginx/letsencrypt_nginx/configurator.py index d1ab8f3d1..29e69e498 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/configurator.py +++ b/letsencrypt-nginx/letsencrypt_nginx/configurator.py @@ -119,7 +119,7 @@ class NginxConfigurator(common.Plugin): # Entry point in main.py for installing cert def deploy_cert(self, domain, cert_path, key_path, - chain_path, fullchain_path): + chain_path, fullchain_path): # pylint: disable=unused-argument """Deploys certificate to specified virtual host. diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py index 203f9920c..d8bdf8355 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/configurator_test.py @@ -112,11 +112,11 @@ class NginxConfiguratorTest(util.NginxTest): generated_conf = self.config.parser.parsed[example_conf] self.assertTrue(util.contains_at_depth(generated_conf, - ['ssl_stapling', 'on'], 2)) + ['ssl_stapling', 'on'], 2)) self.assertTrue(util.contains_at_depth(generated_conf, - ['ssl_stapling_verify', 'on'], 2)) + ['ssl_stapling_verify', 'on'], 2)) self.assertTrue(util.contains_at_depth(generated_conf, - ['ssl_trusted_certificate', 'example/chain.pem'], 2)) + ['ssl_trusted_certificate', 'example/chain.pem'], 2)) def test_deploy_cert(self): server_conf = self.config.parser.abs_path('server.conf') @@ -165,19 +165,20 @@ class NginxConfiguratorTest(util.NginxTest): self.assertEqual([['server_name', 'somename alias another.alias']], parsed_server_conf) self.assertTrue(util.contains_at_depth(parsed_nginx_conf, - [['server'], - [['include', self.config.parser.loc["ssl_options"]], - ['ssl_certificate_key', '/etc/nginx/key.pem'], - ['ssl_certificate', '/etc/nginx/fullchain.pem'], - ['error_log', error_log], - ['access_log', access_log], - ['listen', '5001 ssl'], - ['listen', '8000'], - ['listen', 'somename:8080'], - ['include', 'server.conf'], - [['location', '/'], - [['root', 'html'], ['index', 'index.html index.htm']]]]], - 2)) + [['server'], + [['include', self.config.parser.loc["ssl_options"]], + ['ssl_certificate_key', '/etc/nginx/key.pem'], + ['ssl_certificate', '/etc/nginx/fullchain.pem'], + ['error_log', error_log], + ['access_log', access_log], + ['listen', '5001 ssl'], + ['listen', '8000'], + ['listen', 'somename:8080'], + ['include', 'server.conf'], + [['location', '/'], + [['root', 'html'], + ['index', 'index.html index.htm']]]]], + 2)) def test_get_all_certs_keys(self): nginx_conf = self.config.parser.abs_path('nginx.conf') diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 3af8de2a2..1b396b0b8 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -93,7 +93,7 @@ def _find_domains(args, installer): if not domains: raise Error("Please specify --domains, or --installer that " - "will help in domain names autodiscovery") + "will help in domain names autodiscovery") return domains @@ -308,6 +308,7 @@ def _auth_from_domains(le_client, config, domains, plugins): return lineage + def set_configurator(previously, now): """ Setting configurators multiple ways is okay, as long as they all agree @@ -319,10 +320,11 @@ def set_configurator(previously, now): return previously if previously: if previously != now: - msg = "Too many flags setting configurators/installers/authenticators %s -> %s" - raise PluginSelectionError, msg % (`previously`, `now`) + msg = "Too many flags setting configurators/installers/authenticators {0} -> {1}" + raise PluginSelectionError(msg.format(repr(previously), repr(now))) return now + def diagnose_configurator_problem(cfg_type, requested, plugins): """ Raise the most helpful error message about a plugin being unavailable @@ -351,7 +353,7 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): '"letsencrypt-auto auth" to get a cert you can install manually') else: msg = "{0} could not be determined or is not installed".format(cfg_type) - raise PluginSelectionError, msg + raise PluginSelectionError(msg) def choose_configurator_plugins(args, config, plugins, verb): diff --git a/letsencrypt/errors.py b/letsencrypt/errors.py index 406b9c12c..3bfed4d23 100644 --- a/letsencrypt/errors.py +++ b/letsencrypt/errors.py @@ -24,6 +24,7 @@ class SubprocessError(Error): class CertStorageError(Error): """Generic `.CertStorage` error.""" + # Auth Handler Errors class AuthorizationError(Error): """Authorization error.""" @@ -64,9 +65,11 @@ class DvsniError(DvAuthError): class PluginError(Error): """Let's Encrypt Plugin error.""" + class PluginSelectionError(Error): """A problem with plugin/configurator selection or setup""" + class NoInstallationError(PluginError): """Let's Encrypt No Installation error.""" From 0e18395a1bda28977044ab60867ab2e97bfc9b87 Mon Sep 17 00:00:00 2001 From: Sharif Nassar Date: Tue, 20 Oct 2015 22:35:03 -0700 Subject: [PATCH 58/92] 100% coverage is the goal, so add a test --- letsencrypt/plugins/util_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/letsencrypt/plugins/util_test.py b/letsencrypt/plugins/util_test.py index 14cbcf7a8..1591976b0 100644 --- a/letsencrypt/plugins/util_test.py +++ b/letsencrypt/plugins/util_test.py @@ -98,6 +98,10 @@ class AlreadyListeningTest(unittest.TestCase): self.assertEqual(mock_get_utility.call_count, 1) mock_process.assert_called_once_with(4420) + @mock.patch("letsencrypt.plugins.util.psutil.net_connections") + def test_access_denied_exception(self, mock_net): + mock_net.side_effect = psutil.AccessDenied("") + self.assertFalse(self._call(12345)) if __name__ == "__main__": unittest.main() # pragma: no cover From 39a44b97edc39a95d221118e768fad8790fb709d Mon Sep 17 00:00:00 2001 From: Sharif Nassar Date: Tue, 20 Oct 2015 22:29:35 -0700 Subject: [PATCH 59/92] Jedi mind trick on coverage tool --- letsencrypt/plugins/manual.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/letsencrypt/plugins/manual.py b/letsencrypt/plugins/manual.py index 99463c362..f7717064b 100644 --- a/letsencrypt/plugins/manual.py +++ b/letsencrypt/plugins/manual.py @@ -130,10 +130,7 @@ binary for temporary key/certificate generation.""".replace("\n", "") if self.conf("test-mode"): logger.debug("Test mode. Executing the manual command: %s", command) # sh shipped with OS X does't support echo -n - if sys.platform == "darwin": - executable = "/bin/bash" - else: - executable = None + executable = "/bin/bash" if sys.platform == "darwin" else None try: self._httpd = subprocess.Popen( command, From fbe116c386907bd8826f19703354337a5de99932 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 21 Oct 2015 22:57:30 +1100 Subject: [PATCH 60/92] Fixed typos --- docs/contributing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 6d0a2d4ba..6b6550c71 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -372,6 +372,6 @@ FreeBSD Bootstrap script for FreeBSD uses ``pkg`` for package installation, i.e. it does not use ports. -FreeBSD by default uses ``tcsh``. In order to activate virtulenv (see -below), you will need a compatbile shell, e.g. ``pkg install bash && +FreeBSD by default uses ``tcsh``. In order to activate virtualenv (see +below), you will need a compatible shell, e.g. ``pkg install bash && bash``. From f130cb470cada7591a05b25713e54adaa5ca94ac Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 10:58:36 -0700 Subject: [PATCH 61/92] Don't find "-v" in "--version" Fixes #1065 --- letsencrypt-auto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt-auto b/letsencrypt-auto index 0b3d9b72d..7cba2ab92 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -18,7 +18,7 @@ fi for arg in "$@" ; do # This first clause is redundant with the third, but hedging on portability - if [ "$arg" = "-v" ] || [ "$arg" = "--verbose" ] || echo "$arg" | grep -E -- -v+ ; then + if [ "$arg" = "-v" ] || [ "$arg" = "--verbose" ] || echo "$arg" | grep -E -- "-v+$" ; then VERBOSE=1 fi done From 594613e2ce92757a8f590a4dc2139a529259d878 Mon Sep 17 00:00:00 2001 From: Whyfoo Date: Wed, 21 Oct 2015 20:58:33 +0200 Subject: [PATCH 62/92] Name fix --- letsencrypt-nginx/letsencrypt_nginx/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt-nginx/letsencrypt_nginx/parser.py b/letsencrypt-nginx/letsencrypt_nginx/parser.py index fc8ed95f1..19483821a 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/parser.py +++ b/letsencrypt-nginx/letsencrypt_nginx/parser.py @@ -491,5 +491,5 @@ def _add_directives(block, directives, replace=False): changed = True if not changed: raise errors.MisconfigurationError( - 'LetsEncrypt expected directive for %s in the Nginx ' + 'Let\'s Encrypt expected directive for %s in the Nginx ' 'config but did not find it.' % directive[0]) From 059ca6dbce361403e52dade0eae2e6a55dc1d6c8 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 12:23:00 -0700 Subject: [PATCH 63/92] Make debian bootstrapper more agnostic about venv packaging Closes: #1061 --- bootstrap/_deb_common.sh | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/bootstrap/_deb_common.sh b/bootstrap/_deb_common.sh index 687f30d09..f6467cf99 100755 --- a/bootstrap/_deb_common.sh +++ b/bootstrap/_deb_common.sh @@ -12,46 +12,33 @@ # - Raspbian: # - 7.8 (armhf) +apt-get update # virtualenv binary can be found in different packages depending on # distro version (#346) -newer () { - apt-get install -y lsb-release --no-install-recommends - distro=$(lsb_release -si) - # 6.0.10 => 60, 14.04 => 1404 - # TODO: in sid version==unstable - version=$(lsb_release -sr | awk -F '.' '{print $1 $2}') - if [ "$distro" = "Ubuntu" -a "$version" -ge 1410 ] - then - return 0; - elif [ "$distro" = "Debian" -a "$version" -ge 80 ] - then - return 0; - else - return 1; - fi -} -apt-get update - -# you can force newer if lsb_release is not available (e.g. Docker -# debian:jessie base image) -if [ "$1" = "newer" ] || newer -then +virtualenv= +if apt-cache show virtualenv > /dev/null ; then virtualenv="virtualenv" -else - virtualenv="python-virtualenv" fi +if apt-cache show python-virtualenv > /dev/null ; then + virtualenv="$virualenv python-virtualenv" +fi apt-get install -y --no-install-recommends \ git-core \ python \ python-dev \ - "$virtualenv" \ + $virtualenv \ gcc \ dialog \ libaugeas0 \ libssl-dev \ libffi-dev \ ca-certificates \ + +if ! which virtualenv > /dev/null ; then + echo Failed to install a working \"virtualenv\" command, exiting + exit 1 +fi From 41a59c0e15a05b14c3b6df6db966b148c13a2a79 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 12:27:22 -0700 Subject: [PATCH 64/92] typo --- bootstrap/_deb_common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap/_deb_common.sh b/bootstrap/_deb_common.sh index f6467cf99..ae34dea37 100755 --- a/bootstrap/_deb_common.sh +++ b/bootstrap/_deb_common.sh @@ -23,7 +23,7 @@ if apt-cache show virtualenv > /dev/null ; then fi if apt-cache show python-virtualenv > /dev/null ; then - virtualenv="$virualenv python-virtualenv" + virtualenv="$virtualenv python-virtualenv" fi apt-get install -y --no-install-recommends \ From db1f0a6688dbffd33e3e1fa65dab0f6ac29b2569 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 13:42:48 -0700 Subject: [PATCH 65/92] Fix pip / nginx heisenbug Closes: #1072 --- letsencrypt-auto | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/letsencrypt-auto b/letsencrypt-auto index 0b3d9b72d..b2b7a3f1c 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -69,8 +69,12 @@ if [ "$VERBOSE" = 1 ] ; then echo $VENV_BIN/pip install -U setuptools $VENV_BIN/pip install -U pip - # nginx is buggy / disabled for now... - $VENV_BIN/pip install -U letsencrypt letsencrypt-apache #letsencrypt-nginx + $VENV_BIN/pip install -U letsencrypt letsencrypt-apache + # nginx is buggy / disabled for now, but upgrade it if the user has + # installed it manually + if $VENV_BIN/pip freeze | grep -q letsencrypt-nginx ; then + $VENV_BIN/pip install -U letsencrypt letsencrypt-nginx + fi else $VENV_BIN/pip install -U setuptools > /dev/null echo -n . @@ -80,6 +84,10 @@ else $VENV_BIN/pip install -U letsencrypt > /dev/null echo -n . $VENV_BIN/pip install -U letsencrypt-apache > /dev/null + if $VENV_BIN/pip freeze | grep -q letsencrypt-nginx ; then + echo -n . + $VENV_BIN/pip install -U letsencrypt-nginx > /dev/null + fi echo fi From 7ce1da56d53c302c9021380385151269f0d80105 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 15:59:20 -0700 Subject: [PATCH 66/92] Point the user to fullchain.pem, not cert.pem Closes: #1024 --- letsencrypt/cli.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 1b396b0b8..31891dd5d 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -267,16 +267,22 @@ def _treat_as_renewal(config, domains): return None -def _report_new_cert(cert_path): - """Reports the creation of a new certificate to the user.""" - expiry = crypto_util.notAfter(cert_path).date() +def _report_new_cert(lineage): + """ + Reports the creation of a new certificate to the user. + :param RenewableCert lineage: the lineage of the new cert + """ + expiry = crypto_util.notAfter(lineage.cert).date() reporter_util = zope.component.getUtility(interfaces.IReporter) - reporter_util.add_message("Congratulations! Your certificate has been " - "saved at {0} and will expire on {1}. To obtain " - "a new version of the certificate in the " - "future, simply run Let's Encrypt again.".format( - cert_path, expiry), - reporter_util.MEDIUM_PRIORITY) + # Tell the user about fullchain.pem because that's what modern webservers + # (Nginx and Apache2.4) will want. + # XXX Perhaps one day we could detect the presence of known old webservers + # and say something more informative here. + msg = ("Congratulations! Your certificate and chain have been saved at {0}." + " Your cert will expire on {1}. To obtain a new version of the " + "certificate in the future, simply run Let's Encrypt again." + .format(lineage.fullchain, expiry)) + reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY) def _auth_from_domains(le_client, config, domains, plugins): @@ -304,7 +310,7 @@ def _auth_from_domains(le_client, config, domains, plugins): if not lineage: raise Error("Certificate could not be obtained") - _report_new_cert(lineage.cert) + _report_new_cert(lineage) return lineage From 6382b184f073337f16d4e68480d5a800beea9179 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 15:57:37 -0700 Subject: [PATCH 67/92] Update documentation of tested platforms --- bootstrap/_deb_common.sh | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/bootstrap/_deb_common.sh b/bootstrap/_deb_common.sh index ae34dea37..2f44c4e91 100755 --- a/bootstrap/_deb_common.sh +++ b/bootstrap/_deb_common.sh @@ -1,16 +1,22 @@ #!/bin/sh -# Tested with: -# - Ubuntu: -# - 12.04 (x64, Travis) -# - 14.04 (x64, Vagrant) -# - 14.10 (x64) -# - Debian: -# - 6.0.10 "squeeze" (x64) -# - 7.8 "wheezy" (x64) -# - 8.0 "jessie" (x64) -# - Raspbian: -# - 7.8 (armhf) +# Current version tested with: +# +# - Ubuntu +# - 14.04 (x64) +# - 15.04 (x64) +# - Debian +# - 7.9 "wheezy" (x64) +# - sid (2015-10-21) (x64) + +# Past versions tested with: +# +# - Debian 8.0 "jessie" (x64) +# - Raspbian 7.8 (armhf) + +# Believed not to work: +# +# - Debian 6.0.10 "squeeze" (x64) apt-get update From 934301abc6f3925294ffc03e3be3c2b5dcb61a67 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 13:50:08 +0000 Subject: [PATCH 68/92] Fix ACME module description --- acme/README.rst | 2 +- acme/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/acme/README.rst b/acme/README.rst index e3ca8b738..4b6ea818c 100644 --- a/acme/README.rst +++ b/acme/README.rst @@ -1 +1 @@ -ACME protocol implementation for Python +ACME protocol implementation in Python diff --git a/acme/setup.py b/acme/setup.py index 6448b7fe9..6e27890b1 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -41,7 +41,7 @@ testing_extras = [ setup( name='acme', version=version, - description='ACME protocol implementation', + description='ACME protocol implementation in Python', url='https://github.com/letsencrypt/letsencrypt', author="Let's Encrypt Project", author_email='client-dev@letsencrypt.org', From b9868d3c9748e28207f7ee3e66f6622333f4f8d7 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 13:42:17 +0000 Subject: [PATCH 69/92] sphinx-quickstart for subpkgs ``` sphinx-quickstart --dot _ --project acme-python --author Let's Encrypt Project -v 0 --release 0 --language en --suffix .rst --master index --ext-autodoc --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode --makefile --batchfile acme/docs sphinx-quickstart --dot _ --project letsencrypt-apache --author Let's Encrypt Project -v 0 --release 0 --language en --suffix .rst --master index --ext-autodoc --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode --makefile --batchfile letsencrypt-apache/docs sphinx-quickstart --dot _ --project letsencrypt-nginx --author Let's Encrypt Project -v 0 --release 0 --language en --suffix .rst --master index --ext-autodoc --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode --makefile --batchfile letsencrypt-nginx/docs sphinx-quickstart --dot _ --project letshelp-letsencrypt --author Let's Encrypt Project -v 0 --release 0 --language en --suffix .rst --master index --ext-autodoc --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode --makefile --batchfile letshelp-letsencrypt/docs sphinx-quickstart --dot _ --project letsencrypt-compatibility-test --author Let's Encrypt Project -v 0 --release 0 --language en --suffix .rst --master index --ext-autodoc --ext-intersphinx --ext-todo --ext-coverage --ext-viewcode --makefile --batchfile letsencrypt-compatibility-test/docs ``` --- acme/docs/Makefile | 192 ++++++++++++ acme/docs/conf.py | 294 ++++++++++++++++++ acme/docs/index.rst | 22 ++ acme/docs/make.bat | 263 ++++++++++++++++ letsencrypt-apache/docs/Makefile | 192 ++++++++++++ letsencrypt-apache/docs/conf.py | 294 ++++++++++++++++++ letsencrypt-apache/docs/index.rst | 22 ++ letsencrypt-apache/docs/make.bat | 263 ++++++++++++++++ letsencrypt-compatibility-test/docs/Makefile | 192 ++++++++++++ letsencrypt-compatibility-test/docs/conf.py | 294 ++++++++++++++++++ letsencrypt-compatibility-test/docs/index.rst | 22 ++ letsencrypt-compatibility-test/docs/make.bat | 263 ++++++++++++++++ letsencrypt-nginx/docs/Makefile | 192 ++++++++++++ letsencrypt-nginx/docs/conf.py | 294 ++++++++++++++++++ letsencrypt-nginx/docs/index.rst | 22 ++ letsencrypt-nginx/docs/make.bat | 263 ++++++++++++++++ letshelp-letsencrypt/docs/Makefile | 192 ++++++++++++ letshelp-letsencrypt/docs/conf.py | 294 ++++++++++++++++++ letshelp-letsencrypt/docs/index.rst | 22 ++ letshelp-letsencrypt/docs/make.bat | 263 ++++++++++++++++ 20 files changed, 3855 insertions(+) create mode 100644 acme/docs/Makefile create mode 100644 acme/docs/conf.py create mode 100644 acme/docs/index.rst create mode 100644 acme/docs/make.bat create mode 100644 letsencrypt-apache/docs/Makefile create mode 100644 letsencrypt-apache/docs/conf.py create mode 100644 letsencrypt-apache/docs/index.rst create mode 100644 letsencrypt-apache/docs/make.bat create mode 100644 letsencrypt-compatibility-test/docs/Makefile create mode 100644 letsencrypt-compatibility-test/docs/conf.py create mode 100644 letsencrypt-compatibility-test/docs/index.rst create mode 100644 letsencrypt-compatibility-test/docs/make.bat create mode 100644 letsencrypt-nginx/docs/Makefile create mode 100644 letsencrypt-nginx/docs/conf.py create mode 100644 letsencrypt-nginx/docs/index.rst create mode 100644 letsencrypt-nginx/docs/make.bat create mode 100644 letshelp-letsencrypt/docs/Makefile create mode 100644 letshelp-letsencrypt/docs/conf.py create mode 100644 letshelp-letsencrypt/docs/index.rst create mode 100644 letshelp-letsencrypt/docs/make.bat diff --git a/acme/docs/Makefile b/acme/docs/Makefile new file mode 100644 index 000000000..79de9c0a3 --- /dev/null +++ b/acme/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/acme-python.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/acme-python.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/acme-python" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/acme-python" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/acme/docs/conf.py b/acme/docs/conf.py new file mode 100644 index 000000000..0b7dee0e1 --- /dev/null +++ b/acme/docs/conf.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# +# acme-python documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 18 13:38:06 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'acme-python' +copyright = u'2015, Let\'s Encrypt Project' +author = u'Let\'s Encrypt Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'acme-pythondoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'acme-python.tex', u'acme-python Documentation', + u'Let\'s Encrypt Project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'acme-python', u'acme-python Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'acme-python', u'acme-python Documentation', + author, 'acme-python', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/acme/docs/index.rst b/acme/docs/index.rst new file mode 100644 index 000000000..357d73fd0 --- /dev/null +++ b/acme/docs/index.rst @@ -0,0 +1,22 @@ +.. acme-python documentation master file, created by + sphinx-quickstart on Sun Oct 18 13:38:06 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to acme-python's documentation! +======================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/acme/docs/make.bat b/acme/docs/make.bat new file mode 100644 index 000000000..781185977 --- /dev/null +++ b/acme/docs/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\acme-python.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\acme-python.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/letsencrypt-apache/docs/Makefile b/letsencrypt-apache/docs/Makefile new file mode 100644 index 000000000..9bf5154fe --- /dev/null +++ b/letsencrypt-apache/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/letsencrypt-apache.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/letsencrypt-apache.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/letsencrypt-apache" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/letsencrypt-apache" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py new file mode 100644 index 000000000..f572d2a7f --- /dev/null +++ b/letsencrypt-apache/docs/conf.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# +# letsencrypt-apache documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 18 13:39:26 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'letsencrypt-apache' +copyright = u'2015, Let\'s Encrypt Project' +author = u'Let\'s Encrypt Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'letsencrypt-apachedoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'letsencrypt-apache.tex', u'letsencrypt-apache Documentation', + u'Let\'s Encrypt Project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'letsencrypt-apache', u'letsencrypt-apache Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'letsencrypt-apache', u'letsencrypt-apache Documentation', + author, 'letsencrypt-apache', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/letsencrypt-apache/docs/index.rst b/letsencrypt-apache/docs/index.rst new file mode 100644 index 000000000..64f0e3e14 --- /dev/null +++ b/letsencrypt-apache/docs/index.rst @@ -0,0 +1,22 @@ +.. letsencrypt-apache documentation master file, created by + sphinx-quickstart on Sun Oct 18 13:39:26 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to letsencrypt-apache's documentation! +============================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/letsencrypt-apache/docs/make.bat b/letsencrypt-apache/docs/make.bat new file mode 100644 index 000000000..62a54fd2c --- /dev/null +++ b/letsencrypt-apache/docs/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\letsencrypt-apache.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\letsencrypt-apache.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/letsencrypt-compatibility-test/docs/Makefile b/letsencrypt-compatibility-test/docs/Makefile new file mode 100644 index 000000000..90582a59b --- /dev/null +++ b/letsencrypt-compatibility-test/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/letsencrypt-compatibility-test.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/letsencrypt-compatibility-test.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/letsencrypt-compatibility-test" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/letsencrypt-compatibility-test" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py new file mode 100644 index 000000000..2c468a763 --- /dev/null +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# +# letsencrypt-compatibility-test documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 18 13:40:53 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'letsencrypt-compatibility-test' +copyright = u'2015, Let\'s Encrypt Project' +author = u'Let\'s Encrypt Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'letsencrypt-compatibility-testdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'letsencrypt-compatibility-test.tex', u'letsencrypt-compatibility-test Documentation', + u'Let\'s Encrypt Project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'letsencrypt-compatibility-test', u'letsencrypt-compatibility-test Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'letsencrypt-compatibility-test', u'letsencrypt-compatibility-test Documentation', + author, 'letsencrypt-compatibility-test', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/letsencrypt-compatibility-test/docs/index.rst b/letsencrypt-compatibility-test/docs/index.rst new file mode 100644 index 000000000..3df442c65 --- /dev/null +++ b/letsencrypt-compatibility-test/docs/index.rst @@ -0,0 +1,22 @@ +.. letsencrypt-compatibility-test documentation master file, created by + sphinx-quickstart on Sun Oct 18 13:40:53 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to letsencrypt-compatibility-test's documentation! +========================================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/letsencrypt-compatibility-test/docs/make.bat b/letsencrypt-compatibility-test/docs/make.bat new file mode 100644 index 000000000..c75269bdc --- /dev/null +++ b/letsencrypt-compatibility-test/docs/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\letsencrypt-compatibility-test.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\letsencrypt-compatibility-test.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/letsencrypt-nginx/docs/Makefile b/letsencrypt-nginx/docs/Makefile new file mode 100644 index 000000000..3a3828235 --- /dev/null +++ b/letsencrypt-nginx/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/letsencrypt-nginx.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/letsencrypt-nginx.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/letsencrypt-nginx" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/letsencrypt-nginx" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py new file mode 100644 index 000000000..4cde40314 --- /dev/null +++ b/letsencrypt-nginx/docs/conf.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# +# letsencrypt-nginx documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 18 13:39:39 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'letsencrypt-nginx' +copyright = u'2015, Let\'s Encrypt Project' +author = u'Let\'s Encrypt Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'letsencrypt-nginxdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'letsencrypt-nginx.tex', u'letsencrypt-nginx Documentation', + u'Let\'s Encrypt Project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'letsencrypt-nginx', u'letsencrypt-nginx Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'letsencrypt-nginx', u'letsencrypt-nginx Documentation', + author, 'letsencrypt-nginx', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/letsencrypt-nginx/docs/index.rst b/letsencrypt-nginx/docs/index.rst new file mode 100644 index 000000000..c4822af52 --- /dev/null +++ b/letsencrypt-nginx/docs/index.rst @@ -0,0 +1,22 @@ +.. letsencrypt-nginx documentation master file, created by + sphinx-quickstart on Sun Oct 18 13:39:39 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to letsencrypt-nginx's documentation! +============================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/letsencrypt-nginx/docs/make.bat b/letsencrypt-nginx/docs/make.bat new file mode 100644 index 000000000..eb19a3fb5 --- /dev/null +++ b/letsencrypt-nginx/docs/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\letsencrypt-nginx.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\letsencrypt-nginx.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/letshelp-letsencrypt/docs/Makefile b/letshelp-letsencrypt/docs/Makefile new file mode 100644 index 000000000..8e742d837 --- /dev/null +++ b/letshelp-letsencrypt/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/letshelp-letsencrypt.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/letshelp-letsencrypt.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/letshelp-letsencrypt" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/letshelp-letsencrypt" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py new file mode 100644 index 000000000..cd1ae4531 --- /dev/null +++ b/letshelp-letsencrypt/docs/conf.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# +# letshelp-letsencrypt documentation build configuration file, created by +# sphinx-quickstart on Sun Oct 18 13:40:19 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'letshelp-letsencrypt' +copyright = u'2015, Let\'s Encrypt Project' +author = u'Let\'s Encrypt Project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0' +# The full version, including alpha/beta/rc tags. +release = '0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'letshelp-letsencryptdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'letshelp-letsencrypt.tex', u'letshelp-letsencrypt Documentation', + u'Let\'s Encrypt Project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'letshelp-letsencrypt', u'letshelp-letsencrypt Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'letshelp-letsencrypt', u'letshelp-letsencrypt Documentation', + author, 'letshelp-letsencrypt', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/letshelp-letsencrypt/docs/index.rst b/letshelp-letsencrypt/docs/index.rst new file mode 100644 index 000000000..db806d874 --- /dev/null +++ b/letshelp-letsencrypt/docs/index.rst @@ -0,0 +1,22 @@ +.. letshelp-letsencrypt documentation master file, created by + sphinx-quickstart on Sun Oct 18 13:40:19 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to letshelp-letsencrypt's documentation! +================================================ + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/letshelp-letsencrypt/docs/make.bat b/letshelp-letsencrypt/docs/make.bat new file mode 100644 index 000000000..006f7825d --- /dev/null +++ b/letshelp-letsencrypt/docs/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 2> nul +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\letshelp-letsencrypt.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\letshelp-letsencrypt.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end From 635008f5e69dadde3240972661bbd437f0b2f4a5 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:12:39 +0000 Subject: [PATCH 70/92] Configure intersphinx --- acme/docs/conf.py | 7 ++++--- docs/conf.py | 8 +++++--- letsencrypt-apache/docs/conf.py | 9 ++++++--- letsencrypt-compatibility-test/docs/conf.py | 11 ++++++++--- letsencrypt-nginx/docs/conf.py | 9 ++++++--- letshelp-letsencrypt/docs/conf.py | 9 ++++++--- 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/acme/docs/conf.py b/acme/docs/conf.py index 0b7dee0e1..21a412ec0 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -24,7 +24,7 @@ import shlex # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -290,5 +290,6 @@ texinfo_documents = [ #texinfo_no_detailmenu = False -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = { + 'python': ('https://docs.python.org/', None), +} diff --git a/docs/conf.py b/docs/conf.py index e2b360a6e..9a649e2de 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -42,7 +42,7 @@ for pkg in 'acme', 'letsencrypt-apache', 'letsencrypt-nginx': # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -320,7 +320,9 @@ texinfo_documents = [ #texinfo_no_detailmenu = False -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} +intersphinx_mapping = { + 'python': ('https://docs.python.org/': None), + 'acme': ('https://acme-python.readthedocs.org', None), +} todo_include_todos = True diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py index f572d2a7f..4a0bf16c8 100644 --- a/letsencrypt-apache/docs/conf.py +++ b/letsencrypt-apache/docs/conf.py @@ -24,7 +24,7 @@ import shlex # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -290,5 +290,8 @@ texinfo_documents = [ #texinfo_no_detailmenu = False -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = { + 'python': ('https://docs.python.org/', None), + 'acme': ('https://acme-python.readthedocs.org', None), + 'letsencrypt': ('https://letsencrypt.readthedocs.org', None), +} diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index 2c468a763..3cd77fe0e 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -24,7 +24,7 @@ import shlex # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -290,5 +290,10 @@ texinfo_documents = [ #texinfo_no_detailmenu = False -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = { + 'python': ('https://docs.python.org/', None), + 'acme': ('https://acme-python.readthedocs.org', None), + 'letsencrypt': ('https://letsencrypt.readthedocs.org', None), + 'letsencrypt-apache': ('https://letsencrypt-apache.readthedocs.org', None), + 'letsencrypt-nginx': ('https://letsencrypt-nginx.readthedocs.org', None), +} diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py index 4cde40314..f9924894b 100644 --- a/letsencrypt-nginx/docs/conf.py +++ b/letsencrypt-nginx/docs/conf.py @@ -24,7 +24,7 @@ import shlex # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -290,5 +290,8 @@ texinfo_documents = [ #texinfo_no_detailmenu = False -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = { + 'python': ('https://docs.python.org/', None), + 'acme': ('https://acme-python.readthedocs.org', None), + 'letsencrypt': ('https://letsencrypt.readthedocs.org', None), +} diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py index cd1ae4531..96de8890e 100644 --- a/letshelp-letsencrypt/docs/conf.py +++ b/letshelp-letsencrypt/docs/conf.py @@ -24,7 +24,7 @@ import shlex # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -290,5 +290,8 @@ texinfo_documents = [ #texinfo_no_detailmenu = False -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = { + 'python': ('https://docs.python.org/', None), + 'acme': ('https://acme-python.readthedocs.org', None), + 'letsencrypt': ('https://letsencrypt.readthedocs.org', None), +} From 511eef130bf7d41c6b44b65d389f67506ce1413e Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:15:32 +0000 Subject: [PATCH 71/92] Unify todo_include_todos --- docs/conf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 9a649e2de..f96c48352 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -126,6 +126,9 @@ pygments_style = 'sphinx' # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + # -- Options for HTML output ---------------------------------------------- @@ -324,5 +327,3 @@ intersphinx_mapping = { 'python': ('https://docs.python.org/': None), 'acme': ('https://acme-python.readthedocs.org', None), } - -todo_include_todos = True From 607ea59fd35c8c039c44b4a7022bf0347985507f Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:04:46 +0000 Subject: [PATCH 72/92] Add extensions for subpkgs docs --- acme/docs/conf.py | 1 + letsencrypt-compatibility-test/docs/conf.py | 1 + 2 files changed, 2 insertions(+) diff --git a/acme/docs/conf.py b/acme/docs/conf.py index 21a412ec0..7b243771f 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -35,6 +35,7 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', + 'sphinxcontrib.programoutput', ] # Add any paths that contain templates here, relative to this directory. diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index 3cd77fe0e..a118bedf1 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -35,6 +35,7 @@ extensions = [ 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', + 'repoze.sphinx.autointerface', ] # Add any paths that contain templates here, relative to this directory. From 1a6fc9ce76c1659b745eae5dbc802f2421ee89e7 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:21:04 +0000 Subject: [PATCH 73/92] RTD theme everywhere! --- acme/docs/conf.py | 10 +++++++++- letsencrypt-apache/docs/conf.py | 10 +++++++++- letsencrypt-compatibility-test/docs/conf.py | 10 +++++++++- letsencrypt-nginx/docs/conf.py | 10 +++++++++- letshelp-letsencrypt/docs/conf.py | 10 +++++++++- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/acme/docs/conf.py b/acme/docs/conf.py index 7b243771f..c4ee0c740 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -115,7 +115,15 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' + +# http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# otherwise, readthedocs.org uses their theme by default, so no need to specify it # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py index 4a0bf16c8..8dbffdcd8 100644 --- a/letsencrypt-apache/docs/conf.py +++ b/letsencrypt-apache/docs/conf.py @@ -114,7 +114,15 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' + +# http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# otherwise, readthedocs.org uses their theme by default, so no need to specify it # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index a118bedf1..554e71315 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -115,7 +115,15 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' + +# http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# otherwise, readthedocs.org uses their theme by default, so no need to specify it # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py index f9924894b..30093408e 100644 --- a/letsencrypt-nginx/docs/conf.py +++ b/letsencrypt-nginx/docs/conf.py @@ -114,7 +114,15 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' + +# http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# otherwise, readthedocs.org uses their theme by default, so no need to specify it # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py index 96de8890e..8e7890709 100644 --- a/letshelp-letsencrypt/docs/conf.py +++ b/letshelp-letsencrypt/docs/conf.py @@ -114,7 +114,15 @@ todo_include_todos = True # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'alabaster' + +# http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +# otherwise, readthedocs.org uses their theme by default, so no need to specify it # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 1f0cbda9fc3fb55a1427e976d89f4c52c4be08be Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:26:16 +0000 Subject: [PATCH 74/92] Unify autodoc options --- acme/docs/conf.py | 3 +++ letsencrypt-apache/docs/conf.py | 3 +++ letsencrypt-compatibility-test/docs/conf.py | 3 +++ letsencrypt-nginx/docs/conf.py | 3 +++ letshelp-letsencrypt/docs/conf.py | 3 +++ 5 files changed, 15 insertions(+) diff --git a/acme/docs/conf.py b/acme/docs/conf.py index c4ee0c740..b77b87c45 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -38,6 +38,9 @@ extensions = [ 'sphinxcontrib.programoutput', ] +autodoc_member_order = 'bysource' +autodoc_default_flags = ['show-inheritance', 'private-members'] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py index 8dbffdcd8..1f5838fcc 100644 --- a/letsencrypt-apache/docs/conf.py +++ b/letsencrypt-apache/docs/conf.py @@ -37,6 +37,9 @@ extensions = [ 'sphinx.ext.viewcode', ] +autodoc_member_order = 'bysource' +autodoc_default_flags = ['show-inheritance', 'private-members'] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index 554e71315..066596de7 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -38,6 +38,9 @@ extensions = [ 'repoze.sphinx.autointerface', ] +autodoc_member_order = 'bysource' +autodoc_default_flags = ['show-inheritance', 'private-members'] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py index 30093408e..9716ae6d3 100644 --- a/letsencrypt-nginx/docs/conf.py +++ b/letsencrypt-nginx/docs/conf.py @@ -37,6 +37,9 @@ extensions = [ 'sphinx.ext.viewcode', ] +autodoc_member_order = 'bysource' +autodoc_default_flags = ['show-inheritance', 'private-members'] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py index 8e7890709..e9d50855b 100644 --- a/letshelp-letsencrypt/docs/conf.py +++ b/letshelp-letsencrypt/docs/conf.py @@ -37,6 +37,9 @@ extensions = [ 'sphinx.ext.viewcode', ] +autodoc_member_order = 'bysource' +autodoc_default_flags = ['show-inheritance', 'private-members'] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From dfdb64c505ed0f16c7d32afeef4a457593fb6edb Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:31:06 +0000 Subject: [PATCH 75/92] sphinx: default_role py:obj --- acme/docs/conf.py | 2 +- letsencrypt-apache/docs/conf.py | 2 +- letsencrypt-compatibility-test/docs/conf.py | 2 +- letsencrypt-nginx/docs/conf.py | 2 +- letshelp-letsencrypt/docs/conf.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/acme/docs/conf.py b/acme/docs/conf.py index b77b87c45..47f9321f9 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -88,7 +88,7 @@ exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +default_role = 'py:obj' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py index 1f5838fcc..8d57abb0e 100644 --- a/letsencrypt-apache/docs/conf.py +++ b/letsencrypt-apache/docs/conf.py @@ -87,7 +87,7 @@ exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +default_role = 'py:obj' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index 066596de7..5236996d2 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -88,7 +88,7 @@ exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +default_role = 'py:obj' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py index 9716ae6d3..d19a73209 100644 --- a/letsencrypt-nginx/docs/conf.py +++ b/letsencrypt-nginx/docs/conf.py @@ -87,7 +87,7 @@ exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +default_role = 'py:obj' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py index e9d50855b..d7fc03ddc 100644 --- a/letshelp-letsencrypt/docs/conf.py +++ b/letshelp-letsencrypt/docs/conf.py @@ -87,7 +87,7 @@ exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +default_role = 'py:obj' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True From 86f01d1fa9a62b95b2db407d4859ae501744799c Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:33:11 +0000 Subject: [PATCH 76/92] sphinx: copyright 2014-2015 --- acme/docs/conf.py | 2 +- docs/conf.py | 2 +- letsencrypt-apache/docs/conf.py | 2 +- letsencrypt-compatibility-test/docs/conf.py | 2 +- letsencrypt-nginx/docs/conf.py | 2 +- letshelp-letsencrypt/docs/conf.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/acme/docs/conf.py b/acme/docs/conf.py index 47f9321f9..dc5dec0ff 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -57,7 +57,7 @@ master_doc = 'index' # General information about the project. project = u'acme-python' -copyright = u'2015, Let\'s Encrypt Project' +copyright = u'2015-2015, Let\'s Encrypt Project' author = u'Let\'s Encrypt Project' # The version info for the project you're documenting, acts as replacement for diff --git a/docs/conf.py b/docs/conf.py index f96c48352..2de0dd877 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ master_doc = 'index' # General information about the project. project = u'Let\'s Encrypt' -copyright = u'2014, Let\'s Encrypt Project' +copyright = u'2014-2015, Let\'s Encrypt Project' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py index 8d57abb0e..f578531db 100644 --- a/letsencrypt-apache/docs/conf.py +++ b/letsencrypt-apache/docs/conf.py @@ -56,7 +56,7 @@ master_doc = 'index' # General information about the project. project = u'letsencrypt-apache' -copyright = u'2015, Let\'s Encrypt Project' +copyright = u'2014-2015, Let\'s Encrypt Project' author = u'Let\'s Encrypt Project' # The version info for the project you're documenting, acts as replacement for diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index 5236996d2..4ec0a1d9a 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -57,7 +57,7 @@ master_doc = 'index' # General information about the project. project = u'letsencrypt-compatibility-test' -copyright = u'2015, Let\'s Encrypt Project' +copyright = u'2014-2015, Let\'s Encrypt Project' author = u'Let\'s Encrypt Project' # The version info for the project you're documenting, acts as replacement for diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py index d19a73209..e8e320542 100644 --- a/letsencrypt-nginx/docs/conf.py +++ b/letsencrypt-nginx/docs/conf.py @@ -56,7 +56,7 @@ master_doc = 'index' # General information about the project. project = u'letsencrypt-nginx' -copyright = u'2015, Let\'s Encrypt Project' +copyright = u'2014-2015, Let\'s Encrypt Project' author = u'Let\'s Encrypt Project' # The version info for the project you're documenting, acts as replacement for diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py index d7fc03ddc..3561a12d1 100644 --- a/letshelp-letsencrypt/docs/conf.py +++ b/letshelp-letsencrypt/docs/conf.py @@ -56,7 +56,7 @@ master_doc = 'index' # General information about the project. project = u'letshelp-letsencrypt' -copyright = u'2015, Let\'s Encrypt Project' +copyright = u'2014-2015, Let\'s Encrypt Project' author = u'Let\'s Encrypt Project' # The version info for the project you're documenting, acts as replacement for From baa6c4aeec6401de31a054c5c95940eff250d073 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 14:50:46 +0000 Subject: [PATCH 77/92] gitignores for various doc files --- acme/docs/.gitignore | 1 + acme/docs/_static/.gitignore | 0 acme/docs/_templates/.gitignore | 0 docs/.gitignore | 2 +- letsencrypt-apache/docs/.gitignore | 1 + letsencrypt-apache/docs/_static/.gitignore | 0 letsencrypt-apache/docs/_templates/.gitignore | 0 letsencrypt-compatibility-test/docs/.gitignore | 1 + letsencrypt-compatibility-test/docs/_static/.gitignore | 0 letsencrypt-compatibility-test/docs/_templates/.gitignore | 0 letsencrypt-nginx/docs/.gitignore | 1 + letsencrypt-nginx/docs/_static/.gitignore | 0 letsencrypt-nginx/docs/_templates/.gitignore | 0 letshelp-letsencrypt/docs/.gitignore | 1 + letshelp-letsencrypt/docs/_static/.gitignore | 0 letshelp-letsencrypt/docs/_templates/.gitignore | 0 16 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 acme/docs/.gitignore create mode 100644 acme/docs/_static/.gitignore create mode 100644 acme/docs/_templates/.gitignore create mode 100644 letsencrypt-apache/docs/.gitignore create mode 100644 letsencrypt-apache/docs/_static/.gitignore create mode 100644 letsencrypt-apache/docs/_templates/.gitignore create mode 100644 letsencrypt-compatibility-test/docs/.gitignore create mode 100644 letsencrypt-compatibility-test/docs/_static/.gitignore create mode 100644 letsencrypt-compatibility-test/docs/_templates/.gitignore create mode 100644 letsencrypt-nginx/docs/.gitignore create mode 100644 letsencrypt-nginx/docs/_static/.gitignore create mode 100644 letsencrypt-nginx/docs/_templates/.gitignore create mode 100644 letshelp-letsencrypt/docs/.gitignore create mode 100644 letshelp-letsencrypt/docs/_static/.gitignore create mode 100644 letshelp-letsencrypt/docs/_templates/.gitignore diff --git a/acme/docs/.gitignore b/acme/docs/.gitignore new file mode 100644 index 000000000..ba65b13af --- /dev/null +++ b/acme/docs/.gitignore @@ -0,0 +1 @@ +/_build/ diff --git a/acme/docs/_static/.gitignore b/acme/docs/_static/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/acme/docs/_templates/.gitignore b/acme/docs/_templates/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/docs/.gitignore b/docs/.gitignore index 69fa449dd..ba65b13af 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1 +1 @@ -_build/ +/_build/ diff --git a/letsencrypt-apache/docs/.gitignore b/letsencrypt-apache/docs/.gitignore new file mode 100644 index 000000000..ba65b13af --- /dev/null +++ b/letsencrypt-apache/docs/.gitignore @@ -0,0 +1 @@ +/_build/ diff --git a/letsencrypt-apache/docs/_static/.gitignore b/letsencrypt-apache/docs/_static/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letsencrypt-apache/docs/_templates/.gitignore b/letsencrypt-apache/docs/_templates/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letsencrypt-compatibility-test/docs/.gitignore b/letsencrypt-compatibility-test/docs/.gitignore new file mode 100644 index 000000000..ba65b13af --- /dev/null +++ b/letsencrypt-compatibility-test/docs/.gitignore @@ -0,0 +1 @@ +/_build/ diff --git a/letsencrypt-compatibility-test/docs/_static/.gitignore b/letsencrypt-compatibility-test/docs/_static/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letsencrypt-compatibility-test/docs/_templates/.gitignore b/letsencrypt-compatibility-test/docs/_templates/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letsencrypt-nginx/docs/.gitignore b/letsencrypt-nginx/docs/.gitignore new file mode 100644 index 000000000..ba65b13af --- /dev/null +++ b/letsencrypt-nginx/docs/.gitignore @@ -0,0 +1 @@ +/_build/ diff --git a/letsencrypt-nginx/docs/_static/.gitignore b/letsencrypt-nginx/docs/_static/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letsencrypt-nginx/docs/_templates/.gitignore b/letsencrypt-nginx/docs/_templates/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letshelp-letsencrypt/docs/.gitignore b/letshelp-letsencrypt/docs/.gitignore new file mode 100644 index 000000000..ba65b13af --- /dev/null +++ b/letshelp-letsencrypt/docs/.gitignore @@ -0,0 +1 @@ +/_build/ diff --git a/letshelp-letsencrypt/docs/_static/.gitignore b/letshelp-letsencrypt/docs/_static/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/letshelp-letsencrypt/docs/_templates/.gitignore b/letshelp-letsencrypt/docs/_templates/.gitignore new file mode 100644 index 000000000..e69de29bb From 5fe5d69192c3ec21201fcdf63f87c6bdfdb418fa Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 13:45:18 +0000 Subject: [PATCH 78/92] Include docs in subpkgs tarballs --- acme/MANIFEST.in | 1 + letsencrypt-apache/MANIFEST.in | 1 + letsencrypt-compatibility-test/MANIFEST.in | 1 + letsencrypt-nginx/MANIFEST.in | 1 + letshelp-letsencrypt/MANIFEST.in | 1 + 5 files changed, 5 insertions(+) diff --git a/acme/MANIFEST.in b/acme/MANIFEST.in index ec2b09e05..a452d60d4 100644 --- a/acme/MANIFEST.in +++ b/acme/MANIFEST.in @@ -1,3 +1,4 @@ include LICENSE.txt include README.rst +recursive-include docs * recursive-include acme/testdata * diff --git a/letsencrypt-apache/MANIFEST.in b/letsencrypt-apache/MANIFEST.in index ff99bf0d8..51c2df858 100644 --- a/letsencrypt-apache/MANIFEST.in +++ b/letsencrypt-apache/MANIFEST.in @@ -1,4 +1,5 @@ include LICENSE.txt include README.rst +recursive-include docs * recursive-include letsencrypt_apache/tests/testdata * include letsencrypt_apache/options-ssl-apache.conf diff --git a/letsencrypt-compatibility-test/MANIFEST.in b/letsencrypt-compatibility-test/MANIFEST.in index 4d346a5d0..24d777841 100644 --- a/letsencrypt-compatibility-test/MANIFEST.in +++ b/letsencrypt-compatibility-test/MANIFEST.in @@ -1,5 +1,6 @@ include LICENSE.txt include README.rst +recursive-include docs * include letsencrypt_compatibility_test/configurators/apache/a2enmod.sh include letsencrypt_compatibility_test/configurators/apache/a2dismod.sh include letsencrypt_compatibility_test/configurators/apache/Dockerfile diff --git a/letsencrypt-nginx/MANIFEST.in b/letsencrypt-nginx/MANIFEST.in index c4bd67735..912d624d9 100644 --- a/letsencrypt-nginx/MANIFEST.in +++ b/letsencrypt-nginx/MANIFEST.in @@ -1,4 +1,5 @@ include LICENSE.txt include README.rst +recursive-include docs * recursive-include letsencrypt_nginx/tests/testdata * include letsencrypt_nginx/options-ssl-nginx.conf diff --git a/letshelp-letsencrypt/MANIFEST.in b/letshelp-letsencrypt/MANIFEST.in index 96c1d7ba5..6ea55a950 100644 --- a/letshelp-letsencrypt/MANIFEST.in +++ b/letshelp-letsencrypt/MANIFEST.in @@ -1,3 +1,4 @@ include LICENSE.txt include README.rst +recursive-include docs * recursive-include letshelp_letsencrypt/testdata * From 946ee632386d5973145d6371409173442947fbd0 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 13:49:26 +0000 Subject: [PATCH 79/92] docs_extra for subpkgs --- acme/setup.py | 7 +++++++ letsencrypt-apache/setup.py | 8 ++++++++ letsencrypt-compatibility-test/setup.py | 9 +++++++++ letsencrypt-nginx/setup.py | 8 ++++++++ letshelp-letsencrypt/setup.py | 8 ++++++++ 5 files changed, 40 insertions(+) diff --git a/acme/setup.py b/acme/setup.py index 6e27890b1..59c07d5c8 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -32,6 +32,12 @@ if sys.version_info < (2, 7): else: install_requires.append('mock') +docs_extras = [ + 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags + 'sphinx_rtd_theme', + 'sphinxcontrib-programoutput', +] + testing_extras = [ 'nose', 'tox', @@ -61,6 +67,7 @@ setup( include_package_data=True, install_requires=install_requires, extras_require={ + 'docs': docs_extras, 'testing': testing_extras, }, entry_points={ diff --git a/letsencrypt-apache/setup.py b/letsencrypt-apache/setup.py index 626e700b2..2180219f1 100644 --- a/letsencrypt-apache/setup.py +++ b/letsencrypt-apache/setup.py @@ -20,6 +20,11 @@ if sys.version_info < (2, 7): else: install_requires.append('mock') +docs_extras = [ + 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags + 'sphinx_rtd_theme', +] + setup( name='letsencrypt-apache', version=version, @@ -48,6 +53,9 @@ setup( packages=find_packages(), include_package_data=True, install_requires=install_requires, + extras_require={ + 'docs': docs_extras, + }, entry_points={ 'letsencrypt.plugins': [ 'apache = letsencrypt_apache.configurator:ApacheConfigurator', diff --git a/letsencrypt-compatibility-test/setup.py b/letsencrypt-compatibility-test/setup.py index 2e70fd1d7..3bd8f274e 100644 --- a/letsencrypt-compatibility-test/setup.py +++ b/letsencrypt-compatibility-test/setup.py @@ -19,6 +19,12 @@ if sys.version_info < (2, 7): else: install_requires.append('mock') +docs_extras = [ + 'repoze.sphinx.autointerface', + 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags + 'sphinx_rtd_theme', +] + setup( name='letsencrypt-compatibility-test', version=version, @@ -41,6 +47,9 @@ setup( packages=find_packages(), include_package_data=True, install_requires=install_requires, + extras_require={ + 'docs': docs_extras, + }, entry_points={ 'console_scripts': [ 'letsencrypt-compatibility-test = letsencrypt_compatibility_test.test_driver:main', diff --git a/letsencrypt-nginx/setup.py b/letsencrypt-nginx/setup.py index a37b8222b..5d80807d1 100644 --- a/letsencrypt-nginx/setup.py +++ b/letsencrypt-nginx/setup.py @@ -20,6 +20,11 @@ if sys.version_info < (2, 7): else: install_requires.append('mock') +docs_extras = [ + 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags + 'sphinx_rtd_theme', +] + setup( name='letsencrypt-nginx', version=version, @@ -48,6 +53,9 @@ setup( packages=find_packages(), include_package_data=True, install_requires=install_requires, + extras_require={ + 'docs': docs_extras, + }, entry_points={ 'letsencrypt.plugins': [ 'nginx = letsencrypt_nginx.configurator:NginxConfigurator', diff --git a/letshelp-letsencrypt/setup.py b/letshelp-letsencrypt/setup.py index a83fc8843..a63e0aad4 100644 --- a/letshelp-letsencrypt/setup.py +++ b/letshelp-letsencrypt/setup.py @@ -14,6 +14,11 @@ if sys.version_info < (2, 7): else: install_requires.append('mock') +docs_extras = [ + 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags + 'sphinx_rtd_theme', +] + setup( name='letshelp-letsencrypt', version=version, @@ -41,6 +46,9 @@ setup( packages=find_packages(), include_package_data=True, install_requires=install_requires, + extras_require={ + 'docs': docs_extras, + }, entry_points={ 'console_scripts': [ 'letshelp-letsencrypt-apache = letshelp_letsencrypt.apache:main', From f922b9b6940523f56b18aaafbb1eeaeb030b2d9c Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 14:17:10 +0000 Subject: [PATCH 80/92] Split docs into subpkgs (fixes #969) --- acme/docs/api.rst | 8 ++++++++ {docs/pkgs/acme => acme/docs/api}/index.rst | 0 {docs/pkgs/acme => acme/docs/api}/jose.rst | 0 acme/docs/conf.py | 9 +++++++-- acme/docs/index.rst | 1 + {docs => acme/docs}/man/jws.rst | 0 docs/conf.py | 10 ---------- docs/contributing.rst | 10 ++-------- docs/index.rst | 1 - docs/pkgs.rst | 14 -------------- letsencrypt-apache/docs/api.rst | 8 ++++++++ .../docs/api/index.rst | 0 letsencrypt-apache/docs/conf.py | 12 +++++++++++- letsencrypt-apache/docs/index.rst | 5 +++++ letsencrypt-compatibility-test/docs/api.rst | 8 ++++++++ .../docs/api/index.rst | 0 letsencrypt-compatibility-test/docs/conf.py | 5 ++++- letsencrypt-compatibility-test/docs/index.rst | 5 +++++ letsencrypt-nginx/docs/api.rst | 8 ++++++++ .../docs/api/index.rst | 0 letsencrypt-nginx/docs/conf.py | 5 ++++- letsencrypt-nginx/docs/index.rst | 5 +++++ letshelp-letsencrypt/docs/api.rst | 8 ++++++++ .../docs/api/index.rst | 0 letshelp-letsencrypt/docs/conf.py | 5 ++++- letshelp-letsencrypt/docs/index.rst | 5 +++++ 26 files changed, 93 insertions(+), 39 deletions(-) create mode 100644 acme/docs/api.rst rename {docs/pkgs/acme => acme/docs/api}/index.rst (100%) rename {docs/pkgs/acme => acme/docs/api}/jose.rst (100%) rename {docs => acme/docs}/man/jws.rst (100%) delete mode 100644 docs/pkgs.rst create mode 100644 letsencrypt-apache/docs/api.rst rename docs/pkgs/letsencrypt_apache.rst => letsencrypt-apache/docs/api/index.rst (100%) create mode 100644 letsencrypt-compatibility-test/docs/api.rst rename docs/pkgs/letsencrypt_compatibility_test.rst => letsencrypt-compatibility-test/docs/api/index.rst (100%) create mode 100644 letsencrypt-nginx/docs/api.rst rename docs/pkgs/letsencrypt_nginx.rst => letsencrypt-nginx/docs/api/index.rst (100%) create mode 100644 letshelp-letsencrypt/docs/api.rst rename docs/pkgs/letshelp_letsencrypt.rst => letshelp-letsencrypt/docs/api/index.rst (100%) diff --git a/acme/docs/api.rst b/acme/docs/api.rst new file mode 100644 index 000000000..8668ec5d8 --- /dev/null +++ b/acme/docs/api.rst @@ -0,0 +1,8 @@ +================= +API Documentation +================= + +.. toctree:: + :glob: + + api/** diff --git a/docs/pkgs/acme/index.rst b/acme/docs/api/index.rst similarity index 100% rename from docs/pkgs/acme/index.rst rename to acme/docs/api/index.rst diff --git a/docs/pkgs/acme/jose.rst b/acme/docs/api/jose.rst similarity index 100% rename from docs/pkgs/acme/jose.rst rename to acme/docs/api/jose.rst diff --git a/acme/docs/conf.py b/acme/docs/conf.py index dc5dec0ff..1448aaea3 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -16,10 +16,14 @@ import sys import os import shlex + +here = os.path.abspath(os.path.dirname(__file__)) + + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) # -- General configuration ------------------------------------------------ @@ -271,7 +275,8 @@ latex_documents = [ # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'acme-python', u'acme-python Documentation', - [author], 1) + [author], 1), + ('man/jws', 'jws', u'jws script documentation', [project], 1), ] # If true, show URL addresses after external links. diff --git a/acme/docs/index.rst b/acme/docs/index.rst index 357d73fd0..940d79037 100644 --- a/acme/docs/index.rst +++ b/acme/docs/index.rst @@ -11,6 +11,7 @@ Contents: .. toctree:: :maxdepth: 2 + api Indices and tables diff --git a/docs/man/jws.rst b/acme/docs/man/jws.rst similarity index 100% rename from docs/man/jws.rst rename to acme/docs/man/jws.rst diff --git a/docs/conf.py b/docs/conf.py index 2de0dd877..dad4e608f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,13 +17,6 @@ import os import re import sys -import mock - - -# http://docs.readthedocs.org/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules -# c.f. #262 -sys.modules.update( - (mod_name, mock.MagicMock()) for mod_name in ['augeas']) here = os.path.abspath(os.path.dirname(__file__)) @@ -36,8 +29,6 @@ with codecs.open(init_fn, encoding='utf8') as fd: # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) -for pkg in 'acme', 'letsencrypt-apache', 'letsencrypt-nginx': - sys.path.insert(0, os.path.abspath(os.path.join(here, '..', pkg))) # -- General configuration ------------------------------------------------ @@ -292,7 +283,6 @@ man_pages = [ [project], 1), ('man/letsencrypt-renewer', 'letsencrypt-renewer', u'letsencrypt-renewer script documentation', [project], 1), - ('man/jws', 'jws', u'jws script documentation', [project], 1), ] # If true, show URL addresses after external links. diff --git a/docs/contributing.rst b/docs/contributing.rst index 6b6550c71..60e7f35c2 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -84,14 +84,8 @@ run (in a separate terminal):: If you would like to test `letsencrypt_nginx` plugin (highly encouraged) make sure to install prerequisites as listed in -``letsencrypt-nginx/tests/boulder-integration.sh``: - -.. include:: ../letsencrypt-nginx/tests/boulder-integration.sh - :start-line: 1 - :end-line: 2 - :code: shell - -and rerun the integration tests suite. +``letsencrypt-nginx/tests/boulder-integration.sh`` and rerun +the integration tests suite. .. _Boulder: https://github.com/letsencrypt/boulder .. _Go: https://golang.org diff --git a/docs/index.rst b/docs/index.rst index b076b45c6..72be096f9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,7 +13,6 @@ Welcome to the Let's Encrypt client documentation! :maxdepth: 1 api - pkgs Indices and tables diff --git a/docs/pkgs.rst b/docs/pkgs.rst deleted file mode 100644 index 2e1b18dfb..000000000 --- a/docs/pkgs.rst +++ /dev/null @@ -1,14 +0,0 @@ -======== -Packages -======== - -.. note:: It is planned to distribute `acme` and plugins separately as - described in `#358`_. For the time being those packages are bundled - together into a single repo, and single documentation. - -.. _`#358`: https://github.com/letsencrypt/letsencrypt/issues/358 - -.. toctree:: - :glob: - - pkgs/** diff --git a/letsencrypt-apache/docs/api.rst b/letsencrypt-apache/docs/api.rst new file mode 100644 index 000000000..8668ec5d8 --- /dev/null +++ b/letsencrypt-apache/docs/api.rst @@ -0,0 +1,8 @@ +================= +API Documentation +================= + +.. toctree:: + :glob: + + api/** diff --git a/docs/pkgs/letsencrypt_apache.rst b/letsencrypt-apache/docs/api/index.rst similarity index 100% rename from docs/pkgs/letsencrypt_apache.rst rename to letsencrypt-apache/docs/api/index.rst diff --git a/letsencrypt-apache/docs/conf.py b/letsencrypt-apache/docs/conf.py index f578531db..e439428af 100644 --- a/letsencrypt-apache/docs/conf.py +++ b/letsencrypt-apache/docs/conf.py @@ -16,10 +16,20 @@ import sys import os import shlex +import mock + + +# http://docs.readthedocs.org/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules +# c.f. #262 +sys.modules.update( + (mod_name, mock.MagicMock()) for mod_name in ['augeas']) + +here = os.path.abspath(os.path.dirname(__file__)) + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) # -- General configuration ------------------------------------------------ diff --git a/letsencrypt-apache/docs/index.rst b/letsencrypt-apache/docs/index.rst index 64f0e3e14..9be7c20d5 100644 --- a/letsencrypt-apache/docs/index.rst +++ b/letsencrypt-apache/docs/index.rst @@ -12,6 +12,11 @@ Contents: :maxdepth: 2 +.. toctree:: + :maxdepth: 1 + + api + Indices and tables ================== diff --git a/letsencrypt-compatibility-test/docs/api.rst b/letsencrypt-compatibility-test/docs/api.rst new file mode 100644 index 000000000..8668ec5d8 --- /dev/null +++ b/letsencrypt-compatibility-test/docs/api.rst @@ -0,0 +1,8 @@ +================= +API Documentation +================= + +.. toctree:: + :glob: + + api/** diff --git a/docs/pkgs/letsencrypt_compatibility_test.rst b/letsencrypt-compatibility-test/docs/api/index.rst similarity index 100% rename from docs/pkgs/letsencrypt_compatibility_test.rst rename to letsencrypt-compatibility-test/docs/api/index.rst diff --git a/letsencrypt-compatibility-test/docs/conf.py b/letsencrypt-compatibility-test/docs/conf.py index 4ec0a1d9a..5a63c1dca 100644 --- a/letsencrypt-compatibility-test/docs/conf.py +++ b/letsencrypt-compatibility-test/docs/conf.py @@ -16,10 +16,13 @@ import sys import os import shlex + +here = os.path.abspath(os.path.dirname(__file__)) + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) # -- General configuration ------------------------------------------------ diff --git a/letsencrypt-compatibility-test/docs/index.rst b/letsencrypt-compatibility-test/docs/index.rst index 3df442c65..df57ee6e6 100644 --- a/letsencrypt-compatibility-test/docs/index.rst +++ b/letsencrypt-compatibility-test/docs/index.rst @@ -12,6 +12,11 @@ Contents: :maxdepth: 2 +.. toctree:: + :maxdepth: 1 + + api + Indices and tables ================== diff --git a/letsencrypt-nginx/docs/api.rst b/letsencrypt-nginx/docs/api.rst new file mode 100644 index 000000000..8668ec5d8 --- /dev/null +++ b/letsencrypt-nginx/docs/api.rst @@ -0,0 +1,8 @@ +================= +API Documentation +================= + +.. toctree:: + :glob: + + api/** diff --git a/docs/pkgs/letsencrypt_nginx.rst b/letsencrypt-nginx/docs/api/index.rst similarity index 100% rename from docs/pkgs/letsencrypt_nginx.rst rename to letsencrypt-nginx/docs/api/index.rst diff --git a/letsencrypt-nginx/docs/conf.py b/letsencrypt-nginx/docs/conf.py index e8e320542..8bcae3a78 100644 --- a/letsencrypt-nginx/docs/conf.py +++ b/letsencrypt-nginx/docs/conf.py @@ -16,10 +16,13 @@ import sys import os import shlex + +here = os.path.abspath(os.path.dirname(__file__)) + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) # -- General configuration ------------------------------------------------ diff --git a/letsencrypt-nginx/docs/index.rst b/letsencrypt-nginx/docs/index.rst index c4822af52..94db969ab 100644 --- a/letsencrypt-nginx/docs/index.rst +++ b/letsencrypt-nginx/docs/index.rst @@ -12,6 +12,11 @@ Contents: :maxdepth: 2 +.. toctree:: + :maxdepth: 1 + + api + Indices and tables ================== diff --git a/letshelp-letsencrypt/docs/api.rst b/letshelp-letsencrypt/docs/api.rst new file mode 100644 index 000000000..8668ec5d8 --- /dev/null +++ b/letshelp-letsencrypt/docs/api.rst @@ -0,0 +1,8 @@ +================= +API Documentation +================= + +.. toctree:: + :glob: + + api/** diff --git a/docs/pkgs/letshelp_letsencrypt.rst b/letshelp-letsencrypt/docs/api/index.rst similarity index 100% rename from docs/pkgs/letshelp_letsencrypt.rst rename to letshelp-letsencrypt/docs/api/index.rst diff --git a/letshelp-letsencrypt/docs/conf.py b/letshelp-letsencrypt/docs/conf.py index 3561a12d1..abbf3621d 100644 --- a/letshelp-letsencrypt/docs/conf.py +++ b/letshelp-letsencrypt/docs/conf.py @@ -16,10 +16,13 @@ import sys import os import shlex + +here = os.path.abspath(os.path.dirname(__file__)) + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(here, '..'))) # -- General configuration ------------------------------------------------ diff --git a/letshelp-letsencrypt/docs/index.rst b/letshelp-letsencrypt/docs/index.rst index db806d874..6b67a2e1f 100644 --- a/letshelp-letsencrypt/docs/index.rst +++ b/letshelp-letsencrypt/docs/index.rst @@ -12,6 +12,11 @@ Contents: :maxdepth: 2 +.. toctree:: + :maxdepth: 1 + + api + Indices and tables ================== From fe49889b168321093ce7056e4314c751912f7e7d Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 15:42:14 +0000 Subject: [PATCH 81/92] Per subpkg requirements.txt for RTD --- acme/readthedocs.org.requirements.txt | 10 ++++++++++ letsencrypt-apache/readthedocs.org.requirements.txt | 10 ++++++++++ .../readthedocs.org.requirements.txt | 10 ++++++++++ letsencrypt-nginx/readthedocs.org.requirements.txt | 10 ++++++++++ letshelp-letsencrypt/readthedocs.org.requirements.txt | 10 ++++++++++ readthedocs.org.requirements.txt | 5 ----- 6 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 acme/readthedocs.org.requirements.txt create mode 100644 letsencrypt-apache/readthedocs.org.requirements.txt create mode 100644 letsencrypt-compatibility-test/readthedocs.org.requirements.txt create mode 100644 letsencrypt-nginx/readthedocs.org.requirements.txt create mode 100644 letshelp-letsencrypt/readthedocs.org.requirements.txt diff --git a/acme/readthedocs.org.requirements.txt b/acme/readthedocs.org.requirements.txt new file mode 100644 index 000000000..65e6c7cf3 --- /dev/null +++ b/acme/readthedocs.org.requirements.txt @@ -0,0 +1,10 @@ +# readthedocs.org gives no way to change the install command to "pip +# install -e .[docs]" (that would in turn install documentation +# dependencies), but it allows to specify a requirements.txt file at +# https://readthedocs.org/dashboard/letsencrypt/advanced/ (c.f. #259) + +# Although ReadTheDocs certainly doesn't need to install the project +# in --editable mode (-e), just "pip install .[docs]" does not work as +# expected and "pip install -e .[docs]" must be used instead + +-e acme[docs] diff --git a/letsencrypt-apache/readthedocs.org.requirements.txt b/letsencrypt-apache/readthedocs.org.requirements.txt new file mode 100644 index 000000000..9e782a01e --- /dev/null +++ b/letsencrypt-apache/readthedocs.org.requirements.txt @@ -0,0 +1,10 @@ +# readthedocs.org gives no way to change the install command to "pip +# install -e .[docs]" (that would in turn install documentation +# dependencies), but it allows to specify a requirements.txt file at +# https://readthedocs.org/dashboard/letsencrypt/advanced/ (c.f. #259) + +# Although ReadTheDocs certainly doesn't need to install the project +# in --editable mode (-e), just "pip install .[docs]" does not work as +# expected and "pip install -e .[docs]" must be used instead + +-e letsencrypt-apache[docs] diff --git a/letsencrypt-compatibility-test/readthedocs.org.requirements.txt b/letsencrypt-compatibility-test/readthedocs.org.requirements.txt new file mode 100644 index 000000000..86d680426 --- /dev/null +++ b/letsencrypt-compatibility-test/readthedocs.org.requirements.txt @@ -0,0 +1,10 @@ +# readthedocs.org gives no way to change the install command to "pip +# install -e .[docs]" (that would in turn install documentation +# dependencies), but it allows to specify a requirements.txt file at +# https://readthedocs.org/dashboard/letsencrypt/advanced/ (c.f. #259) + +# Although ReadTheDocs certainly doesn't need to install the project +# in --editable mode (-e), just "pip install .[docs]" does not work as +# expected and "pip install -e .[docs]" must be used instead + +-e letsencrypt-compatibility-test[docs] diff --git a/letsencrypt-nginx/readthedocs.org.requirements.txt b/letsencrypt-nginx/readthedocs.org.requirements.txt new file mode 100644 index 000000000..9a36ed259 --- /dev/null +++ b/letsencrypt-nginx/readthedocs.org.requirements.txt @@ -0,0 +1,10 @@ +# readthedocs.org gives no way to change the install command to "pip +# install -e .[docs]" (that would in turn install documentation +# dependencies), but it allows to specify a requirements.txt file at +# https://readthedocs.org/dashboard/letsencrypt/advanced/ (c.f. #259) + +# Although ReadTheDocs certainly doesn't need to install the project +# in --editable mode (-e), just "pip install .[docs]" does not work as +# expected and "pip install -e .[docs]" must be used instead + +-e letsencrypt-nginx[docs] diff --git a/letshelp-letsencrypt/readthedocs.org.requirements.txt b/letshelp-letsencrypt/readthedocs.org.requirements.txt new file mode 100644 index 000000000..898d2716e --- /dev/null +++ b/letshelp-letsencrypt/readthedocs.org.requirements.txt @@ -0,0 +1,10 @@ +# readthedocs.org gives no way to change the install command to "pip +# install -e .[docs]" (that would in turn install documentation +# dependencies), but it allows to specify a requirements.txt file at +# https://readthedocs.org/dashboard/letsencrypt/advanced/ (c.f. #259) + +# Although ReadTheDocs certainly doesn't need to install the project +# in --editable mode (-e), just "pip install .[docs]" does not work as +# expected and "pip install -e .[docs]" must be used instead + +-e letshelp-letsencrypt[docs] diff --git a/readthedocs.org.requirements.txt b/readthedocs.org.requirements.txt index 3c3a3c576..27cccb0a6 100644 --- a/readthedocs.org.requirements.txt +++ b/readthedocs.org.requirements.txt @@ -7,9 +7,4 @@ # in --editable mode (-e), just "pip install .[docs]" does not work as # expected and "pip install -e .[docs]" must be used instead --e acme -e .[docs] --e letsencrypt-apache --e letsencrypt-nginx --e letsencrypt-compatibility-test --e letshelp-letsencrypt From 5b757bdff235d127fd1ec0aa6c01fa85ef5c2a91 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 16:01:27 +0000 Subject: [PATCH 82/92] Split ACME API docs --- acme/docs/api/challenges.rst | 5 ++++ acme/docs/api/client.rst | 5 ++++ acme/docs/api/errors.rst | 5 ++++ acme/docs/api/fields.rst | 5 ++++ acme/docs/api/index.rst | 56 ------------------------------------ acme/docs/api/messages.rst | 5 ++++ acme/docs/api/other.rst | 5 ++++ acme/docs/api/standalone.rst | 5 ++++ acme/docs/index.rst | 3 ++ 9 files changed, 38 insertions(+), 56 deletions(-) create mode 100644 acme/docs/api/challenges.rst create mode 100644 acme/docs/api/client.rst create mode 100644 acme/docs/api/errors.rst create mode 100644 acme/docs/api/fields.rst delete mode 100644 acme/docs/api/index.rst create mode 100644 acme/docs/api/messages.rst create mode 100644 acme/docs/api/other.rst create mode 100644 acme/docs/api/standalone.rst diff --git a/acme/docs/api/challenges.rst b/acme/docs/api/challenges.rst new file mode 100644 index 000000000..7bc084fe9 --- /dev/null +++ b/acme/docs/api/challenges.rst @@ -0,0 +1,5 @@ +Challenges +---------- + +.. automodule:: acme.challenges + :members: diff --git a/acme/docs/api/client.rst b/acme/docs/api/client.rst new file mode 100644 index 000000000..d0ab89eb2 --- /dev/null +++ b/acme/docs/api/client.rst @@ -0,0 +1,5 @@ +Client +------ + +.. automodule:: acme.client + :members: diff --git a/acme/docs/api/errors.rst b/acme/docs/api/errors.rst new file mode 100644 index 000000000..644ff0e71 --- /dev/null +++ b/acme/docs/api/errors.rst @@ -0,0 +1,5 @@ +Errors +------ + +.. automodule:: acme.errors + :members: diff --git a/acme/docs/api/fields.rst b/acme/docs/api/fields.rst new file mode 100644 index 000000000..c224f7fef --- /dev/null +++ b/acme/docs/api/fields.rst @@ -0,0 +1,5 @@ +Fields +------ + +.. automodule:: acme.fields + :members: diff --git a/acme/docs/api/index.rst b/acme/docs/api/index.rst deleted file mode 100644 index 23c5a3284..000000000 --- a/acme/docs/api/index.rst +++ /dev/null @@ -1,56 +0,0 @@ -:mod:`acme` -=========== - -.. contents:: - -.. automodule:: acme - :members: - - -Client ------- - -.. automodule:: acme.client - :members: - - -Messages --------- - -.. automodule:: acme.messages - :members: - - -Challenges ----------- - -.. automodule:: acme.challenges - :members: - - -Other ACME objects ------------------- - -.. automodule:: acme.other - :members: - - -Fields ------- - -.. automodule:: acme.fields - :members: - - -Errors ------- - -.. automodule:: acme.errors - :members: - - -Standalone ----------- - -.. automodule:: acme.standalone - :members: diff --git a/acme/docs/api/messages.rst b/acme/docs/api/messages.rst new file mode 100644 index 000000000..0374a72c8 --- /dev/null +++ b/acme/docs/api/messages.rst @@ -0,0 +1,5 @@ +Messages +-------- + +.. automodule:: acme.messages + :members: diff --git a/acme/docs/api/other.rst b/acme/docs/api/other.rst new file mode 100644 index 000000000..eb27a5d53 --- /dev/null +++ b/acme/docs/api/other.rst @@ -0,0 +1,5 @@ +Other ACME objects +------------------ + +.. automodule:: acme.other + :members: diff --git a/acme/docs/api/standalone.rst b/acme/docs/api/standalone.rst new file mode 100644 index 000000000..a65e5df2a --- /dev/null +++ b/acme/docs/api/standalone.rst @@ -0,0 +1,5 @@ +Standalone +---------- + +.. automodule:: acme.standalone + :members: diff --git a/acme/docs/index.rst b/acme/docs/index.rst index 940d79037..8d298054e 100644 --- a/acme/docs/index.rst +++ b/acme/docs/index.rst @@ -13,6 +13,9 @@ Contents: api +.. automodule:: acme + :members: + Indices and tables ================== From ca464c25fbe15d197938142af690ba6c0d32e379 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 16:10:21 +0000 Subject: [PATCH 83/92] Split JOSE API docs --- acme/docs/api.rst | 2 +- acme/docs/api/jose.rst | 67 +++---------------------------- acme/docs/api/jose/base64.rst | 5 +++ acme/docs/api/jose/errors.rst | 5 +++ acme/docs/api/jose/interfaces.rst | 5 +++ acme/docs/api/jose/json_util.rst | 5 +++ acme/docs/api/jose/jwa.rst | 5 +++ acme/docs/api/jose/jwk.rst | 5 +++ acme/docs/api/jose/jws.rst | 5 +++ acme/docs/api/jose/util.rst | 5 +++ 10 files changed, 46 insertions(+), 63 deletions(-) create mode 100644 acme/docs/api/jose/base64.rst create mode 100644 acme/docs/api/jose/errors.rst create mode 100644 acme/docs/api/jose/interfaces.rst create mode 100644 acme/docs/api/jose/json_util.rst create mode 100644 acme/docs/api/jose/jwa.rst create mode 100644 acme/docs/api/jose/jwk.rst create mode 100644 acme/docs/api/jose/jws.rst create mode 100644 acme/docs/api/jose/util.rst diff --git a/acme/docs/api.rst b/acme/docs/api.rst index 8668ec5d8..c874d8470 100644 --- a/acme/docs/api.rst +++ b/acme/docs/api.rst @@ -5,4 +5,4 @@ API Documentation .. toctree:: :glob: - api/** + api/* diff --git a/acme/docs/api/jose.rst b/acme/docs/api/jose.rst index fa3a0e9bb..0f7dd627c 100644 --- a/acme/docs/api/jose.rst +++ b/acme/docs/api/jose.rst @@ -1,67 +1,10 @@ -:mod:`acme.jose` -================ - -.. contents:: +JOSE +---- .. automodule:: acme.jose :members: +.. toctree:: + :glob: -JSON Web Algorithms -------------------- - -.. automodule:: acme.jose.jwa - :members: - - -JSON Web Key ------------- - -.. automodule:: acme.jose.jwk - :members: - - -JSON Web Signature ------------------- - -.. automodule:: acme.jose.jws - :members: - - -Implementation details ----------------------- - - -Interfaces -~~~~~~~~~~ - -.. automodule:: acme.jose.interfaces - :members: - - -Errors -~~~~~~ - -.. automodule:: acme.jose.errors - :members: - - -JSON utilities -~~~~~~~~~~~~~~ - -.. automodule:: acme.jose.json_util - :members: - - -JOSE Base64 -~~~~~~~~~~~ - -.. automodule:: acme.jose.b64 - :members: - - -Utilities -~~~~~~~~~ - -.. automodule:: acme.jose.util - :members: + jose/* diff --git a/acme/docs/api/jose/base64.rst b/acme/docs/api/jose/base64.rst new file mode 100644 index 000000000..a40f8b11b --- /dev/null +++ b/acme/docs/api/jose/base64.rst @@ -0,0 +1,5 @@ +JOSE Base64 +----------- + +.. automodule:: acme.jose.b64 + :members: diff --git a/acme/docs/api/jose/errors.rst b/acme/docs/api/jose/errors.rst new file mode 100644 index 000000000..60d9b5c78 --- /dev/null +++ b/acme/docs/api/jose/errors.rst @@ -0,0 +1,5 @@ +Errors +------ + +.. automodule:: acme.jose.errors + :members: diff --git a/acme/docs/api/jose/interfaces.rst b/acme/docs/api/jose/interfaces.rst new file mode 100644 index 000000000..7b72b364f --- /dev/null +++ b/acme/docs/api/jose/interfaces.rst @@ -0,0 +1,5 @@ +Interfaces +---------- + +.. automodule:: acme.jose.interfaces + :members: diff --git a/acme/docs/api/jose/json_util.rst b/acme/docs/api/jose/json_util.rst new file mode 100644 index 000000000..f06edead2 --- /dev/null +++ b/acme/docs/api/jose/json_util.rst @@ -0,0 +1,5 @@ +JSON utilities +-------------- + +.. automodule:: acme.jose.json_util + :members: diff --git a/acme/docs/api/jose/jwa.rst b/acme/docs/api/jose/jwa.rst new file mode 100644 index 000000000..c858a5d1d --- /dev/null +++ b/acme/docs/api/jose/jwa.rst @@ -0,0 +1,5 @@ +JSON Web Algorithms +------------------- + +.. automodule:: acme.jose.jwa + :members: diff --git a/acme/docs/api/jose/jwk.rst b/acme/docs/api/jose/jwk.rst new file mode 100644 index 000000000..8e6bbe13f --- /dev/null +++ b/acme/docs/api/jose/jwk.rst @@ -0,0 +1,5 @@ +JSON Web Key +------------ + +.. automodule:: acme.jose.jwk + :members: diff --git a/acme/docs/api/jose/jws.rst b/acme/docs/api/jose/jws.rst new file mode 100644 index 000000000..15335bf8f --- /dev/null +++ b/acme/docs/api/jose/jws.rst @@ -0,0 +1,5 @@ +JSON Web Signature +------------------ + +.. automodule:: acme.jose.jws + :members: diff --git a/acme/docs/api/jose/util.rst b/acme/docs/api/jose/util.rst new file mode 100644 index 000000000..41cbbcc31 --- /dev/null +++ b/acme/docs/api/jose/util.rst @@ -0,0 +1,5 @@ +Utilities +--------- + +.. automodule:: acme.jose.util + :members: From 762e9e578f3f31760e151c00c8d2dff9510ba483 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 16:14:42 +0000 Subject: [PATCH 84/92] Split letsencrypt-apache API docs --- .../docs/api/augeas_configurator.rst | 5 +++ letsencrypt-apache/docs/api/configurator.rst | 5 +++ letsencrypt-apache/docs/api/display_ops.rst | 5 +++ letsencrypt-apache/docs/api/dvsni.rst | 5 +++ letsencrypt-apache/docs/api/index.rst | 42 ------------------- letsencrypt-apache/docs/api/obj.rst | 5 +++ letsencrypt-apache/docs/api/parser.rst | 5 +++ letsencrypt-apache/docs/index.rst | 4 ++ 8 files changed, 34 insertions(+), 42 deletions(-) create mode 100644 letsencrypt-apache/docs/api/augeas_configurator.rst create mode 100644 letsencrypt-apache/docs/api/configurator.rst create mode 100644 letsencrypt-apache/docs/api/display_ops.rst create mode 100644 letsencrypt-apache/docs/api/dvsni.rst delete mode 100644 letsencrypt-apache/docs/api/index.rst create mode 100644 letsencrypt-apache/docs/api/obj.rst create mode 100644 letsencrypt-apache/docs/api/parser.rst diff --git a/letsencrypt-apache/docs/api/augeas_configurator.rst b/letsencrypt-apache/docs/api/augeas_configurator.rst new file mode 100644 index 000000000..3b1821e3d --- /dev/null +++ b/letsencrypt-apache/docs/api/augeas_configurator.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_apache.augeas_configurator` +--------------------------------------------- + +.. automodule:: letsencrypt_apache.augeas_configurator + :members: diff --git a/letsencrypt-apache/docs/api/configurator.rst b/letsencrypt-apache/docs/api/configurator.rst new file mode 100644 index 000000000..2ed613286 --- /dev/null +++ b/letsencrypt-apache/docs/api/configurator.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_apache.configurator` +-------------------------------------- + +.. automodule:: letsencrypt_apache.configurator + :members: diff --git a/letsencrypt-apache/docs/api/display_ops.rst b/letsencrypt-apache/docs/api/display_ops.rst new file mode 100644 index 000000000..59ff9d15e --- /dev/null +++ b/letsencrypt-apache/docs/api/display_ops.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_apache.display_ops` +------------------------------------- + +.. automodule:: letsencrypt_apache.display_ops + :members: diff --git a/letsencrypt-apache/docs/api/dvsni.rst b/letsencrypt-apache/docs/api/dvsni.rst new file mode 100644 index 000000000..945771db8 --- /dev/null +++ b/letsencrypt-apache/docs/api/dvsni.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_apache.dvsni` +------------------------------- + +.. automodule:: letsencrypt_apache.dvsni + :members: diff --git a/letsencrypt-apache/docs/api/index.rst b/letsencrypt-apache/docs/api/index.rst deleted file mode 100644 index c4e7e8e6e..000000000 --- a/letsencrypt-apache/docs/api/index.rst +++ /dev/null @@ -1,42 +0,0 @@ -:mod:`letsencrypt_apache` -------------------------- - -.. automodule:: letsencrypt_apache - :members: - -:mod:`letsencrypt_apache.configurator` -====================================== - -.. automodule:: letsencrypt_apache.configurator - :members: - -:mod:`letsencrypt_apache.display_ops` -===================================== - -.. automodule:: letsencrypt_apache.display_ops - :members: - -:mod:`letsencrypt_apache.dvsni` -=============================== - -.. automodule:: letsencrypt_apache.dvsni - :members: - -:mod:`letsencrypt_apache.obj` -============================= - -.. automodule:: letsencrypt_apache.obj - :members: - -:mod:`letsencrypt_apache.parser` -================================ - -.. automodule:: letsencrypt_apache.parser - :members: - - -:mod:`letsencrypt_apache.augeas_configurator` -============================================= - -.. automodule:: letsencrypt_apache.augeas_configurator - :members: diff --git a/letsencrypt-apache/docs/api/obj.rst b/letsencrypt-apache/docs/api/obj.rst new file mode 100644 index 000000000..969293ca1 --- /dev/null +++ b/letsencrypt-apache/docs/api/obj.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_apache.obj` +----------------------------- + +.. automodule:: letsencrypt_apache.obj + :members: diff --git a/letsencrypt-apache/docs/api/parser.rst b/letsencrypt-apache/docs/api/parser.rst new file mode 100644 index 000000000..0c998e06c --- /dev/null +++ b/letsencrypt-apache/docs/api/parser.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_apache.parser` +-------------------------------- + +.. automodule:: letsencrypt_apache.parser + :members: diff --git a/letsencrypt-apache/docs/index.rst b/letsencrypt-apache/docs/index.rst index 9be7c20d5..f968ccbef 100644 --- a/letsencrypt-apache/docs/index.rst +++ b/letsencrypt-apache/docs/index.rst @@ -18,6 +18,10 @@ Contents: api +.. automodule:: letsencrypt_apache + :members: + + Indices and tables ================== From a1847362d530b6d0257ef7939a89cac5ec46c578 Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 18 Oct 2015 16:17:11 +0000 Subject: [PATCH 85/92] Split letsencrypt-nginx API docs --- letsencrypt-nginx/docs/api/dvsni.rst | 5 ++++ letsencrypt-nginx/docs/api/index.rst | 35 ---------------------- letsencrypt-nginx/docs/api/nginxparser.rst | 5 ++++ letsencrypt-nginx/docs/api/obj.rst | 5 ++++ letsencrypt-nginx/docs/api/parser.rst | 5 ++++ letsencrypt-nginx/docs/index.rst | 4 +++ 6 files changed, 24 insertions(+), 35 deletions(-) create mode 100644 letsencrypt-nginx/docs/api/dvsni.rst delete mode 100644 letsencrypt-nginx/docs/api/index.rst create mode 100644 letsencrypt-nginx/docs/api/nginxparser.rst create mode 100644 letsencrypt-nginx/docs/api/obj.rst create mode 100644 letsencrypt-nginx/docs/api/parser.rst diff --git a/letsencrypt-nginx/docs/api/dvsni.rst b/letsencrypt-nginx/docs/api/dvsni.rst new file mode 100644 index 000000000..4f5f9d7e3 --- /dev/null +++ b/letsencrypt-nginx/docs/api/dvsni.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_nginx.dvsni` +------------------------------ + +.. automodule:: letsencrypt_nginx.dvsni + :members: diff --git a/letsencrypt-nginx/docs/api/index.rst b/letsencrypt-nginx/docs/api/index.rst deleted file mode 100644 index 03114b685..000000000 --- a/letsencrypt-nginx/docs/api/index.rst +++ /dev/null @@ -1,35 +0,0 @@ -:mod:`letsencrypt_nginx` ------------------------- - -.. automodule:: letsencrypt_nginx - :members: - -:mod:`letsencrypt_nginx.configurator` -===================================== - -.. automodule:: letsencrypt_nginx.configurator - :members: - -:mod:`letsencrypt_nginx.dvsni` -============================== - -.. automodule:: letsencrypt_nginx.dvsni - :members: - -:mod:`letsencrypt_nginx.obj` -============================ - -.. automodule:: letsencrypt_nginx.obj - :members: - -:mod:`letsencrypt_nginx.parser` -=============================== - -.. automodule:: letsencrypt_nginx.parser - :members: - -:mod:`letsencrypt_nginx.nginxparser` -==================================== - -.. automodule:: letsencrypt_nginx.nginxparser - :members: diff --git a/letsencrypt-nginx/docs/api/nginxparser.rst b/letsencrypt-nginx/docs/api/nginxparser.rst new file mode 100644 index 000000000..e55bda0b1 --- /dev/null +++ b/letsencrypt-nginx/docs/api/nginxparser.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_nginx.nginxparser` +------------------------------------ + +.. automodule:: letsencrypt_nginx.nginxparser + :members: diff --git a/letsencrypt-nginx/docs/api/obj.rst b/letsencrypt-nginx/docs/api/obj.rst new file mode 100644 index 000000000..418b87cf7 --- /dev/null +++ b/letsencrypt-nginx/docs/api/obj.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_nginx.obj` +---------------------------- + +.. automodule:: letsencrypt_nginx.obj + :members: diff --git a/letsencrypt-nginx/docs/api/parser.rst b/letsencrypt-nginx/docs/api/parser.rst new file mode 100644 index 000000000..6582263ef --- /dev/null +++ b/letsencrypt-nginx/docs/api/parser.rst @@ -0,0 +1,5 @@ +:mod:`letsencrypt_nginx.parser` +------------------------------- + +.. automodule:: letsencrypt_nginx.parser + :members: diff --git a/letsencrypt-nginx/docs/index.rst b/letsencrypt-nginx/docs/index.rst index 94db969ab..e4f8f715f 100644 --- a/letsencrypt-nginx/docs/index.rst +++ b/letsencrypt-nginx/docs/index.rst @@ -18,6 +18,10 @@ Contents: api +.. automodule:: letsencrypt_nginx + :members: + + Indices and tables ================== From 1964bdeb78d69e7de7b36f58c0b39c2655037d37 Mon Sep 17 00:00:00 2001 From: Harlan Lieberman-Berg Date: Wed, 21 Oct 2015 19:36:07 -0400 Subject: [PATCH 86/92] Correct minor syntax error in docs/conf.py. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index dad4e608f..124f0f9ad 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -314,6 +314,6 @@ texinfo_documents = [ intersphinx_mapping = { - 'python': ('https://docs.python.org/': None), + 'python': ('https://docs.python.org/', None), 'acme': ('https://acme-python.readthedocs.org', None), } From ccfeeb9fe534823ea8566702bd00bcdea0faf8ba Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 21:00:30 -0700 Subject: [PATCH 87/92] Fix test cases; along the way, have --csr save fullchain.pem --- letsencrypt/cli.py | 32 ++++++++++++++++++++------------ letsencrypt/client.py | 23 +++++++++++++++++------ letsencrypt/tests/cli_test.py | 18 ++++++++++-------- letsencrypt/tests/client_test.py | 8 ++++++-- 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 31891dd5d..3b5339a1a 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -267,21 +267,29 @@ def _treat_as_renewal(config, domains): return None -def _report_new_cert(lineage): +def _report_new_cert(cert_path, fullchain_path): """ Reports the creation of a new certificate to the user. - :param RenewableCert lineage: the lineage of the new cert + :param string cert_path: path to cert + :param string fullchain_path: path to full chain """ - expiry = crypto_util.notAfter(lineage.cert).date() + expiry = crypto_util.notAfter(cert_path).date() reporter_util = zope.component.getUtility(interfaces.IReporter) - # Tell the user about fullchain.pem because that's what modern webservers - # (Nginx and Apache2.4) will want. + if fullchain_path: + # Print the path to fullchain.pem because that's what modern webservers + # (Nginx and Apache2.4) will want. + and_chain = "and chain have" + path = fullchain_path + else: + # Unless we're in .csr mode and there really isn't one + and_chain = "has " + path = cert_path # XXX Perhaps one day we could detect the presence of known old webservers # and say something more informative here. - msg = ("Congratulations! Your certificate and chain have been saved at {0}." - " Your cert will expire on {1}. To obtain a new version of the " + msg = ("Congratulations! Your certificate {0} been saved at {1}." + " Your cert will expire on {2}. To obtain a new version of the " "certificate in the future, simply run Let's Encrypt again." - .format(lineage.fullchain, expiry)) + .format(and_chain, path, expiry)) reporter_util.add_message(msg, reporter_util.MEDIUM_PRIORITY) @@ -310,7 +318,7 @@ def _auth_from_domains(le_client, config, domains, plugins): if not lineage: raise Error("Certificate could not be obtained") - _report_new_cert(lineage) + _report_new_cert(lineage.cert, lineage.fullchain) return lineage @@ -461,9 +469,9 @@ def auth(args, config, plugins): if args.csr is not None: certr, chain = le_client.obtain_certificate_from_csr(le_util.CSR( file=args.csr[0], data=args.csr[1], form="der")) - cert_path, _ = le_client.save_certificate( - certr, chain, args.cert_path, args.chain_path) - _report_new_cert(cert_path) + cert_path, _, cert_fullchain = le_client.save_certificate( + certr, chain, args.cert_path, args.chain_path, args.fullchain_path) + _report_new_cert(cert_path, cert_fullchain) else: domains = _find_domains(args, installer) _auth_from_domains(le_client, config, domains, plugins) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index 732bdcf03..a7a4847b2 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -258,7 +258,7 @@ class Client(object): params, config, cli_config) return lineage - def save_certificate(self, certr, chain_cert, cert_path, chain_path): + def save_certificate(self, certr, chain_cert, cert_path, chain_path, fullchain_path): # pylint: disable=no-self-use """Saves the certificate received from the ACME server. @@ -268,20 +268,22 @@ class Client(object): :param list chain_cert: :param str cert_path: Candidate path to a certificate. :param str chain_path: Candidate path to a certificate chain. + :param str fullchain_path: Candidate path to a full cert chain. - :returns: cert_path, chain_path (absolute paths to the actual files) + :returns: cert_path, chain_path, fullchain_path (absolute paths to the actual files) :rtype: `tuple` of `str` :raises IOError: If unable to find room to write the cert files """ - for path in cert_path, chain_path: + for path in cert_path, chain_path, fullchain_path: le_util.make_or_verify_dir( os.path.dirname(path), 0o755, os.geteuid(), self.config.strict_permissions) # try finally close cert_chain_abspath = None + fullchain_abspath = None cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) # TODO: Except cert_pem = OpenSSL.crypto.dump_certificate( @@ -294,8 +296,7 @@ class Client(object): act_cert_path) if chain_cert: - chain_file, act_chain_path = le_util.unique_file( - chain_path, 0o644) + chain_file, act_chain_path = le_util.unique_file(chain_path, 0o644) # TODO: Except chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert) try: @@ -308,7 +309,17 @@ class Client(object): # This expects a valid chain file cert_chain_abspath = os.path.abspath(act_chain_path) - return os.path.abspath(act_cert_path), cert_chain_abspath + # fullchain is cert + chain + fullchain_file, act_fullchain_path = le_util.unique_file( + fullchain_path, 0o644) + try: + fullchain_file.write(cert_pem + chain_pem) + finally: + fullchain_file.close() + logger.info("Cert chain written to %s", act_fullchain_path) + fullchain_abspath = os.path.abspath(act_fullchain_path) + + return os.path.abspath(act_cert_path), cert_chain_abspath, fullchain_abspath def deploy_certificate(self, domains, privkey_path, cert_path, chain_path, fullchain_path): diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 9d9164f24..73ab84bdf 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -149,7 +149,7 @@ class CLITest(unittest.TestCase): date = '1970-01-01' mock_notAfter().date.return_value = date - mock_lineage = mock.MagicMock(cert=cert_path) + mock_lineage = mock.MagicMock(cert=cert_path, fullchain=cert_path) mock_client = mock.MagicMock() mock_client.obtain_and_enroll_certificate.return_value = mock_lineage self._auth_new_request_common(mock_client) @@ -177,9 +177,10 @@ class CLITest(unittest.TestCase): @mock.patch('letsencrypt.cli._treat_as_renewal') @mock.patch('letsencrypt.cli._init_le_client') def test_auth_renewal(self, mock_init, mock_renewal, mock_get_utility): - cert_path = '/etc/letsencrypt/live/foo.bar' + cert_path = '/etc/letsencrypt/live/foo.bar/cert.pem' + chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem' - mock_lineage = mock.MagicMock(cert=cert_path) + mock_lineage = mock.MagicMock(cert=cert_path,fullchain=chain_path) mock_cert = mock.MagicMock(body='body') mock_key = mock.MagicMock(pem='pem_key') mock_renewal.return_value = mock_lineage @@ -195,7 +196,7 @@ class CLITest(unittest.TestCase): mock_lineage.update_all_links_to.assert_called_once_with( mock_lineage.latest_common_version()) self.assertTrue( - cert_path in mock_get_utility().add_message.call_args[0][0]) + chain_path in mock_get_utility().add_message.call_args[0][0]) @mock.patch('letsencrypt.crypto_util.notAfter') @mock.patch('letsencrypt.cli.display_ops.pick_installer') @@ -203,23 +204,24 @@ class CLITest(unittest.TestCase): @mock.patch('letsencrypt.cli._init_le_client') def test_auth_csr(self, mock_init, mock_get_utility, mock_pick_installer, mock_notAfter): - cert_path = '/etc/letsencrypt/live/foo.bar' + cert_path = '/etc/letsencrypt/live/blahcert.pem' date = '1970-01-01' mock_notAfter().date.return_value = date mock_client = mock.MagicMock() mock_client.obtain_certificate_from_csr.return_value = ('certr', 'chain') - mock_client.save_certificate.return_value = cert_path, None + mock_client.save_certificate.return_value = cert_path, None, None mock_init.return_value = mock_client installer = 'installer' self._call( ['-a', 'standalone', '-i', installer, 'auth', '--csr', CSR, - '--cert-path', cert_path, '--chain-path', '/']) + '--cert-path', cert_path, '--fullchain-path', '/', + '--chain-path', '/']) self.assertEqual(mock_pick_installer.call_args[0][1], installer) mock_client.save_certificate.assert_called_once_with( - 'certr', 'chain', cert_path, '/') + 'certr', 'chain', cert_path, '/', '/') self.assertTrue( cert_path in mock_get_utility().add_message.call_args[0][0]) self.assertTrue( diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index 3f7b84a64..249778964 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -124,14 +124,18 @@ class ClientTest(unittest.TestCase): cert2 = test_util.load_cert(certs[2]) candidate_cert_path = os.path.join(tmp_path, "certs", "cert.pem") candidate_chain_path = os.path.join(tmp_path, "chains", "chain.pem") + candidate_fullchain_path = os.path.join(tmp_path, "chains", "fullchain.pem") - cert_path, chain_path = self.client.save_certificate( - certr, [cert1, cert2], candidate_cert_path, candidate_chain_path) + cert_path, chain_path, fullchain_path = self.client.save_certificate( + certr, [cert1, cert2], candidate_cert_path, candidate_chain_path, + candidate_fullchain_path) self.assertEqual(os.path.dirname(cert_path), os.path.dirname(candidate_cert_path)) self.assertEqual(os.path.dirname(chain_path), os.path.dirname(candidate_chain_path)) + self.assertEqual(os.path.dirname(fullchain_path), + os.path.dirname(candidate_fullchain_path)) with open(cert_path, "r") as cert_file: cert_contents = cert_file.read() From cf5cb9d3ff139da5090891e43f1b9cf3808f9c5e Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 21:15:19 -0700 Subject: [PATCH 88/92] Satisfy pylint... sort of --- letsencrypt/client.py | 5 ++++- letsencrypt/tests/cli_test.py | 2 +- letsencrypt/tests/client_test.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index a7a4847b2..31597c7d3 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -259,7 +259,7 @@ class Client(object): return lineage def save_certificate(self, certr, chain_cert, cert_path, chain_path, fullchain_path): - # pylint: disable=no-self-use + # pylint: disable=no-self-use,too-many-locals """Saves the certificate received from the ACME server. :param certr: ACME "certificate" resource. @@ -295,6 +295,9 @@ class Client(object): logger.info("Server issued certificate; certificate written to %s", act_cert_path) + # TODO too long, refactor... either split this into another function + # up one level (though it needs a copy of cert_pem) or find a way to + # reuse machinery from storage.py if chain_cert: chain_file, act_chain_path = le_util.unique_file(chain_path, 0o644) # TODO: Except diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 73ab84bdf..8e9172055 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -180,7 +180,7 @@ class CLITest(unittest.TestCase): cert_path = '/etc/letsencrypt/live/foo.bar/cert.pem' chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem' - mock_lineage = mock.MagicMock(cert=cert_path,fullchain=chain_path) + mock_lineage = mock.MagicMock(cert=cert_path, fullchain=chain_path) mock_cert = mock.MagicMock(body='body') mock_key = mock.MagicMock(pem='pem_key') mock_renewal.return_value = mock_lineage diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index 249778964..13613374f 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -114,7 +114,7 @@ class ClientTest(unittest.TestCase): mock.sentinel.key, domains, self.config.csr_dir) self._check_obtain_certificate() - def test_save_certificate(self): + def test_save_certificate(self): # pylint: disable=too-many-locals certs = ["matching_cert.pem", "cert.pem", "cert-san.pem"] tmp_path = tempfile.mkdtemp() os.chmod(tmp_path, 0o755) # TODO: really?? From 8a09e616c2e056f772c3e96ed2bd1d63e7519da7 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 22:58:18 -0700 Subject: [PATCH 89/92] its it's --- README.rst | 2 +- letsencrypt-auto | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4040ca284..769bc7a8f 100644 --- a/README.rst +++ b/README.rst @@ -80,7 +80,7 @@ Current Features - apache/2.x (tested and working on Ubuntu Linux) - nginx/0.8.48+ (under development) - - standalone (runs it's own simple webserver to prove you control a domain) + - standalone (runs its own simple webserver to prove you control a domain) * The private key is generated locally on your system. * Can talk to the Let's Encrypt (demo) CA or optionally to other ACME diff --git a/letsencrypt-auto b/letsencrypt-auto index e7c9d6737..5b974c1f8 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -1,5 +1,8 @@ #!/bin/sh -e # +# A script to run the latest release version of the Let's Encrypt in a +# virtual environment +# # Installs and updates the letencrypt virtualenv, and runs letsencrypt # using that virtual environment. This allows the client to function decently # without requiring specific versions of its dependencies from the operating From 1c215d0c671fb301341045456b8e709ea95fe509 Mon Sep 17 00:00:00 2001 From: Peter Eckersley Date: Wed, 21 Oct 2015 23:10:55 -0700 Subject: [PATCH 90/92] Sphinxify also pythonic str instead of string --- letsencrypt/cli.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 3b5339a1a..3ae58d12a 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -270,8 +270,9 @@ def _treat_as_renewal(config, domains): def _report_new_cert(cert_path, fullchain_path): """ Reports the creation of a new certificate to the user. - :param string cert_path: path to cert - :param string fullchain_path: path to full chain + + :param str cert_path: path to cert + :param str fullchain_path: path to full chain """ expiry = crypto_util.notAfter(cert_path).date() reporter_util = zope.component.getUtility(interfaces.IReporter) @@ -326,8 +327,8 @@ def _auth_from_domains(le_client, config, domains, plugins): def set_configurator(previously, now): """ Setting configurators multiple ways is okay, as long as they all agree - :param string previously: previously identified request for the installer/authenticator - :param string requested: the request currently being processed + :param str previously: previously identified request for the installer/authenticator + :param str requested: the request currently being processed """ if now is None: # we're not actually setting anything @@ -343,8 +344,8 @@ def diagnose_configurator_problem(cfg_type, requested, plugins): """ Raise the most helpful error message about a plugin being unavailable - :param string cfg_type: either "installer" or "authenticator" - :param string requested: the plugin that was requested + :param str cfg_type: either "installer" or "authenticator" + :param str requested: the plugin that was requested :param PluginRegistry plugins: available plugins :raises error.PluginSelectionError: if there was a problem From e4a0eee66296aaa07ff6c8b5c3703cca0133f4fa Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 21 Oct 2015 23:25:05 -0700 Subject: [PATCH 91/92] Satisfied spacing OCD --- letsencrypt/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index 3ae58d12a..5163f2868 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -268,11 +268,11 @@ def _treat_as_renewal(config, domains): def _report_new_cert(cert_path, fullchain_path): - """ - Reports the creation of a new certificate to the user. + """Reports the creation of a new certificate to the user. :param str cert_path: path to cert :param str fullchain_path: path to full chain + """ expiry = crypto_util.notAfter(cert_path).date() reporter_util = zope.component.getUtility(interfaces.IReporter) From f13566e5ba29edfad9879bc5eacb1e78eb435ec7 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 22 Oct 2015 00:35:52 -0700 Subject: [PATCH 92/92] Quick refactor --- letsencrypt/client.py | 64 ++++++++++++++++---------------- letsencrypt/tests/client_test.py | 8 ++-- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index 31597c7d3..3a6d90472 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -258,8 +258,8 @@ class Client(object): params, config, cli_config) return lineage - def save_certificate(self, certr, chain_cert, cert_path, chain_path, fullchain_path): - # pylint: disable=no-self-use,too-many-locals + def save_certificate(self, certr, chain_cert, + cert_path, chain_path, fullchain_path): """Saves the certificate received from the ACME server. :param certr: ACME "certificate" resource. @@ -270,7 +270,8 @@ class Client(object): :param str chain_path: Candidate path to a certificate chain. :param str fullchain_path: Candidate path to a full cert chain. - :returns: cert_path, chain_path, fullchain_path (absolute paths to the actual files) + :returns: cert_path, chain_path, and fullchain_path as absolute + paths to the actual files :rtype: `tuple` of `str` :raises IOError: If unable to find room to write the cert files @@ -281,13 +282,9 @@ class Client(object): os.path.dirname(path), 0o755, os.geteuid(), self.config.strict_permissions) - # try finally close - cert_chain_abspath = None - fullchain_abspath = None - cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) - # TODO: Except cert_pem = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, certr.body) + cert_file, act_cert_path = le_util.unique_file(cert_path, 0o644) try: cert_file.write(cert_pem) finally: @@ -295,32 +292,13 @@ class Client(object): logger.info("Server issued certificate; certificate written to %s", act_cert_path) - # TODO too long, refactor... either split this into another function - # up one level (though it needs a copy of cert_pem) or find a way to - # reuse machinery from storage.py + cert_chain_abspath = None + fullchain_abspath = None if chain_cert: - chain_file, act_chain_path = le_util.unique_file(chain_path, 0o644) - # TODO: Except chain_pem = crypto_util.dump_pyopenssl_chain(chain_cert) - try: - chain_file.write(chain_pem) - finally: - chain_file.close() - - logger.info("Cert chain written to %s", act_chain_path) - - # This expects a valid chain file - cert_chain_abspath = os.path.abspath(act_chain_path) - - # fullchain is cert + chain - fullchain_file, act_fullchain_path = le_util.unique_file( - fullchain_path, 0o644) - try: - fullchain_file.write(cert_pem + chain_pem) - finally: - fullchain_file.close() - logger.info("Cert chain written to %s", act_fullchain_path) - fullchain_abspath = os.path.abspath(act_fullchain_path) + cert_chain_abspath = _save_chain(chain_pem, chain_path) + fullchain_abspath = _save_chain(cert_pem + chain_pem, + fullchain_path) return os.path.abspath(act_cert_path), cert_chain_abspath, fullchain_abspath @@ -479,3 +457,25 @@ def view_config_changes(config): rev = reverter.Reverter(config) rev.recovery_routine() rev.view_config_changes() + + +def _save_chain(chain_pem, chain_path): + """Saves chain_pem at a unique path based on chain_path. + + :param str chain_pem: certificate chain in PEM format + :param str chain_path: candidate path for the cert chain + + :returns: absolute path to saved cert chain + :rtype: str + + """ + chain_file, act_chain_path = le_util.unique_file(chain_path, 0o644) + try: + chain_file.write(chain_pem) + finally: + chain_file.close() + + logger.info("Cert chain written to %s", act_chain_path) + + # This expects a valid chain file + return os.path.abspath(act_chain_path) diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index 13613374f..2efe11108 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -114,20 +114,20 @@ class ClientTest(unittest.TestCase): mock.sentinel.key, domains, self.config.csr_dir) self._check_obtain_certificate() - def test_save_certificate(self): # pylint: disable=too-many-locals + def test_save_certificate(self): certs = ["matching_cert.pem", "cert.pem", "cert-san.pem"] tmp_path = tempfile.mkdtemp() os.chmod(tmp_path, 0o755) # TODO: really?? certr = mock.MagicMock(body=test_util.load_cert(certs[0])) - cert1 = test_util.load_cert(certs[1]) - cert2 = test_util.load_cert(certs[2]) + chain_cert = [test_util.load_cert(certs[1]), + test_util.load_cert(certs[2])] candidate_cert_path = os.path.join(tmp_path, "certs", "cert.pem") candidate_chain_path = os.path.join(tmp_path, "chains", "chain.pem") candidate_fullchain_path = os.path.join(tmp_path, "chains", "fullchain.pem") cert_path, chain_path, fullchain_path = self.client.save_certificate( - certr, [cert1, cert2], candidate_cert_path, candidate_chain_path, + certr, chain_cert, candidate_cert_path, candidate_chain_path, candidate_fullchain_path) self.assertEqual(os.path.dirname(cert_path),