From de483ec4571f1b90ed8512f56f962434c11e4428 Mon Sep 17 00:00:00 2001 From: Jan Mach <jan.mach@cesnet.cz> Date: Tue, 19 Feb 2019 18:18:38 +0100 Subject: [PATCH] Implemented Hawat command line interface based on flask.cli and Click. Currently only built-in Flask commands run, shell, etc. are available. It can be used to launch development web server, which is now documented in development documentation page. (Redmine issue: #4216) --- Makefile | 10 ++ bin/mentat-hawat.py | 61 ------------- bin/mentat-hawat.wsgi | 7 +- doc/sphinx/_doclib/bin_mentat-hawat.rst | 20 ---- doc/sphinx/_doclib/development.rst | 59 ++++++++++++ hawat.local.conf | 4 + lib/hawat/__init__.py | 13 ++- lib/hawat/app.py | 116 ++++++++++++++---------- lib/hawat/config.py | 9 ++ setup.py | 10 +- 10 files changed, 171 insertions(+), 138 deletions(-) delete mode 100755 bin/mentat-hawat.py delete mode 100644 doc/sphinx/_doclib/bin_mentat-hawat.rst create mode 100644 hawat.local.conf diff --git a/Makefile b/Makefile index 8b6a97c84..c68848427 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,8 @@ help: @echo " * $(GREEN)deps-postgresql$(NC): configure required PostgreSQL user accounts and databases" @echo " * $(GREEN)deps-translations$(NC): compile all available translations" @echo "" + @echo " * $(GREEN)run-webui-dev$(NC): run development web server with development configuration" + @echo "" @echo " * $(GREEN)clean-pycs$(NC): clean up Python compiled files" @echo " * $(GREEN)clean-build-python$(NC): clean up Python build directories" @echo " * $(GREEN)clean-build-debian$(NC): clean up Debian build directories" @@ -331,6 +333,14 @@ deps-postgresql: FORCE #------------------------------------------------------------------------------- +run-webui-dev: + @echo "\n$(GREEN)*** Running development web server with development configuration ***$(NC)\n" + FLASK_ENV=development FLASK_CONFIG=development FLASK_CONFIG_FILE=$(shell realpath ./hawat.local.conf) hawat-cli run + + +#------------------------------------------------------------------------------- + + clean-pycs: FORCE @echo "\n$(GREEN)*** Cleaning up Python precompiled files ***$(NC)\n" @find . -name '*.pyc' -delete diff --git a/bin/mentat-hawat.py b/bin/mentat-hawat.py deleted file mode 100755 index 9848c2eae..000000000 --- a/bin/mentat-hawat.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -#------------------------------------------------------------------------------- -# This file is part of Mentat system (https://mentat.cesnet.cz/). -# -# Copyright (C) since 2011 CESNET, z.s.p.o (http://www.ces.net/) -# Use of this source is governed by the MIT license, see LICENSE file. -#------------------------------------------------------------------------------- - -""" -Web interface for Mentat system - local development server - -This command will launch built-in development HTTP server and bind it to ``localhost``, -port ``5000``. It will also force the debug mode to ``True``. - -Usage -^^^^^ - -Just execute with Python3 interpreter:: - - python3 mentat-hawat.py - -Now point your browser to ``localhost``, port ``5000``:: - - http://localhost:5000 - -License -^^^^^^^ - -Copyright (C) since 2011 CESNET, z.s.p.o (http://www.ces.net/) -Use of this source is governed by the MIT license. -""" - - -__author__ = "Jan Mach <jan.mach@cesnet.cz>" -__credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" - - -if __name__ == '__main__': - - import hawat - - # - # Use prepared factory function to create application instance. The factory - # function takes number of arguments, that can be used to fine tune coniguration - # of the application. This is can be very usefull when extending applications` - # capabilities or for purposes of testing. Please refer to the documentation - # for more information. - # - APP = hawat.create_app( - config_object = 'hawat.config.DevelopmentConfig' - ) - - # - # Launch WSGI application, bind to localhost:5000 and enforce debug mode to True. - # - APP.run( - host = '127.0.0.1', - port = 5000, - debug = True - ) diff --git a/bin/mentat-hawat.wsgi b/bin/mentat-hawat.wsgi index 88f9a9223..c097b24e9 100644 --- a/bin/mentat-hawat.wsgi +++ b/bin/mentat-hawat.wsgi @@ -15,4 +15,9 @@ import hawat # capabilities or for purposes of testing. Please refer to the documentation # for more information. # -application = hawat.create_app() +application = hawat.create_app_full( + config_object = 'hawat.config.ProductionConfig', + config_file = '/etc/mentat/mentat-hawat.py.conf', + config_env = 'FLASK_CONFIG_FILE' +) + diff --git a/doc/sphinx/_doclib/bin_mentat-hawat.rst b/doc/sphinx/_doclib/bin_mentat-hawat.rst deleted file mode 100644 index a2db955da..000000000 --- a/doc/sphinx/_doclib/bin_mentat-hawat.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. _section-bin-mentat-hawat: - -mentat-hawat.py -================================================================================ - -Web interface for Mentat system - local development server - -This command will launch built-in development HTTP server and bind it to ``localhost``, -port ``5000``. It will also force the debug mode to ``True``. - -Usage -^^^^^ - -Just execute with Python3 interpreter:: - - python3 mentat-hawat.py - -Now point your browser to ``localhost``, port ``5000``:: - - http://localhost:5000 diff --git a/doc/sphinx/_doclib/development.rst b/doc/sphinx/_doclib/development.rst index 23d2f23fb..6f44c9777 100644 --- a/doc/sphinx/_doclib/development.rst +++ b/doc/sphinx/_doclib/development.rst @@ -198,6 +198,65 @@ targets:: (venv) $ make deps-webui-upgrade +Running development web server +```````````````````````````````````````````````````````````````````````````````` + +The web interface for this project is written in excellent `Flask <http://flask.pocoo.org/>`__ +microframework, that comes with built-in webserver for development. It can be +launched in following ways:: + + # A: You may use the Flask built-in command in a following way: + (venv) $ FLASK_APP=hawat FLASK_ENV=development FLASK_CONFIG=development FLASK_CONFIG_FILE=$(realpath ./hawat.local.conf) flask run + + # B: You may custom command line interface to launch webserver in development + # mode and with development configuration: + (venv) $ FLASK_ENV=development FLASK_CONFIG=development FLASK_CONFIG_FILE=$(realpath ./hawat.local.conf) hawat-cli run + + # C: Use following makefile target to do the same as the three above with less + # typing: + (venv) $ make run-webui-dev + +There are following environment variables you may use to tweak the application +launch according to your needs: + +* ``FLASK_DEBUG`` + + This configuration controls state of the internal debugger independently on the + ``FLASK_ENV`` setting. It is a boolean value and should be either ``True`` or + ``False``. Default value is ``False``. + +* ``FLASK_ENV`` + + This configuration controls application environment setting. This is a string + value and should be either ``development`` or ``production``. Default value is + ``production``. + +* ``FLASK_CONFIG`` + + This configuration controls the name of the configuration class from :py:mod:`mydojo.config` + module that will be used to configure the application. Valid value is one of the + :py:attr:`mydojo.config.CONFIG_MAP`. Default value is ``default``. + +* ``FLASK_CONFIG_FILE`` + + This configuration controls the name of the configuration file that will be used + to further configure the application. Values in this file are applied last and + will override anything in the configuration classes from :py:mod:`mydojo.config`. + Default value is empty. It must point to existing file if set, otherwise an exception + will be raised. Please use absolute path to the file to avoid any surprises. + +.. note:: + + The ``FLASK_CONFIG_FILE`` is especially handy for customizing the local + application configuration during development process or during deployment. + +For more information please study following resources: + +* `Flask: Command Line Interface <http://flask.pocoo.org/docs/1.0/cli/>`__ +* `Flask: Configuration Handling <http://flask.pocoo.org/docs/1.0/config/>`__ +* `Flask API: Configuration <http://flask.pocoo.org/docs/1.0/api/#configuration>`__ + + Documentation ```````````````````````````````````````````````````````````````````````````````` diff --git a/hawat.local.conf b/hawat.local.conf new file mode 100644 index 000000000..95dbd34bd --- /dev/null +++ b/hawat.local.conf @@ -0,0 +1,4 @@ +SECRET_KEY = 'local-secret-key' +HAWAT_LOG_DEFAULT_LEVEL = 'debug' +HAWAT_LOG_FILE = '/var/tmp/hawat.dev.log' +HAWAT_LOG_FILE_LEVEL = 'debug' diff --git a/lib/hawat/__init__.py b/lib/hawat/__init__.py index 0a5ecb009..aaa46915f 100644 --- a/lib/hawat/__init__.py +++ b/lib/hawat/__init__.py @@ -78,5 +78,14 @@ __author__ = "Jan Mach <jan.mach@cesnet.cz>" __credits__ = "Pavel Kácha <pavel.kacha@cesnet.cz>, Andrea Kropáčová <andrea.kropacova@cesnet.cz>" -# Expose main application factory to current namespace -from .app import create_app +import click +from flask.cli import FlaskGroup + + +# Expose main application factories to current namespace +from .app import create_app, create_app_full + + +@click.group(cls = FlaskGroup, create_app = create_app) +def cli(): + """Command line interface for the Hawat application.""" diff --git a/lib/hawat/app.py b/lib/hawat/app.py index 425f3b02e..0c361b4b1 100644 --- a/lib/hawat/app.py +++ b/lib/hawat/app.py @@ -49,6 +49,7 @@ import mentat.idea.jsondict import hawat.base import hawat.const +import hawat.config import hawat.acl import hawat.log import hawat.db @@ -56,6 +57,9 @@ import hawat.events from hawat.models.user import GuiUserModel +APP_NAME = 'hawat' +"""Name of the application as a constant for Flask.""" + RE_COUNTRY_CODE = re.compile('^[a-zA-Z]{2,3}$') """Regular expression for validating language/country codes.""" @@ -63,6 +67,69 @@ RE_COUNTRY_CODE = re.compile('^[a-zA-Z]{2,3}$') #------------------------------------------------------------------------------- +def create_app_full( + config_dict = None, + config_object = 'hawat.config.ProductionConfig', + config_file = None, + config_env = 'FLASK_CONFIG_FILE'): + """ + Factory function for building Hawat application. This function takes number of + optional arguments, that can be used to create a very customized instance of + Hawat application. This can be very usefull when extending applications` + capabilities or for purposes of testing. Each of these arguments has default + value for the most common application setup, so for disabling it entirely it + is necessary to provide ``None`` as a value. + + :param dict config_dict: Initial default configurations. + :param str config_object: Name of the class or module containing configurations. + :param str config_file: Name of the file containing additional configurations. + :param str config_env: Name of the environment variable pointing to file containing configurations. + :return: Hawat application + :rtype: hawat.base.HawatApp + """ + + app = hawat.base.HawatApp(APP_NAME) + + if config_dict and isinstance(config_dict, dict): + app.config.update(config_dict) + if config_object: + app.config.from_object(config_object) + if config_file: + app.config.from_pyfile(config_file) + if config_env and os.getenv(config_env, None): + app.config.from_envvar(config_env) + + _setup_app_logging(app) + _setup_app_mailer(app) + _setup_app_core(app) + _setup_app_db(app) + _setup_app_eventdb(app) + _setup_app_auth(app) + _setup_app_acl(app) + _setup_app_babel(app) + _setup_app_menu(app) + _setup_app_blueprints(app) + + return app + +def create_app(): + """ + Factory function for building Hawat application. This function does not take + any arguments, any necessary customizations must be done using environment + variables. + + :return: Hawat application + :rtype: hawat.base.HawatApp + """ + config_name = os.getenv('FLASK_CONFIG', 'default') + return create_app_full( + config_object = hawat.config.CONFIG_MAP[config_name] + ) + + +#------------------------------------------------------------------------------- + + def _setup_app_logging(app): """ Setup logging to file and via email for given Hawat application. Logging @@ -819,52 +886,3 @@ def _setup_app_blueprints(app): app.register_blueprints() return app - - -#------------------------------------------------------------------------------- - - -def create_app( - config_dict = None, - config_object = 'hawat.config.ProductionConfig', - config_file = '/etc/mentat/mentat-hawat.py.conf', - config_env = 'HAWAT_CONFIG_FILE'): - """ - Factory function for building Hawat application. This function takes number of - optional arguments, that can be used to create a very customized instance of - Hawat application. This can be very usefull when extending applications` - capabilities or for purposes of testing. Each of these arguments has default - value for the most common application setup, so for disabling it entirely it - is necessary to provide ``None`` as a value. - - :param dict config_dict: Initial default configurations. - :param str config_object: Name of the class or module containing configurations. - :param str config_file: Name of the file containing configurations. - :param str config_env: Name of the environment variable pointing to file containing configurations. - :return: Hawat application - :rtype: hawat.base.HawatApp - """ - - app = hawat.base.HawatApp('hawat') - - if config_dict and isinstance(config_dict, dict): - app.config.update(config_dict) - if config_object: - app.config.from_object(config_object) - if config_file: - app.config.from_pyfile(config_file, silent = True) - if config_env: - app.config.from_envvar(config_env, silent = True) - - _setup_app_logging(app) - _setup_app_mailer(app) - _setup_app_core(app) - _setup_app_db(app) - _setup_app_eventdb(app) - _setup_app_auth(app) - _setup_app_acl(app) - _setup_app_babel(app) - _setup_app_menu(app) - _setup_app_blueprints(app) - - return app diff --git a/lib/hawat/config.py b/lib/hawat/config.py index 0e44e38ef..d38757315 100644 --- a/lib/hawat/config.py +++ b/lib/hawat/config.py @@ -303,3 +303,12 @@ class TestingConfig(Config): # pylint: disable=locally-disabled,too-few-public- TESTING = True """Overwritten default value from :py:const:`hawat.config.Config.TESTING`""" + + +CONFIG_MAP = { + 'development': DevelopmentConfig, + 'production': ProductionConfig, + 'testing': TestingConfig, + 'default': ProductionConfig +} +"""Configuration map for easy mapping of configuration aliases to config objects.""" diff --git a/setup.py b/setup.py index d95026b71..4e2cf2c45 100644 --- a/setup.py +++ b/setup.py @@ -120,11 +120,11 @@ setup( # # Resources: # http://flask.pocoo.org/docs/1.0/cli/#custom-commands - #entry_points={ - # 'console_scripts': [ - # 'hawat-cli=hawat:cli' - # ], - #}, + entry_points={ + 'console_scripts': [ + 'hawat-cli=hawat:cli' + ], + }, include_package_data = True, zip_safe = False ) -- GitLab