blob: 686d2fee3b3acf65aeb2f2aec720d63a14a42e43 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001#!/usr/bin/env python -tt
2#
3# Copyright (c) 2011 Intel, Inc.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the Free
7# Software Foundation; version 2 of the License
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12# for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc., 59
16# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18__all__ = ['ImagerPlugin', 'SourcePlugin']
19
20import os
21import logging
22
23from collections import defaultdict
24from importlib.machinery import SourceFileLoader
25
26from wic import WicError
27from wic.misc import get_bitbake_var
28
29PLUGIN_TYPES = ["imager", "source"]
30
31SCRIPTS_PLUGIN_DIR = "scripts/lib/wic/plugins"
32
33logger = logging.getLogger('wic')
34
35PLUGINS = defaultdict(dict)
36
37class PluginMgr:
38 _plugin_dirs = []
39
40 @classmethod
41 def get_plugins(cls, ptype):
42 """Get dictionary of <plugin_name>:<class> pairs."""
43 if ptype not in PLUGIN_TYPES:
44 raise WicError('%s is not valid plugin type' % ptype)
45
46 # collect plugin directories
47 if not cls._plugin_dirs:
48 cls._plugin_dirs = [os.path.join(os.path.dirname(__file__), 'plugins')]
49 layers = get_bitbake_var("BBLAYERS") or ''
50 for layer_path in layers.split():
51 path = os.path.join(layer_path, SCRIPTS_PLUGIN_DIR)
52 path = os.path.abspath(os.path.expanduser(path))
53 if path not in cls._plugin_dirs and os.path.isdir(path):
54 cls._plugin_dirs.insert(0, path)
55
56 if ptype not in PLUGINS:
57 # load all ptype plugins
58 for pdir in cls._plugin_dirs:
59 ppath = os.path.join(pdir, ptype)
60 if os.path.isdir(ppath):
61 for fname in os.listdir(ppath):
62 if fname.endswith('.py'):
63 mname = fname[:-3]
64 mpath = os.path.join(ppath, fname)
65 logger.debug("loading plugin module %s", mpath)
66 SourceFileLoader(mname, mpath).load_module()
67
68 return PLUGINS.get(ptype)
69
70class PluginMeta(type):
71 def __new__(cls, name, bases, attrs):
72 class_type = type.__new__(cls, name, bases, attrs)
73 if 'name' in attrs:
74 PLUGINS[class_type.wic_plugin_type][attrs['name']] = class_type
75
76 return class_type
77
78class ImagerPlugin(metaclass=PluginMeta):
79 wic_plugin_type = "imager"
80
81 def do_create(self):
82 raise WicError("Method %s.do_create is not implemented" %
83 self.__class__.__name__)
84
85class SourcePlugin(metaclass=PluginMeta):
86 wic_plugin_type = "source"
87 """
88 The methods that can be implemented by --source plugins.
89
90 Any methods not implemented in a subclass inherit these.
91 """
92
93 @classmethod
94 def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir,
95 bootimg_dir, kernel_dir, native_sysroot):
96 """
97 Called after all partitions have been prepared and assembled into a
98 disk image. This provides a hook to allow finalization of a
99 disk image e.g. to write an MBR to it.
100 """
101 logger.debug("SourcePlugin: do_install_disk: disk: %s", disk_name)
102
103 @classmethod
104 def do_stage_partition(cls, part, source_params, creator, cr_workdir,
105 oe_builddir, bootimg_dir, kernel_dir,
106 native_sysroot):
107 """
108 Special content staging hook called before do_prepare_partition(),
109 normally empty.
110
111 Typically, a partition will just use the passed-in parame e.g
112 straight bootimg_dir, etc, but in some cases, things need to
113 be more tailored e.g. to use a deploy dir + /boot, etc. This
114 hook allows those files to be staged in a customized fashion.
115 Not that get_bitbake_var() allows you to acces non-standard
116 variables that you might want to use for this.
117 """
118 logger.debug("SourcePlugin: do_stage_partition: part: %s", part)
119
120 @classmethod
121 def do_configure_partition(cls, part, source_params, creator, cr_workdir,
122 oe_builddir, bootimg_dir, kernel_dir,
123 native_sysroot):
124 """
125 Called before do_prepare_partition(), typically used to create
126 custom configuration files for a partition, for example
127 syslinux or grub config files.
128 """
129 logger.debug("SourcePlugin: do_configure_partition: part: %s", part)
130
131 @classmethod
132 def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
133 oe_builddir, bootimg_dir, kernel_dir, rootfs_dir,
134 native_sysroot):
135 """
136 Called to do the actual content population for a partition i.e. it
137 'prepares' the partition to be incorporated into the image.
138 """
139 logger.debug("SourcePlugin: do_prepare_partition: part: %s", part)
140
141 @classmethod
142 def do_post_partition(cls, part, source_params, creator, cr_workdir,
143 oe_builddir, bootimg_dir, kernel_dir, rootfs_dir,
144 native_sysroot):
145 """
146 Called after the partition is created. It is useful to add post
147 operations e.g. security signing the partition.
148 """
149 logger.debug("SourcePlugin: do_post_partition: part: %s", part)