From d967fa55d3db98e904275c9a76dd91ede64f1a57 Mon Sep 17 00:00:00 2001 From: Martin BTS Date: Thu, 10 Oct 2019 22:51:21 +0200 Subject: [PATCH] Refactor installer [3/3] -- hardcode default * added comments to main installer class to describe what the important statements do * ALL the relations between input parameters (their names) and validation classes are defined in parameters/__init__.py; no more looking in different places. Is there validation for a specific input? This file holds the anser! Do you want to add validation for another paramter? Do it there! --- askbot/deployment/__init__.py | 24 ++++- askbot/deployment/parameters/__init__.py | 109 ++++++++++++++--------- 2 files changed, 90 insertions(+), 43 deletions(-) diff --git a/askbot/deployment/__init__.py b/askbot/deployment/__init__.py index f2911d8482..77283d799e 100644 --- a/askbot/deployment/__init__.py +++ b/askbot/deployment/__init__.py @@ -12,7 +12,7 @@ from askbot.utils.functions import generate_random_key from askbot.deployment.template_loader import DeploymentTemplate from askbot.deployment.parameters import ConfigManagerCollection -from askbot.deployment.common.base import ObjectWithOutput +from askbot.deployment.base import ObjectWithOutput from askbot.deployment.deployables.components import DeployableComponent import askbot.deployment.deployables as deployable @@ -285,17 +285,30 @@ def __call__(self): # this is the main part of the original askbot_setup() nothing = DeployableComponent() nothing.deploy = lambda: None + # install into options['dir_name'] project = deployable.ProjectRoot(options['dir_name']) + + # select where to look for source files and templates project.src_dir = os.path.join(self.ASKBOT_ROOT, self.SOURCE_DIR) + + # set log dir an log file project.contents.update({ options['logdir_name']: {options['logfile_name']: deployable.EmptyFile} }) + # set the directory where settings.py etc. go, defaults to site = deployable.AskbotSite(options['app_name']) - site.src_dir = os.path.join(self.ASKBOT_ROOT, self.SOURCE_DIR) + + # install as a sub-directory to the intall directory site.dst_dir = options['dir_name'] + + # select where to look for source files and templates + site.src_dir = os.path.join(self.ASKBOT_ROOT, self.SOURCE_DIR) + + # use user provided paramters to render files site.context.update(options) + # install container specifics, analogous to site uwsgi = deployable.AskbotApp() uwsgi.src_dir = os.path.join(self.ASKBOT_ROOT, self.SOURCE_DIR) uwsgi.dst_dir = options['dir_name'] @@ -304,13 +317,15 @@ def __call__(self): # this is the main part of the original askbot_setup() 'askbot_app': uwsgi.name, # defaults to askbot_app }) + # put the path to settings.py into manage.py project.context = {'settings_path': f'{site.name}.settings'} todo = [ project, site ] if options['create_project'] in ['no', 'none', 'false', '0', 'nothing']: - todo = [ nothing ] + todo = [ nothing ] # undocumented noop for the installer elif options['create_project'] == 'container-uwsgi': + # if we install into a container we additionally want these files project.contents.update({ 'cron': { 'crontab': deployable.RenderedFile, # askbot_site, askbot_app @@ -318,12 +333,15 @@ def __call__(self): # this is the main part of the original askbot_setup() }}) todo.append(uwsgi) + # maybe we could just use the noop nothing instead of this? if options['dry_run']: raise StopIteration + # install askbot for component in todo: component.deploy() + # the happily ever after section for successful deployments help_file = path_utils.get_path_to_help_file() self.print(messages.HOW_TO_DEPLOY_NEW % {'help_file': help_file}) diff --git a/askbot/deployment/parameters/__init__.py b/askbot/deployment/parameters/__init__.py index ed9ff3b549..f19e227c00 100644 --- a/askbot/deployment/parameters/__init__.py +++ b/askbot/deployment/parameters/__init__.py @@ -1,40 +1,69 @@ -from askbot.deployment.parameters.base import ConfigManager -from askbot.deployment.parameters.cache import CacheConfigManager -from askbot.deployment.parameters.database import DbConfigManager -from askbot.deployment.parameters.filesystem import FilesystemConfigManager - -# one could make a case for not deriving ConfigManagerCollection from -# ConfigManager because the collection serves a different purpose than the -# individual manager, but they are still quite similar -class ConfigManagerCollection(ConfigManager): - """ - This is the main config manager that will be used by the Askbot installer. - It is a hard coded ordered collection of all config managers the installer - shall use. - """ - def __init__(self, interactive=False, verbosity=0): - super(ConfigManagerCollection, self).__init__(interactive=interactive, verbosity=verbosity) - self.register('database', DbConfigManager(interactive=interactive, verbosity=verbosity)) - self.register('cache', CacheConfigManager(interactive=interactive, verbosity=verbosity)) - self.register('filesystem', FilesystemConfigManager(interactive=interactive, verbosity=verbosity)) - - def _order(self, keys): - full_set = ['filesystem', 'database', 'cache'] - return [item for item in full_set if item in keys] - - def configManager(self, name): - return super(ConfigManagerCollection, self).configField(name) - - def complete(self, *args, **kwargs): - for manager in self._order(self.keys): - handler = self.configManager(manager) - handler.complete(*args, **kwargs) - - # these should never be called. we keep these, just in case - def _remember(self, name, value): - raise NotImplementedError(f'Not implemented in {self.__class__.__name__}.') - - def _complete(self, name, value): - raise NotImplementedError(f'Not implemented in {self.__class__.__name__}.') - -__all__ = [ 'DbConfigManager', 'CacheConfigManager', 'FilesystemConfigManager', 'ConfigManagerCollection'] +from askbot.deployment.base import ConfigManagerCollection, ConfigManager +from .configmanagers import CacheConfigManager, DbConfigManager + +from .cache import * +from .database import * +from .filesystem import * + +""" +In this module we assemble the input validation capabilities for the Askbot +installer. + +The goal is to provide a single ConfigManagerCollection instance +(currently named askbotCollection), the installer will use to validate its +parameters. + +The idea is askbotCollection will be able to validate just the +parameters that are register()-ed in this module/file. First we create the +collection and managers. Then we register() all the parameters for which we +want validation. + +The validation implementations vary in complexity. Therefore, all +implementations are defined in derived classes in submodules, structured by +their topic, e.g. cache, database and filesystem. Here, at this level, we +import all classes and use register() as a mapping from parameter name, to +validation implementation. + +The parameter names must match the argpare argument destinations, i.e. the +`dest` argument to ArgumentParser.add_argument(), do be effective. + +THE ORDER IN WHICH VALIDATIONS ARE register()-ed WITH THEIR ConfigManagers +MATTERS! +""" + +# use these values while inizializing this module +interactive=False +verbosity=0 + +# the ConfigManagerCollection the installer will use +askbotCollection = ConfigManagerCollection(interactive=interactive, verbosity=verbosity) + +# the ConfigManagers the installer will use +cacheManager = CacheConfigManager(interactive=interactive, verbosity=verbosity) +databaseManager = DbConfigManager(interactive=interactive, verbosity=verbosity) +filesystemManager = ConfigManager(interactive=interactive, verbosity=verbosity) + +# register the ConfigManagers with the ConfigManagerCollection +askbotCollection.register('filesystem', filesystemManager) +askbotCollection.register('database', databaseManager) +askbotCollection.register('cache', cacheManager) + +# register parameters with config managers. THE ORDERING MATTERS! +cacheManager.register('cache_engine', CacheEngine()) +cacheManager.register('cache_nodes', CacheNodes()) +cacheManager.register('cache_db', CacheDb()) +cacheManager.register('cache_password', CachePass()) + +databaseManager.register('database_engine', DbEngine()) +databaseManager.register('database_name', DbName()) +databaseManager.register('database_user', DbUser()) +databaseManager.register('database_password', DbPass()) +databaseManager.register('database_host', DbHost()) +databaseManager.register('database_port', DbPort()) + +filesystemManager.register('dir_name', ProjectDirName()) +filesystemManager.register('app_name', AppDirName()) +filesystemManager.register('logfile_name', LogfileName()) + + +__all__ = ['askbotCollection', 'cacheManager', 'databaseManager', 'filesystemManager']