Make plugin loader path operations more efficient.

This commit is contained in:
Michael DeHaan 2013-04-20 12:31:14 -04:00
parent 5a8dff5bce
commit e6bf01a6b0
2 changed files with 65 additions and 29 deletions

View file

@ -170,13 +170,23 @@ def main():
if len(args) == 0:
p.print_help()
def print_paths(finder):
''' Returns a string suitable for printing of the search path '''
# Uses a list to get the order right
ret = []
for i in finder._get_paths():
if i not in ret:
ret.append(i)
return os.pathsep.join(ret)
for module in args:
filename = utils.plugins.module_finder.find_plugin(module)
if filename is None:
sys.stderr.write("module %s not found in %s\n" % (module,
utils.plugins.module_finder.print_paths()))
print_paths(utils.plugins.module_finder)))
continue
if any(filename.endswith(x) for x in BLACKLIST_EXTS):

View file

@ -23,34 +23,47 @@ import ansible.constants as C
from ansible import errors
MODULE_CACHE = {}
PATH_CACHE = {}
PLUGIN_PATH_CACHE = {}
_basedirs = []
def push_basedir(basedir):
_basedirs.insert(0, basedir)
class PluginLoader(object):
"""PluginLoader loads plugins from the best source
'''
PluginLoader loads plugins from the configured plugin directories.
It searches for plugins by iterating through the combined list of
play basedirs, configured paths, and the installed package directory.
play basedirs, configured paths, and the python path.
The first match is used.
"""
'''
def __init__(self, class_name, package, config, subdir, aliases={}):
"""Create a new PluginLoader"""
self.class_name = class_name
self.package = package
self.config = config
self.subdir = subdir
self.aliases = aliases
self.class_name = class_name
self.package = package
self.config = config
self.subdir = subdir
self.aliases = aliases
if not class_name in MODULE_CACHE:
MODULE_CACHE[class_name] = {}
if not class_name in PATH_CACHE:
PATH_CACHE[class_name] = None
if not class_name in PLUGIN_PATH_CACHE:
PLUGIN_PATH_CACHE[class_name] = {}
self._module_cache = MODULE_CACHE[class_name]
self._paths = PATH_CACHE[class_name]
self._plugin_path_cache = PLUGIN_PATH_CACHE[class_name]
self._module_cache = MODULE_CACHE[class_name]
self._extra_dirs = []
def _get_package_path(self):
"""Gets the path of a Python package"""
''' Gets the path of a Python package '''
if not self.package:
return []
if not hasattr(self, 'package_path'):
@ -60,9 +73,11 @@ class PluginLoader(object):
return [self.package_path]
def _get_paths(self):
"""Return a list of paths to search for plugins in
''' Return a list of paths to search for plugins in '''
if self._paths is not None:
return self._paths
The list is searched in order."""
ret = []
ret += self._extra_dirs
for basedir in _basedirs:
@ -71,41 +86,51 @@ class PluginLoader(object):
ret.append(fullpath)
ret += self.config.split(os.pathsep)
ret += self._get_package_path()
self._paths = ret
return ret
def add_directory(self, directory, with_subdir=False):
"""Adds an additional directory to the search path"""
''' Adds an additional directory to the search path '''
self._paths = None
if directory is not None:
if with_subdir:
directory = os.path.join(directory, self.subdir)
self._extra_dirs.append(directory)
def print_paths(self):
"""Returns a string suitable for printing of the search path"""
# Uses a list to get the order right
ret = []
for i in self._get_paths():
if i not in ret:
ret.append(i)
return os.pathsep.join(ret)
def find_plugin(self, name):
"""Find a plugin named name"""
''' Find a plugin named name '''
if 'name' in self._plugin_path_cache:
return self._plugin_path_cache[name]
suffix = ".py"
if not self.class_name:
suffix = ""
paths = self._get_paths()
for i in self._get_paths():
path = os.path.join(i, "%s%s" % (name, suffix))
if os.path.exists(path):
self._plugin_path_cache[name] = path
return path
return None
def has_plugin(self, name):
"""Checks if a plugin named name exists"""
''' Checks if a plugin named name exists '''
return self.find_plugin(name) is not None
__contains__ = has_plugin
def get(self, name, *args, **kwargs):
''' instantiates a plugin of the given name using arguments '''
if name in self.aliases:
name = self.aliases[name]
path = self.find_plugin(name)
@ -116,7 +141,8 @@ class PluginLoader(object):
return getattr(self._module_cache[path], self.class_name)(*args, **kwargs)
def all(self, *args, **kwargs):
''' instantiates all plugins with the same arguments '''
for i in self._get_paths():
for path in glob.glob(os.path.join(i, "*.py")):
name, ext = os.path.splitext(os.path.basename(path))