X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=mediagoblin%2Finit%2Fconfig.py;h=2e22083a5270be9b36e31da42dd02b355e07b363;hb=8096beab5c605a7433cc6bfc10969a6519b98d2a;hp=2f93d32ce6343c88d337a51b78a219750591eb69;hpb=421129b6bbf460057831914c25ab5694f5d21d4f;p=mediagoblin.git diff --git a/mediagoblin/init/config.py b/mediagoblin/init/config.py index 2f93d32c..2e22083a 100644 --- a/mediagoblin/init/config.py +++ b/mediagoblin/init/config.py @@ -1,5 +1,5 @@ # GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011 Free Software Foundation, Inc +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import copy +import logging import os import pkg_resources @@ -21,20 +23,28 @@ from configobj import ConfigObj, flatten_errors from validate import Validator +_log = logging.getLogger(__name__) + + CONFIG_SPEC_PATH = pkg_resources.resource_filename( 'mediagoblin', 'config_spec.ini') -def _setup_defaults(config, config_path): +def _setup_defaults(config, config_path, extra_defaults=None): """ Setup DEFAULTS in a config object from an (absolute) config_path. """ + extra_defaults = extra_defaults or {} + config.setdefault('DEFAULT', {}) config['DEFAULT']['here'] = os.path.dirname(config_path) config['DEFAULT']['__file__'] = config_path + for key, value in extra_defaults.items(): + config['DEFAULT'].setdefault(key, value) -def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH): + +def read_mediagoblin_config(config_path, config_spec_path=CONFIG_SPEC_PATH): """ Read a config object from config_path. @@ -42,12 +52,15 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH): Also provides %(__file__)s and %(here)s values of this file and its directory respectively similar to paste deploy. + Also reads for [plugins] section, appends all config_spec.ini + files from said plugins into the general config_spec specification. + This function doesn't itself raise any exceptions if validation fails, you'll have to do something Args: - config_path: path to the config file - - config_spec: config file that provides defaults and value types + - config_spec_path: config file that provides defaults and value types for validation / conversion. Defaults to mediagoblin/config_spec.ini Returns: @@ -57,23 +70,77 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH): """ config_path = os.path.abspath(config_path) - config_spec = ConfigObj( - config_spec, - encoding='UTF8', list_values=False, _inspec=True) + # PRE-READ of config file. This allows us to fetch the plugins so + # we can add their plugin specs to the general config_spec. + config = ConfigObj( + config_path, + interpolation="ConfigParser") + # temporary bootstrap, just setup here and __file__... we'll do this again + _setup_defaults(config, config_path) + + # Now load the main config spec + config_spec = ConfigObj( + config_spec_path, + encoding="UTF8", list_values=False, _inspec=True) + + # HACK to get MediaGoblin running under Docker/Python 3. Without this line, + # `./bin/gmg dbupdate` fails as the configuration under 'DEFAULT' in + # config_spec still had %(here)s markers in it, when these should have been + # replaced with actual paths, resulting in + # "configobj.MissingInterpolationOption: missing option "here" in + # interpolation". This issue doesn't seem to appear when running on Guix, + # but adding this line also doesn't appear to cause problems on Guix. _setup_defaults(config_spec, config_path) + # Set up extra defaults that will be pushed into the rest of the + # configs. This is a combined extrapolation of defaults based on + mainconfig_defaults = copy.copy(config_spec.get("DEFAULT", {})) + mainconfig_defaults.update(config["DEFAULT"]) + + plugins = config.get("plugins", {}).keys() + plugin_configs = {} + + for plugin in plugins: + try: + plugin_config_spec_path = pkg_resources.resource_filename( + plugin, "config_spec.ini") + if not os.path.exists(plugin_config_spec_path): + continue + + plugin_config_spec = ConfigObj( + plugin_config_spec_path, + encoding="UTF8", list_values=False, _inspec=True) + _setup_defaults( + plugin_config_spec, config_path, mainconfig_defaults) + + if not "plugin_spec" in plugin_config_spec: + continue + + plugin_configs[plugin] = plugin_config_spec["plugin_spec"] + + except ImportError: + _log.warning( + "When setting up config section, could not import '%s'" % + plugin) + + # append the plugin specific sections of the config spec + config_spec["plugins"] = plugin_configs + + _setup_defaults(config_spec, config_path, mainconfig_defaults) + config = ConfigObj( config_path, configspec=config_spec, - interpolation='ConfigParser') + encoding="UTF8", + interpolation="ConfigParser") - _setup_defaults(config, config_path) + _setup_defaults(config, config_path, mainconfig_defaults) # For now the validator just works with the default functions, # but in the future if we want to add additional validation/configuration # functions we'd add them to validator.functions here. - # + # # See also: # http://www.voidspace.org.uk/python/validate.html#adding-functions validator = Validator()