2014-10-30 10:43:24 +00:00
|
|
|
#!/usr/bin/env python -tt
|
2013-08-24 15:31:34 +00:00
|
|
|
#
|
|
|
|
# Copyright (c) 2011 Intel, Inc.
|
|
|
|
#
|
|
|
|
# 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; version 2 of the License
|
|
|
|
#
|
|
|
|
# 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, write to the Free Software Foundation, Inc., 59
|
|
|
|
# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
import os, sys
|
|
|
|
|
2014-08-08 20:53:52 +00:00
|
|
|
from wic import msger
|
|
|
|
from wic import pluginbase
|
|
|
|
from wic.utils import errors
|
|
|
|
from wic.utils.oe.misc import *
|
2013-08-24 15:31:34 +00:00
|
|
|
|
|
|
|
__ALL__ = ['PluginMgr', 'pluginmgr']
|
|
|
|
|
2014-08-04 19:27:52 +00:00
|
|
|
PLUGIN_TYPES = ["imager", "source"]
|
2013-08-24 15:31:34 +00:00
|
|
|
|
2014-08-08 20:53:52 +00:00
|
|
|
PLUGIN_DIR = "/lib/wic/plugins" # relative to scripts
|
2014-05-15 01:37:28 +00:00
|
|
|
SCRIPTS_PLUGIN_DIR = "scripts" + PLUGIN_DIR
|
2013-08-24 15:31:34 +00:00
|
|
|
|
|
|
|
class PluginMgr(object):
|
|
|
|
plugin_dirs = {}
|
|
|
|
|
|
|
|
# make the manager class as singleton
|
|
|
|
_instance = None
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
|
if not cls._instance:
|
|
|
|
cls._instance = super(PluginMgr, cls).__new__(cls, *args, **kwargs)
|
|
|
|
|
|
|
|
return cls._instance
|
|
|
|
|
|
|
|
def __init__(self):
|
2014-08-08 20:53:52 +00:00
|
|
|
wic_path = os.path.dirname(__file__)
|
|
|
|
eos = wic_path.find('scripts') + len('scripts')
|
|
|
|
scripts_path = wic_path[:eos]
|
2014-05-15 01:37:28 +00:00
|
|
|
self.scripts_path = scripts_path
|
|
|
|
self.plugin_dir = scripts_path + PLUGIN_DIR
|
|
|
|
self.layers_path = None
|
|
|
|
|
|
|
|
def _build_plugin_dir_list(self, dl, ptype):
|
|
|
|
if self.layers_path is None:
|
|
|
|
self.layers_path = get_bitbake_var("BBLAYERS")
|
|
|
|
layer_dirs = []
|
|
|
|
|
2014-06-04 01:28:03 +00:00
|
|
|
if self.layers_path is not None:
|
|
|
|
for layer_path in self.layers_path.split():
|
|
|
|
path = os.path.join(layer_path, SCRIPTS_PLUGIN_DIR, ptype)
|
|
|
|
layer_dirs.append(path)
|
2013-09-19 04:32:19 +00:00
|
|
|
|
2014-06-04 01:28:02 +00:00
|
|
|
path = os.path.join(dl, ptype)
|
|
|
|
layer_dirs.append(path)
|
2014-05-15 01:37:28 +00:00
|
|
|
|
|
|
|
return layer_dirs
|
2013-08-24 15:31:34 +00:00
|
|
|
|
|
|
|
def append_dirs(self, dirs):
|
|
|
|
for path in dirs:
|
|
|
|
self._add_plugindir(path)
|
|
|
|
|
|
|
|
# load all the plugins AGAIN
|
|
|
|
self._load_all()
|
|
|
|
|
|
|
|
def _add_plugindir(self, path):
|
|
|
|
path = os.path.abspath(os.path.expanduser(path))
|
|
|
|
|
|
|
|
if not os.path.isdir(path):
|
2014-05-15 01:37:28 +00:00
|
|
|
msger.debug("Plugin dir is not a directory or does not exist: %s"\
|
2013-08-24 15:31:34 +00:00
|
|
|
% path)
|
|
|
|
return
|
|
|
|
|
|
|
|
if path not in self.plugin_dirs:
|
|
|
|
self.plugin_dirs[path] = False
|
|
|
|
# the value True/False means "loaded"
|
|
|
|
|
|
|
|
def _load_all(self):
|
|
|
|
for (pdir, loaded) in self.plugin_dirs.iteritems():
|
|
|
|
if loaded: continue
|
|
|
|
|
|
|
|
sys.path.insert(0, pdir)
|
|
|
|
for mod in [x[:-3] for x in os.listdir(pdir) if x.endswith(".py")]:
|
|
|
|
if mod and mod != '__init__':
|
|
|
|
if mod in sys.modules:
|
|
|
|
#self.plugin_dirs[pdir] = True
|
|
|
|
msger.warning("Module %s already exists, skip" % mod)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
pymod = __import__(mod)
|
|
|
|
self.plugin_dirs[pdir] = True
|
|
|
|
msger.debug("Plugin module %s:%s imported"\
|
|
|
|
% (mod, pymod.__file__))
|
|
|
|
except ImportError, err:
|
|
|
|
msg = 'Failed to load plugin %s/%s: %s' \
|
|
|
|
% (os.path.basename(pdir), mod, err)
|
|
|
|
msger.warning(msg)
|
|
|
|
|
|
|
|
del(sys.path[0])
|
|
|
|
|
|
|
|
def get_plugins(self, ptype):
|
|
|
|
""" the return value is dict of name:class pairs """
|
|
|
|
|
|
|
|
if ptype not in PLUGIN_TYPES:
|
|
|
|
raise errors.CreatorError('%s is not valid plugin type' % ptype)
|
|
|
|
|
2014-05-15 01:37:28 +00:00
|
|
|
plugins_dir = self._build_plugin_dir_list(self.plugin_dir, ptype)
|
|
|
|
|
|
|
|
self.append_dirs(plugins_dir)
|
2013-08-24 15:31:34 +00:00
|
|
|
|
|
|
|
return pluginbase.get_plugins(ptype)
|
|
|
|
|
2014-07-05 00:11:49 +00:00
|
|
|
def get_source_plugins(self):
|
|
|
|
"""
|
|
|
|
Return list of available source plugins.
|
|
|
|
"""
|
|
|
|
plugins_dir = self._build_plugin_dir_list(self.plugin_dir, 'source')
|
|
|
|
|
|
|
|
self.append_dirs(plugins_dir)
|
|
|
|
|
|
|
|
plugins = []
|
|
|
|
|
|
|
|
for _source_name, klass in self.get_plugins('source').iteritems():
|
|
|
|
plugins.append(_source_name)
|
|
|
|
|
|
|
|
return plugins
|
|
|
|
|
|
|
|
|
wic: Add SourcePlugin class
Define the SourcePlugin class, which is the class that should be
subclassed to create a 'source' plugin.
'Source' plugins provide a mechanism to customize various aspects of
the image generation process in wic, mainly the contents of
partitions.
The initial version of wic defined a --source param for partitions,
which was in the first revision hard-coded to two possible values:
rootfs and bootimg.
This patch essentially removes the hard-coded --bootimg param and
replaces it with a plugin system that maps the value specified as
--source to a particular 'source' plugin instead.
A 'source' plugin is created as a subclass of SourcePlugin and the
plugin file containing it is added to scriptsl/lib/mic/plugins/source/
to make the plugin implementation available to the wic implementation.
When the wic implementation needs to invoke a partition-specific
implementation, it looks for the plugin that has the same name as the
--source param given to that partition. For example, if the partition
is set up like this:
part /boot --source bootimg-pcbios ...
then the methods defined as class members of the plugin having the
matching .name class member would be used.
To be more concrete, here's the plugin definition that would match a
'--source bootimg-pcbios' usage, along with an example method that
would be called by the wic implementation when it needed to invoke an
implementation-specific partition-preparation function:
class BootimgPcbiosPlugin(SourcePlugin):
name = 'bootimg-pcbios'
@classmethod
def do_prepare_partition(self, part, ...)
If the subclass itself doesn't implement a function, a 'default'
version in a superclass will be located and used, which is why all
plugins must be derived from SourcePlugin.
This scheme is extensible - adding more hooks is a simple matter of
adding more plugin methods to SourcePlugin and derived classes. The
code that then needs to call the plugin methods the uses
plugin.get_source_plugin_methods() to find the method(s) needed by the
call; this is done by filling up a dict with keys containing the
methon names of interest - on success, these will be filled in with
the actual methods. fPlease see the implementation for examples and
details.
Note that a source plugin need not restrict itself to methods that
apply directly to partitions - methods can also be defined for higher
level processing such as at the 'disk' level. The
get_default_source_plugin() of DirectImageCreator allows the default
source plugin to be retrieved; by default this is set to be the same
plugin used for the /boot partition, but that can be overridden by
specifying a different --source and therefore different plugin on the
'bootloader' line. This isn't ideal, but it avoids forcing a new
high-level object to be defined for that purpose.
Note that the '--source rootfs' param remains as its current
hard-coded value, which is just the rootfs to be used to populate the
partition - by default, that's just the value of the bitbake
ROOTFS_DIR variable (or whatever was passed in using the -r param).
Note that this also could also be overridden by creating a source
plugin using a different name; at this point, unlike with bootimg,
there's been no need to do so.
(From OE-Core rev: 663833d8ecccb36ab42150bc5c9c00be79fa5b93)
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2014-02-04 01:16:57 +00:00
|
|
|
def get_source_plugin_methods(self, source_name, methods):
|
|
|
|
"""
|
|
|
|
The methods param is a dict with the method names to find. On
|
|
|
|
return, the dict values will be filled in with pointers to the
|
|
|
|
corresponding methods. If one or more methods are not found,
|
|
|
|
None is returned.
|
|
|
|
"""
|
|
|
|
return_methods = None
|
|
|
|
for _source_name, klass in self.get_plugins('source').iteritems():
|
|
|
|
if _source_name == source_name:
|
|
|
|
for _method_name in methods.keys():
|
|
|
|
if not hasattr(klass, _method_name):
|
|
|
|
msger.warning("Unimplemented %s source interface for: %s"\
|
|
|
|
% (_method_name, _source_name))
|
|
|
|
return None
|
|
|
|
func = getattr(klass, _method_name)
|
|
|
|
methods[_method_name] = func
|
|
|
|
return_methods = methods
|
|
|
|
return return_methods
|
|
|
|
|
2013-08-24 15:31:34 +00:00
|
|
|
pluginmgr = PluginMgr()
|