diff --git a/ChangeLog b/ChangeLog index 137b8aca..eca184bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,13 +5,12 @@ + Namespace config dictionaries are overwritten by [namespace] section of primary applications configuration files. Meaning, a namespace called 'example' reads configurations from [example] in the applications config - files. Note: the [namespace] section is required. + files. Additionally, Plugin configs can now exist in main application + configs under [plugin], as well as the typical plugins.d directory. + Added new 'bootstrap' directory where all application setup happens for each namespace, and refactored 'plugins' around this bootstrap layout. Along with that, discarded the 'plugins' directory. Plugins are now simply optional namespaces. - + Plugin configs can now exist in main application configs under [plugin], - as well as the typical plugins.d directory. + Plugins can now be enabled by the [root] 'enabled_plugins' list, or under a [plugin] config by setting 'enable_plugin=true'. diff --git a/cement/core/configuration.py b/cement/core/configuration.py index 807c3088..b95a3d8c 100644 --- a/cement/core/configuration.py +++ b/cement/core/configuration.py @@ -117,6 +117,7 @@ def set_config_opts_per_file(namespace, section, config_file): cnf = ConfigObj(config_file) try: config.update(cnf[section]) + cnf.update(config) except KeyError: # FIX ME: can't log here... # log.debug('missing section %s in %s.' % (section, config_file)) diff --git a/cement/core/namespace.py b/cement/core/namespace.py index 7ed63dd0..6d8b9fe6 100644 --- a/cement/core/namespace.py +++ b/cement/core/namespace.py @@ -12,6 +12,28 @@ from cement.core.opt import init_parser log = get_logger(__name__) +def get_namespace(namespace): + """ + Return the namespace object whose label is 'namespace'. + + Required Arguments: + + namespace + The label of the namespace object to return + + """ + if namespaces.has_key(namespace): + return namespaces[namespace] + else: + log.fatal("the namespace '%s' doesn't exist" % namespace) + +def get_config(namespace): + """Get a namespace's config dictionary.""" + if namespaces.has_key(namespace): + return namespaces[namespace].config + else: + log.fatal("the namespace '%s' doesn't exist" % namespace) + def register_namespaceOLD(**kwargs): """ Decorator function to register a namespace. Alternative to registering diff --git a/cement/core/plugin.py b/cement/core/plugin.py index 9772ffac..109fde8d 100644 --- a/cement/core/plugin.py +++ b/cement/core/plugin.py @@ -9,7 +9,8 @@ from cement.core.exc import CementConfigError, CementRuntimeError from cement.core.log import get_logger from cement.core.hook import run_hooks from cement.core.configuration import set_config_opts_per_file, t_f_pass -from cement.core.namespace import CementNamespace, define_namespace +from cement.core.namespace import CementNamespace, define_namespace, \ + get_namespace from cement.core.configuration import ensure_api_compat log = get_logger(__name__) @@ -26,13 +27,14 @@ def get_enabled_plugins_per_files(): Uses the namespaces['root'].config dictionary. """ - for file in os.listdir(namespaces['root'].config['plugin_config_dir']): - cnf = ConfigObj(os.path.join(namespaces['root'].config['plugin_config_dir'], file)) + _n = get_namespace('root') + for file in os.listdir(_n.config['plugin_config_dir']): + cnf = ConfigObj(os.path.join(_n.config['plugin_config_dir'], file)) for sect in cnf.sections: if sect != 'root' and cnf[sect].has_key('enable_plugin') \ and t_f_pass(cnf[sect]['enable_plugin']) == True \ - and not sect in namespaces['root'].config['enabled_plugins']: - namespaces['root'].config['enabled_plugins'].append(sect) + and not sect in _n.config['enabled_plugins']: + _n.config['enabled_plugins'].append(sect) def register_pluginOLD(**kwargs): """ diff --git a/cement/paste/templates/cementapp/+package+/controllers/example.py_tmpl b/cement/paste/templates/cementapp/+package+/controllers/example.py_tmpl index 8fcbb99b..2e146810 100644 --- a/cement/paste/templates/cementapp/+package+/controllers/example.py_tmpl +++ b/cement/paste/templates/cementapp/+package+/controllers/example.py_tmpl @@ -1,6 +1,6 @@ """This is the Example controller for {{package}}.""" -from cement import namespaces +from cement.core.namespace import get_config from cement.core.log import get_logger from cement.core.controller import CementController, expose from cement.core.hook import run_hooks @@ -20,6 +20,12 @@ class ExampleController(CementController): """ + # You can get the root application config like this: + config = get_config('root') + + # Or you can get your example namespace config like this: + config = get_config('example') + # You can print or log output however you like since this function # does not render out to a template. diff --git a/examples/helloworld/helloworld/appmain.py b/examples/helloworld/helloworld/appmain.py index a92bb9bf..2bef0a5f 100644 --- a/examples/helloworld/helloworld/appmain.py +++ b/examples/helloworld/helloworld/appmain.py @@ -15,6 +15,7 @@ from cement.core.app_setup import lay_cement from cement.core.configuration import ensure_api_compat from cement.core.command import run_command +from cement.core.namespace import get_config from helloworld.config import default_config REQUIRED_CEMENT_API = '0.7-0.8:20100210' @@ -35,7 +36,7 @@ def main(): sys.argv.append('default') run_command(sys.argv[1]) - + print get_config('root') except CementArgumentError, e: print("CementArgumentError > %s" % e) sys.exit(e.code) diff --git a/examples/helloworld/helloworld/controllers/example.py b/examples/helloworld/helloworld/controllers/example.py index 0f2aaf9a..1afaf313 100644 --- a/examples/helloworld/helloworld/controllers/example.py +++ b/examples/helloworld/helloworld/controllers/example.py @@ -1,6 +1,6 @@ """This is the Example controller for helloworld.""" -from cement import namespaces +from cement.core.namespace import get_config from cement.core.log import get_logger from cement.core.controller import CementController, expose from cement.core.hook import run_hooks @@ -20,8 +20,15 @@ class ExampleController(CementController): """ + # You can get the root application config like this: + config = get_config('root') + + # Or you can get your example namespace config like this: + config = get_config('example') + # You can print or log output however you like since this function # does not render out to a template. + # Commands are all passed the cli_opts, cli_args from the command line. # So if you have added cli options in your helloworld.bootstrap.example diff --git a/examples/helloworld/helloworld/plugins/__init__.py b/examples/helloworld/helloworld/plugins/__init__.py deleted file mode 100644 index b0d64337..00000000 --- a/examples/helloworld/helloworld/plugins/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__import__('pkg_resources').declare_namespace(__name__) \ No newline at end of file diff --git a/examples/helloworld/helloworld/plugins/example.py b/examples/helloworld/helloworld/plugins/example.py deleted file mode 100644 index 9b061984..00000000 --- a/examples/helloworld/helloworld/plugins/example.py +++ /dev/null @@ -1,100 +0,0 @@ -"""This is an example plugin for helloworld.""" - -import sys, os -import logging - -from cement import namespaces -from cement.core.log import get_logger -from cement.core.opt import init_parser -from cement.core.hook import define_hook, register_hook -from cement.core.plugin import CementPlugin, register_plugin - -from helloworld.appmain import VERSION, BANNER - -log = get_logger(__name__) - -REQUIRED_CEMENT_API = '0.7-0.8:20100210' - -@register_plugin() -class ExamplePlugin(CementPlugin): - # This is how we define a hook that we will honor later (see the example - # controller). Hooks allow other plugins to tie into your namespace. - define_hook('my_example_hook') - - def __init__(self): - CementPlugin.__init__(self, - label='example', - version=VERSION, - description='Example plugin for helloworld', - required_api=REQUIRED_CEMENT_API, - banner=BANNER, - controller = 'ExampleController', # from helloworld.controllers.example - ) - - # plugin configurations can be setup this way - self.config['example_option'] = False - - # plugin cli options can be setup this way. Generally, cli options - # are used to set config options... so if you probably want to - # add your options to both. - self.options.add_option('-E', '--example', action='store', - dest='example_option', default=None, help='Example Plugin Option' - ) - - -# -# HOOKS: Usually defined in the main plugin file (here). Functions -# that you decorate with @register_hook() will be run whenever/wherever -# run_hooks('the_hook_name') is called. -# - -@register_hook() -def options_hook(*args, **kwargs): - """ - Use this hook to add options to other namespaces. An OptParse object is - expected on return, and any options will be merged into the root options. - root options can also be used as local options by setting the config - option 'merge_root_options = true' in the plugin config. - """ - root_options = init_parser() - root_options.add_option('-G', '--root-option', action ='store_true', - dest='root_option', default=None, help='Example root option' - ) - - # return the namespace and the root options to add. - return ('root', root_options) - -@register_hook() -def options_hook(*args, **kwargs): - """ - We can also use the options hook to tie into other plugins, or even our - own. This is an alternateway of adding options for your [or other] - plugins. - """ - my_options = init_parser() - my_options.add_option('--new-local', action ='store', - dest='newlocal_option', default=None, help='Example Local option' - ) - - # return the namespace and the root options to add. - return ('example', my_options) - - -@register_hook() -def post_options_hook(*args, **kwargs): - """ - Use this hook if any operations need to be performed if a root - option is passed. Notice that we set a root option of -G in our - root_options_hook above. Here we can access that value from the - root namespace configuration. - """ - cnf = namespaces['root'].config - if cnf.has_key('root_option'): - print "root_option => %s", cnf['root_option'] - # then do something with it - -@register_hook() -def my_example_hook(*args, **kwargs): - """This is an example hook, that I define in my plugin config above.""" - return "I'm in my_example_hook" - \ No newline at end of file