summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Boddie <paul@boddie.org.uk>2014-08-07 12:05:33 (GMT)
committerPaul Boddie <paul@boddie.org.uk>2014-08-07 12:05:33 (GMT)
commita7bc6a51f07ab95b92f28de2cad592dc29995eca (patch)
tree24ada91782fbb2f63da3e9de9cf5f59e7b37c48f
parent1d3d88ced320e151cf1b8ef53f15b4bee9e77a4e (diff)
downloadpykolab-a7bc6a51f07ab95b92f28de2cad592dc29995eca.tar.gz
Refactored module introspection.
-rw-r--r--pykolab/cli/commands.py155
-rw-r--r--pykolab/introspection.py171
-rw-r--r--pykolab/plugins/__init__.py36
-rw-r--r--pykolab/setup/components.py190
4 files changed, 218 insertions, 334 deletions
diff --git a/pykolab/cli/commands.py b/pykolab/cli/commands.py
index 515d40c..b6dff3a 100644
--- a/pykolab/cli/commands.py
+++ b/pykolab/cli/commands.py
@@ -20,40 +20,20 @@
import os
import sys
+from pykolab.introspection import *
import pykolab
from pykolab.translate import _
+from pykolab import utils
-log = pykolab.getLogger('pykolab.cli')
conf = pykolab.getConf()
commands = {}
-command_groups = {}
def __init__():
- # We only want the base path
- commands_base_path = os.path.dirname(__file__)
+ import_commands(os.path.dirname(__file__), "pykolab.cli", "cmd_", commands)
- for commands_path, dirnames, filenames in os.walk(commands_base_path):
- if not commands_path == commands_base_path:
- continue
-
- for filename in filenames:
- if filename.startswith('cmd_') and filename.endswith('.py'):
- module_name = filename.replace('.py','')
- cmd_name = module_name.replace('cmd_', '')
- #print "exec(\"from %s import __init__ as %s_register\"" % (module_name,cmd_name)
- try:
- exec("from %s import __init__ as %s_register" % (module_name,cmd_name))
- except ImportError, errmsg:
- pass
-
- exec("%s_register()" % (cmd_name))
-
- for dirname in dirnames:
- register_group(commands_path, dirname)
-
- register('help', list_commands)
+ register('help', lambda *args, **kw: list_commands(commands, *args, **kw))
register('delete_user', not_yet_implemented, description="Not yet implemented")
@@ -61,141 +41,24 @@ def __init__():
register('add_group', not_yet_implemented, description="Not yet implemented")
register('delete_group', not_yet_implemented, description="Not yet implemented")
-def list_commands(*args, **kw):
- """
- List commands
- """
-
- __commands = {}
-
- for command in commands.keys():
- if isinstance(command, tuple):
- command_group, command = command
- __commands[command_group] = {
- command: commands[(command_group,command)]
- }
- else:
- __commands[command] = commands[command]
-
- _commands = __commands.keys()
- _commands.sort()
-
- for _command in _commands:
- if __commands[_command].has_key('group'):
- continue
-
- if __commands[_command].has_key('function'):
- # This is a top-level command
- if not __commands[_command]['description'] == None:
- print "%-25s - %s" % (_command.replace('_','-'),__commands[_command]['description'])
- else:
- print "%-25s" % (_command.replace('_','-'))
-
- for _command in _commands:
- if not __commands[_command].has_key('function'):
- # This is a nested command
- print "\n" + _("Command Group: %s") % (_command) + "\n"
- ___commands = __commands[_command].keys()
- ___commands.sort()
- for __command in ___commands:
- if not __commands[_command][__command]['description'] == None:
- print "%-4s%-21s - %s" % ('',__command.replace('_','-'),__commands[_command][__command]['description'])
- else:
- print "%-4s%-21s" % ('',__command.replace('_','-'))
-
def execute(cmd_name, *args, **kw):
if cmd_name == "":
execute("help")
sys.exit(0)
if not commands.has_key(cmd_name):
- log.error(_("No such command."))
+ utils.message(_("No such command."))
sys.exit(1)
if not commands[cmd_name].has_key('function') and \
not commands[cmd_name].has_key('group'):
- log.error(_("No such command."))
+ utils.message(_("No such command."))
sys.exit(1)
- if commands[cmd_name].has_key('group'):
- group = commands[cmd_name]['group']
- command_name = commands[cmd_name]['cmd_name']
- try:
- exec("from %s.cmd_%s import cli_options as %s_%s_cli_options" % (group,command_name,group,command_name))
- exec("%s_%s_cli_options()" % (group,command_name))
- except ImportError, e:
- pass
-
- else:
- command_name = commands[cmd_name]['cmd_name']
- try:
- exec("from cmd_%s import cli_options as %s_cli_options" % (command_name,command_name))
- exec("%s_cli_options()" % (command_name))
- except ImportError, errmsg:
- pass
+ import_command_options(cmd_name, "cmd_name", "pykolab.cli", "cmd_", commands)
conf.finalize_conf()
commands[cmd_name]['function'](conf.cli_args, kw)
-def register_group(dirname, module):
- commands_base_path = os.path.join(os.path.dirname(__file__), module)
-
- commands[module] = {}
-
- for commands_path, dirnames, filenames in os.walk(commands_base_path):
- if not commands_path == commands_base_path:
- continue
-
- for filename in filenames:
- if filename.startswith('cmd_') and filename.endswith('.py'):
- module_name = filename.replace('.py','')
- cmd_name = module_name.replace('cmd_', '')
- #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" % (module,module_name,module,cmd_name)
- exec("from %s.%s import __init__ as %s_%s_register" % (module,module_name,module,cmd_name))
- exec("%s_%s_register()" % (module,cmd_name))
-
-def register(cmd_name, func, group=None, description=None, aliases=[]):
- if not group == None:
- command = "%s_%s" % (group,cmd_name)
- else:
- command = cmd_name
-
- if isinstance(aliases, basestring):
- aliases = [aliases]
-
- if commands.has_key(command):
- log.fatal(_("Command '%s' already registered") % (command))
- sys.exit(1)
-
- if callable(func):
- if group == None:
- commands[cmd_name] = {
- 'cmd_name': cmd_name,
- 'function': func,
- 'description': description
- }
- else:
- commands[group][cmd_name] = {
- 'cmd_name': cmd_name,
- 'function': func,
- 'description': description
- }
-
- commands[command] = commands[group][cmd_name]
- commands[command]['group'] = group
- commands[command]['cmd_name'] = cmd_name
-
- for alias in aliases:
- commands[alias] = {
- 'cmd_name': cmd_name,
- 'function': func,
- 'description': _("Alias for %s") % (cmd_name.replace('_','-'))
- }
-
-##
-## Commands not yet implemented
-##
-
-def not_yet_implemented(*args, **kw):
- print _("Not yet implemented")
- sys.exit(1)
+def register(*args, **kw):
+ register_command(commands, "cmd_name", *args, **kw)
diff --git a/pykolab/introspection.py b/pykolab/introspection.py
new file mode 100644
index 0000000..69d5576
--- /dev/null
+++ b/pykolab/introspection.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+# Copyright 2010-2013 Kolab Systems AG (http://www.kolabsys.com)
+#
+# Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen a kolabsys.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from pykolab.translate import _
+from os.path import isfile, isdir, join
+import os, sys
+
+def import_object(module_name, attr):
+ """
+ Import from the module with the given name the object with the given
+ attribute name.
+ """
+ module = __import__(module_name, level=0)
+ obj = module
+ for name in module_name.split(".")[1:]:
+ obj = getattr(obj, name)
+ try:
+ return getattr(obj, attr)
+ except AttributeError:
+ raise ImportError, "cannot import name %s" % attr
+
+def list_commands(commands, *args, **kw):
+ """
+ List commands or components.
+ """
+ show_commands(group_commands(commands))
+
+def group_commands(commands):
+ """
+ Return the grouped commands.
+ """
+ grouped_commands = {}
+
+ for command, definition in commands.items():
+ if isinstance(command, tuple):
+ command_group, command = command
+ grouped_commands[command_group] = {command: definition}
+ else:
+ grouped_commands[command] = definition
+
+ return grouped_commands
+
+def get_sorted_commands(commands):
+ """
+ Return the sorted keys of the commands dictionary.
+ """
+ sorted_commands = commands.keys()
+ sorted_commands.sort()
+ return sorted_commands
+
+def show_commands(commands, group=None):
+ """
+ Show commands within a group (or at the top level).
+ """
+ sorted_commands = get_sorted_commands(commands)
+
+ for command in sorted_commands:
+ if not commands[command].has_key('function'):
+ continue
+
+ option = command.replace('_','-')
+ if group:
+ prefix = "%-4s%-21s" % ('', option)
+ else:
+ prefix = "%-25s" % option
+
+ if commands[command]['description'] is not None:
+ print "%s - %s" % (prefix, commands[command]['description'])
+ else:
+ print prefix
+
+ for command in sorted_commands:
+ if not commands[command].has_key('function'):
+ # This is a nested command
+ print "\n" + _("Command Group: %s") % (command) + "\n"
+ show_commands(commands[command], command)
+
+def import_command_options(name, command_key, package, prefix, commands):
+ """
+ Obtain the options for the given command.
+ """
+ try:
+ command_name = commands[name][command_key]
+ if commands[name].has_key('group'):
+ group = commands[name]['group']
+ cmd = import_object("%s.%s.%s%s" % (package, group, prefix, command_name), "cli_options")
+ else:
+ cmd = import_object("%s.%s%s" % (package, prefix, command_name), "cli_options")
+ cmd()
+ except ImportError, errmsg:
+ pass
+
+def import_commands(dirname, package, fileprefix, commands):
+ """
+ Import commands from the given directory root for the given package and
+ involving modules with the given prefix, initialising the commands
+ structure.
+ """
+ for filename in os.listdir(dirname):
+ pathname = join(dirname, filename)
+ if isfile(pathname) and filename.startswith(fileprefix) and filename.endswith('.py'):
+ module_name = filename.replace('.py','')
+ cmd = import_object("%s.%s" % (package, module_name), "__init__")
+ cmd()
+ elif isdir(pathname):
+ register_group(dirname, package, filename, fileprefix, commands)
+
+def register_command(commands, command_key, name, func, group=None, description=None, aliases=[], after=[], before=[]):
+ if group is not None:
+ command = "%s_%s" % (group,name)
+ else:
+ command = name
+
+ if isinstance(aliases, basestring):
+ aliases = [aliases]
+
+ if commands.has_key(command):
+ log.fatal(_("Command '%s' already registered") % (command))
+ sys.exit(1)
+
+ if callable(func):
+ if group is None:
+ commands[name] = {
+ command_key: name,
+ 'function': func,
+ 'description': description,
+ 'after': after,
+ 'before': before,
+ }
+ else:
+ commands[group][name] = {
+ 'function': func,
+ 'description': description,
+ 'after': after,
+ 'before': before,
+ }
+
+ commands[command] = commands[group][name]
+ commands[command]['group'] = group
+ commands[command][command_key] = name
+
+ for alias in aliases:
+ commands[alias] = {
+ command_key: name,
+ 'function': func,
+ 'description': _("Alias for %s") % name.replace('_', '-')
+ }
+
+def register_group(dirname, package, filename, fileprefix, commands):
+ commands[filename] = {}
+ import_commands(join(dirname, filename), "%s.%s" % (package, filename), fileprefix, commands)
+
+def not_yet_implemented(*args, **kw):
+ print _("Not yet implemented")
+ sys.exit(1)
diff --git a/pykolab/plugins/__init__.py b/pykolab/plugins/__init__.py
index 4975b0c..d6ef626 100644
--- a/pykolab/plugins/__init__.py
+++ b/pykolab/plugins/__init__.py
@@ -17,12 +17,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-import logging
import os
-import pdb
import sys
import traceback
+from pykolab.introspection import import_object
import pykolab
from pykolab.translate import _
@@ -63,9 +62,8 @@ class KolabPlugins(object):
"""
for plugin in self.plugins:
try:
- exec("from pykolab.plugins import %s" % (plugin))
- self.plugins[plugin] = True
self.load_plugins(plugins=[plugin])
+ self.plugins[plugin] = True
except ImportError, e:
log.error(_("ImportError for plugin %s: %s") % (plugin,e))
traceback.print_exc()
@@ -85,13 +83,15 @@ class KolabPlugins(object):
Loads plugins specified by a list of plugins or loads them all
"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
if self.plugins[plugin]:
try:
- exec("self.%s = %s.Kolab%s()" % (plugin,plugin,plugin.capitalize()))
+ module = import_object("pykolab.plugins", plugin)
+ cls = getattr(module, "Kolab%s" % plugin.capitalize())
+ setattr(self, plugin, cls())
except:
# TODO: A little better verbosity please!
traceback.print_exc()
@@ -100,7 +100,7 @@ class KolabPlugins(object):
"""
Test for a function set_defaults() in all available and loaded plugins and execute plugin.set_defaults()
"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
@@ -126,7 +126,7 @@ class KolabPlugins(object):
"""
Set runtime variables from plugins, like 'i_did_all_this'
"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
@@ -147,7 +147,7 @@ class KolabPlugins(object):
"""
Add options specified in a plugin to parser. Takes a list of plugin names or does them all
"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
@@ -158,7 +158,7 @@ class KolabPlugins(object):
if hasattr(getattr(self,plugin),"add_options"):
try:
- exec("self.%s.add_options(parser)" % plugin)
+ getattr(self, plugin).add_options(parser)
except RuntimeError, e:
log.error(_("Cannot add options for plugin %s: %s") % (plugin,e))
except TypeError, e:
@@ -171,7 +171,7 @@ class KolabPlugins(object):
Executes plugin.check_plugins() for all enabled plugins or the list of plugin names specified.
"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
@@ -182,7 +182,7 @@ class KolabPlugins(object):
if hasattr(getattr(self,plugin),"check_options"):
try:
- exec("self.%s.check_options()" % plugin)
+ getattr(self, plugin).check_options()
except AttributeError, e:
log.error(_("Cannot check options for plugin %s: %s") % (plugin,e))
else:
@@ -193,7 +193,7 @@ class KolabPlugins(object):
Checks one setting specified by 'option' against the 'val' it is passed by all plugins or by the list of plugins specified
"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
@@ -203,7 +203,7 @@ class KolabPlugins(object):
continue
if hasattr(getattr(self,plugin),"%s_%s" % (func,option)):
- exec("retval = getattr(self,plugin).%s_%s(val)" % (func,option))
+ retval = getattr(getattr(self,plugin), "%s_%s" % (func,option))(val)
return retval
return False
@@ -213,7 +213,7 @@ class KolabPlugins(object):
retval = None
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
for plugin in plugins:
@@ -226,7 +226,7 @@ class KolabPlugins(object):
try:
log.debug(_("Executing hook %s for plugin %s") % (hook,plugin), level=8)
#print "retval = self.%s.%s(%r, %r)" % (plugin,hook, args, kw)
- exec("retval = self.%s.%s(*args, **kw)" % (plugin,hook))
+ retval = getattr(getattr(self, plugin), hook)(*args, **kw)
except TypeError, e:
log.error(_("Cannot execute hook %s for plugin %s: %s") % (hook,plugin,e))
except AttributeError, e:
@@ -236,7 +236,7 @@ class KolabPlugins(object):
def return_true_boolean_from_plugins(self, bool, plugins=[]):
"""Given the name of a boolean, walks all specified plugins, or all available plugins, and returns True if a plugin has it set to true"""
- if len(plugins) < 1:
+ if not plugins:
plugins = self.plugins.keys()
retval = False
@@ -249,7 +249,7 @@ class KolabPlugins(object):
if hasattr(getattr(self,plugin),bool):
try:
- exec("boolval = self.%s.%s" % (plugin,bool))
+ boolval = getattr(getattr(self, plugin), bool)
except AttributeError, e:
pass
else:
diff --git a/pykolab/setup/components.py b/pykolab/setup/components.py
index a9adbfa..4c77d73 100644
--- a/pykolab/setup/components.py
+++ b/pykolab/setup/components.py
@@ -18,8 +18,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-import os
+import os, sys
+from pykolab.introspection import *
import pykolab
from pykolab.constants import *
@@ -29,94 +30,18 @@ log = pykolab.getLogger('pykolab.setup')
conf = pykolab.getConf()
components = {}
-component_groups = {}
executed_components = []
components_included_in_cli = []
-finalize_conf_ok = None
-
def __init__():
- # We only want the base path
- components_base_path = os.path.dirname(__file__)
-
- for components_path, dirnames, filenames in os.walk(components_base_path):
- if not components_path == components_base_path:
- continue
-
- for filename in filenames:
- if filename.startswith('setup_') and filename.endswith('.py'):
- module_name = filename.replace('.py','')
- component_name = module_name.replace('setup_', '')
- #print "exec(\"from %s import __init__ as %s_register\"" % (module_name,component_name)
- exec("from %s import __init__ as %s_register" % (module_name,component_name))
- exec("%s_register()" % (component_name))
-
- for dirname in dirnames:
- register_group(components_path, dirname)
-
- register('help', list_components, description=_("Display this help."))
-
-def list_components(*args, **kw):
- """
- List components
- """
-
- __components = {}
-
- for component in components.keys():
- if isinstance(component, tuple):
- component_group, component = component
- __components[component_group] = {
- component: components[(component_group,component)]
- }
- else:
- __components[component] = components[component]
+ import_commands(os.path.dirname(__file__), "pykolab.setup", "setup_", components)
- _components = __components.keys()
- _components.sort()
+ register('help', help, description=_("Display this help."))
- for _component in _components:
- if __components[_component].has_key('function'):
- # This is a top-level component
- if not __components[_component]['description'] == None:
- print "%-25s - %s" % (_component.replace('_','-'),__components[_component]['description'])
- else:
- print "%-25s" % (_component.replace('_','-'))
-
- for _component in _components:
- if not __components[_component].has_key('function'):
- # This is a nested component
- print "\n" + _("Command Group: %s") % (_component) + "\n"
- ___components = __components[_component].keys()
- ___components.sort()
- for __component in ___components:
- if not __components[_component][__component]['description'] == None:
- print "%-4s%-21s - %s" % ('',__component.replace('_','-'),__components[_component][__component]['description'])
- else:
- print "%-4s%-21s" % ('',__component.replace('_','-'))
-
-def _list_components(*args, **kw):
- """
- List components and return API compatible, parseable lists and
- dictionaries.
- """
-
- __components = {}
-
- for component in components.keys():
- if isinstance(component, tuple):
- component_group, component = component
- __components[component_group] = {
- component: components[(component_group,component)]
- }
- else:
- __components[component] = components[component]
-
- _components = __components.keys()
- _components.sort()
-
- return _components
+def help(*args, **kw):
+ list_commands(components, *args, **kw)
+ print >> sys.stderr, _("\nSpecify 'all' to configure all components.")
def cli_options_from_component(component_name, *args, **kw):
global components_included_in_cli
@@ -124,34 +49,20 @@ def cli_options_from_component(component_name, *args, **kw):
if component_name in components_included_in_cli:
return
- if components[component_name].has_key('group'):
- group = components[component_name]['group']
- component_name = components[component_name]['component_name']
- try:
- exec("from %s.setup_%s import cli_options as %s_%s_cli_options" % (group,component_name,group,component_name))
- exec("%s_%s_cli_options()" % (group,component_name))
- except ImportError, e:
- pass
-
- else:
- try:
- exec("from setup_%s import cli_options as %s_cli_options" % (component_name,component_name))
- exec("%s_cli_options()" % (component_name))
- except ImportError, e:
- pass
-
+ import_command_options(component_name, "component_name", "pykolab.setup", "setup_", components)
components_included_in_cli.append(component_name)
def execute(component_name, *args, **kw):
- if component_name == '':
+ grouped_components = group_commands(components)
+ sorted_components = get_sorted_commands(grouped_components)
- log.debug(
- _("No component selected, continuing for all components"),
- level=8
- )
+ if not component_name:
+ execute("help")
+ return
+ elif component_name == "all":
while 1:
- for component in _list_components():
+ for component in sorted_components:
execute_this = True
if component in executed_components:
@@ -171,8 +82,8 @@ def execute(component_name, *args, **kw):
executed_components.append(component)
executed_all = True
- for component in _list_components():
- if not component in executed_components and not component == "help":
+ for component in sorted_components:
+ if not component in executed_components and component != "help":
executed_all = False
if executed_all:
@@ -180,7 +91,7 @@ def execute(component_name, *args, **kw):
return
else:
- for component in _list_components():
+ for component in sorted_components:
cli_options_from_component(component)
if not components.has_key(component_name):
@@ -201,66 +112,5 @@ def execute(component_name, *args, **kw):
components[component_name]['function'](conf.cli_args, kw)
-def register_group(dirname, module):
- components_base_path = os.path.join(os.path.dirname(__file__), module)
-
- components[module] = {}
-
- for components_path, dirnames, filenames in os.walk(components_base_path):
- if not components_path == components_base_path:
- continue
-
- for filename in filenames:
- if filename.startswith('setup_') and filename.endswith('.py'):
- module_name = filename.replace('.py','')
- component_name = module_name.replace('setup_', '')
- #print "exec(\"from %s.%s import __init__ as %s_%s_register\"" % (module,module_name,module,component_name)
- exec("from %s.%s import __init__ as %s_%s_register" % (module,module_name,module,component_name))
- exec("%s_%s_register()" % (module,component_name))
-
-def register(component_name, func, group=None, description=None, aliases=[], after=[], before=[]):
- if not group == None:
- component = "%s_%s" % (group,component_name)
- else:
- component = component_name
-
- if isinstance(aliases, basestring):
- aliases = [aliases]
-
- if components.has_key(component):
- log.fatal(_("Command '%s' already registered") % (component))
- sys.exit(1)
-
- if callable(func):
- if group == None:
- components[component_name] = {
- 'function': func,
- 'description': description,
- 'after': after,
- 'before': before,
- }
- else:
- components[group][component_name] = {
- 'function': func,
- 'description': description,
- 'after': after,
- 'before': before,
- }
-
- components[component] = components[group][component_name]
- components[component]['group'] = group
- components[component]['component_name'] = component_name
-
- for alias in aliases:
- components[alias] = {
- 'function': func,
- 'description': _("Alias for %s") % (component_name)
- }
-
-##
-## Commands not yet implemented
-##
-
-def not_yet_implemented(*args, **kw):
- print _("Not yet implemented")
- sys.exit(1)
+def register(*args, **kw):
+ register_command(components, "component_name", *args, **kw)