Mercurial > piecrust2
changeset 917:33a89139c284
serve: Add `--admin` option to run the administration panel.
- Removed the `admin run` command.
- Cleaned up middlewares a bit.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Fri, 29 Sep 2017 08:42:38 -0700 |
parents | 84ce51430346 |
children | 7f1da7e7b154 |
files | piecrust/commands/builtin/admin.py piecrust/commands/builtin/serving.py piecrust/serving/middlewares.py piecrust/serving/server.py piecrust/serving/wrappers.py |
diffstat | 5 files changed, 122 insertions(+), 127 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/commands/builtin/admin.py Wed Sep 27 19:07:55 2017 -0700 +++ b/piecrust/commands/builtin/admin.py Fri Sep 29 08:42:38 2017 -0700 @@ -1,7 +1,7 @@ import os import os.path import logging -from piecrust import CACHE_DIR, CONFIG_PATH +from piecrust import CONFIG_PATH from piecrust.commands.base import ChefCommand from piecrust.pathutil import SiteNotFoundError @@ -24,39 +24,6 @@ help="Creates a new administration panel website.") p.set_defaults(sub_func=self._initAdminSite) - p = subparsers.add_parser( - 'genpass', - help=("Generates the hashed password for use as an " - "admin password")) - p.add_argument('password', help="The password to hash.") - p.set_defaults(sub_func=self._generatePassword) - - p = subparsers.add_parser( - 'run', - help="Runs the administrative panel website.") - p.add_argument( - '-p', '--port', - help="The port for the administrative panel website.", - default=8090) - p.add_argument( - '-a', '--address', - help="The host for the administrative panel website.", - default='localhost') - p.add_argument( - '--no-assets', - help="Don't process and monitor the asset folder(s).", - dest='monitor_assets', - action='store_false') - p.add_argument( - '--use-reloader', - help="Restart the server when PieCrust code changes", - action='store_true') - p.add_argument( - '--use-debugger', - help="Show the debugger when an error occurs", - action='store_true') - p.set_defaults(sub_func=self._runAdminSite) - def checkedRun(self, ctx): if ctx.app.root_dir is None: raise SiteNotFoundError(theme=ctx.app.theme_site) @@ -66,33 +33,6 @@ return return ctx.args.sub_func(ctx) - def _runAdminSite(self, ctx): - # See `_run_sse_check` in `piecrust.serving.wrappers` for an - # explanation of this check. - if (ctx.args.monitor_assets and ( - not (ctx.args.debug or ctx.args.use_reloader) or - os.environ.get('WERKZEUG_RUN_MAIN') == 'true')): - from piecrust.serving.procloop import ProcessingLoop - out_dir = os.path.join( - ctx.app.root_dir, CACHE_DIR, 'admin', 'server') - proc_loop = ProcessingLoop(ctx.appfactory, out_dir) - proc_loop.start() - - es = { - 'FOODTRUCK_CMDLINE_MODE': True, - 'FOODTRUCK_ROOT': ctx.app.root_dir, - 'FOODTRUCK_URL_PREFIX': '', - 'SECRET_KEY': os.urandom(22), - 'LOGIN_DISABLED': True} - if ctx.args.debug or ctx.args.use_debugger: - es['DEBUG'] = True - - run_foodtruck( - host=ctx.args.address, - port=ctx.args.port, - use_reloader=ctx.args.use_reloader, - extra_settings=es) - def _initAdminSite(self, ctx): import io import getpass @@ -138,30 +78,3 @@ hashpw = bcrypt.hashpw(binpw, bcrypt.gensalt()).decode('utf8') logger.info(hashpw) - -def run_foodtruck(host=None, port=None, use_reloader=False, - extra_settings=None): - es = {} - if extra_settings: - es.update(extra_settings) - - # Disable PIN protection with Werkzeug's debugger. - os.environ['WERKZEUG_DEBUG_PIN'] = 'off' - - try: - from piecrust.admin.web import create_foodtruck_app - app = create_foodtruck_app(es) - app.run(host=host, port=port, use_reloader=use_reloader, - threaded=True) - except SystemExit: - # This is needed for Werkzeug's code reloader to be able to correctly - # shutdown the child process in order to restart it (otherwise, SSE - # generators will keep it alive). - try: - from . import pubutil - logger.debug("Shutting down SSE generators from main...") - pubutil.server_shutdown = True - except ImportError: - pass - raise -
--- a/piecrust/commands/builtin/serving.py Wed Sep 27 19:07:55 2017 -0700 +++ b/piecrust/commands/builtin/serving.py Fri Sep 29 08:42:38 2017 -0700 @@ -40,28 +40,15 @@ default='werkzeug') def run(self, ctx): + appfactory = ctx.appfactory host = ctx.args.address port = int(ctx.args.port) - debug = ctx.args.debug or ctx.args.use_debugger - appfactory = ctx.appfactory - - if ctx.args.wsgi == 'werkzeug': - from piecrust.serving.wrappers import run_werkzeug_server - run_werkzeug_server( - appfactory, host, port, - serve_admin=ctx.args.admin, - use_debugger=debug, - use_reloader=ctx.args.use_reloader) + use_debugger = ctx.args.debug or ctx.args.use_debugger - elif ctx.args.wsgi == 'gunicorn': - from piecrust.serving.wrappers import run_gunicorn_server - options = { - 'bind': '%s:%s' % (host, port), - 'accesslog': '-', # print access log to stderr - } - if debug: - options['loglevel'] = 'debug' - if ctx.args.use_reloader: - options['reload'] = True - run_gunicorn_server(appfactory, gunicorn_options=options) - + from piecrust.serving.wrappers import run_piecrust_server + run_piecrust_server( + ctx.args.wsgi, appfactory, host, port, + is_cmdline_mode=True, + serve_admin=ctx.args.admin, + use_reloader=ctx.args.use_reloader, + use_debugger=use_debugger)
--- a/piecrust/serving/middlewares.py Wed Sep 27 19:07:55 2017 -0700 +++ b/piecrust/serving/middlewares.py Fri Sep 29 08:42:38 2017 -0700 @@ -12,7 +12,7 @@ make_wrapped_file_response, get_requested_page, get_app_for_server) -class StaticResourcesMiddleware(object): +class PieCrustStaticResourcesMiddleware(object): """ WSGI middleware that serves static files from the `resources/server` directory in the PieCrust package. """ @@ -38,7 +38,8 @@ class PieCrustDebugMiddleware(object): - """ WSGI middleware that handles debugging of PieCrust stuff. + """ WSGI middleware that handles debugging of PieCrust stuff, and runs + the asset pipeline in an SSE thread. """ def __init__(self, app, appfactory, run_sse_check=None):
--- a/piecrust/serving/server.py Wed Sep 27 19:07:55 2017 -0700 +++ b/piecrust/serving/server.py Fri Sep 29 08:42:38 2017 -0700 @@ -21,11 +21,11 @@ logger = logging.getLogger(__name__) -class WsgiServer(object): +class PieCrustServer(object): """ A WSGI application that serves a PieCrust website. """ def __init__(self, appfactory, **kwargs): - self.server = Server(appfactory, **kwargs) + self.server = _ServerImpl(appfactory, **kwargs) def __call__(self, environ, start_response): return self.server._run_request(environ, start_response) @@ -52,7 +52,7 @@ return desc -class Server(object): +class _ServerImpl(object): """ The PieCrust server. """ def __init__(self, appfactory,
--- a/piecrust/serving/wrappers.py Wed Sep 27 19:07:55 2017 -0700 +++ b/piecrust/serving/wrappers.py Fri Sep 29 08:42:38 2017 -0700 @@ -6,8 +6,41 @@ logger = logging.getLogger(__name__) -def run_werkzeug_server(appfactory, host, port, - use_debugger=False, use_reloader=False): +def run_piecrust_server(wsgi, appfactory, host, port, + is_cmdline_mode=False, + serve_admin=False, + use_debugger=False, + use_reloader=False): + + if wsgi == 'werkzeug': + _run_werkzeug_server(appfactory, host, port, + is_cmdline_mode=is_cmdline_mode, + serve_admin=serve_admin, + use_debugger=use_debugger, + use_reloader=use_reloader) + + elif wsgi == 'gunicorn': + options = { + 'bind': '%s:%s' % (host, port), + 'accesslog': '-', # print access log to stderr + } + if use_debugger: + options['loglevel'] = 'debug' + if use_reloader: + options['reload'] = True + _run_gunicorn_server(appfactory, + is_cmdline_mode=is_cmdline_mode, + gunicorn_options=options) + + else: + raise Exception("Unknown WSGI server: %s" % wsgi) + + +def _run_werkzeug_server(appfactory, host, port, *, + is_cmdline_mode=False, + serve_admin=False, + use_debugger=False, + use_reloader=False): from werkzeug.serving import run_simple def _run_sse_check(): @@ -21,6 +54,9 @@ os.environ.get('WERKZEUG_RUN_MAIN') == 'true') app = _get_piecrust_server(appfactory, + is_cmdline_mode=is_cmdline_mode, + serve_site=True, + serve_admin=serve_admin, run_sse_check=_run_sse_check) # We need to do a few things to get Werkzeug to properly shutdown or @@ -45,6 +81,10 @@ from piecrust.serving import procloop procloop.server_shutdown = True + if serve_admin: + from piecrust.admin import pubutil + pubutil.server_shutdown = True + def _shutdown_server_and_raise_sigint(): if not use_reloader or os.environ.get('WERKZEUG_RUN_MAIN') == 'true': # We only need to shutdown the SSE requests for the process @@ -75,7 +115,9 @@ raise -def run_gunicorn_server(appfactory, gunicorn_options=None): +def _run_gunicorn_server(appfactory, + is_cmdline_mode=False, + gunicorn_options=None): from gunicorn.app.base import BaseApplication class PieCrustGunicornApplication(BaseApplication): @@ -92,20 +134,72 @@ def load(self): return self.app - app = _get_piecrust_server(appfactory) + app = _get_piecrust_server(appfactory, + is_cmdline_mode=is_cmdline_mode) gunicorn_options = gunicorn_options or {} app_wrapper = PieCrustGunicornApplication(app, gunicorn_options) app_wrapper.run() -def _get_piecrust_server(appfactory, run_sse_check=None): - from piecrust.serving.middlewares import ( - StaticResourcesMiddleware, PieCrustDebugMiddleware) - from piecrust.serving.server import WsgiServer - app = WsgiServer(appfactory) - app = StaticResourcesMiddleware(app) - app = PieCrustDebugMiddleware( - app, appfactory, run_sse_check=run_sse_check) +def _get_piecrust_server(appfactory, *, + serve_site=True, + serve_admin=False, + is_cmdline_mode=False, + run_sse_check=None): + app = None + + if serve_site: + from piecrust.serving.middlewares import ( + PieCrustStaticResourcesMiddleware, PieCrustDebugMiddleware) + from piecrust.serving.server import PieCrustServer + + app = PieCrustServer(appfactory) + app = PieCrustStaticResourcesMiddleware(app) + + if is_cmdline_mode: + app = PieCrustDebugMiddleware( + app, appfactory, run_sse_check=run_sse_check) + + if serve_admin: + from piecrust.admin.web import create_foodtruck_app + + admin_root_url = '/pc-admin' + es = { + 'FOODTRUCK_CMDLINE_MODE': is_cmdline_mode, + 'FOODTRUCK_ROOT': appfactory.root_dir, + 'FOODTRUCK_URL_PREFIX': admin_root_url, + 'DEBUG': appfactory.debug} + if is_cmdline_mode: + es.update({ + 'SECRET_KEY': os.urandom(22), + 'LOGIN_DISABLED': True}) + + if appfactory.debug and is_cmdline_mode: + # Disable PIN protection with Werkzeug's debugger. + os.environ['WERKZEUG_DEBUG_PIN'] = 'off' + + admin_app = create_foodtruck_app(es) + admin_app.wsgi_app = _PieCrustSiteOrAdminMiddleware( + app, admin_app.wsgi_app, admin_root_url) + app = admin_app + return app + +class _PieCrustSiteOrAdminMiddleware: + def __init__(self, main_app, admin_app, admin_root_url): + from werkzeug.exceptions import abort + + def _err_resp(e, sr): + abort(404) + + self.main_app = main_app + self.admin_app = admin_app or _err_resp + self.admin_root_url = admin_root_url + + def __call__(self, environ, start_response): + path_info = environ.get('PATH_INFO', '') + if path_info.startswith(self.admin_root_url): + return self.admin_app(environ, start_response) + return self.main_app(environ, start_response)