Source code for scap.plugins
# -*- coding: utf-8 -*-
"""
scap.plugins
~~~~~~~~~~~~
Scap plugin architecture
.. function:: find_plugins(plugin_dirs)
Get a list of all plugins found in in plugin_dirs
:param list plugin_dirs: directories to search for plugins
:return: list of all plugin commands found in plugin_dirs
.. function:: load_plugins([plugin_dir])
load scap plugin modules.
:type plugin_dir: str or None
:param str plugin_dir: an additional location to search
Copyright © 2014-2017 Wikimedia Foundation and Contributors.
This file is part of Scap.
Scap 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, version 3.
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/>.
"""
import importlib
import logging
import os
import sys
import traceback
from ..cli import Application
from .say import Say
THIS_MODULE = sys.modules[__name__]
LOADED_PLUGINS = {}
__all__ = ["Say"]
[docs]def find_plugins(plugin_dirs):
"""
returns a list of all plugin commands found in plugin_dirs
"""
plugins = []
for d in plugin_dirs:
if d is None or not os.path.exists(d):
continue
file_list = os.listdir(os.path.realpath(d))
if len(file_list) < 1:
continue
try:
for f in file_list:
if not f.startswith("_") and f.endswith(".py"):
plugins.append(f[:-3])
except OSError:
continue
# add plugin_dir to this module's search path
if d not in __path__:
__path__.append(d)
return plugins
[docs]def load_plugins(plugin_dir=None):
"""
load plugins from ./scap/plugins/*.py and add them to the scap.plugins
module namespace.
"""
if os.getenv("SCAP_DISABLE_PLUGINS"):
return
if LOADED_PLUGINS:
# prevent loading plugins multiple times
return
possible_plugin_dirs = [
plugin_dir,
os.path.join(os.getcwd(), "scap", "plugins"),
os.path.join(os.path.expanduser("~"), ".scap", "plugins"),
]
plugin_dirs = []
for x in possible_plugin_dirs:
if x not in plugin_dirs:
plugin_dirs.append(x)
plugins = find_plugins(plugin_dirs)
if len(plugins) < 1:
return
# Turn off those obnoxious *.pyc files for plugins so we don't litter
maybe_write_bytecode = sys.dont_write_bytecode
sys.dont_write_bytecode = True
# import each of the plugin modules
for plugin in plugins:
# module path relative to scap.plugins:
plugin_module = ".%s" % plugin
try:
mod = importlib.import_module(plugin_module, "scap.plugins")
# find classes in mod which extend scap.cli.Application
for objname in dir(mod):
obj = getattr(mod, objname)
if isinstance(obj, type) and issubclass(obj, Application):
if objname in LOADED_PLUGINS:
# duplicate: another plugin already used the same name
msg = "Duplicate plugin named %s, skipping."
logging.getLogger().warning(msg, objname)
continue
# copy the class into the scap.plugins namespace
setattr(THIS_MODULE, objname, obj)
LOADED_PLUGINS[objname] = obj
__all__.append(objname)
except Exception as e:
msg = "Problem loading plugins from module: scap.plugins.%s (%s)"
err_msg = type(e).__name__ + ":" + str(e)
traceback.print_exc()
logging.getLogger().warning(msg, plugin, err_msg)
# Restore the original setting
sys.dont_write_bytecode = maybe_write_bytecode