196ff1984SBrad Bishop#!/usr/bin/env python3
2eb8dc403SDave Cobbley#
3eb8dc403SDave Cobbley# Copyright (c) 2011 Intel, Inc.
4eb8dc403SDave Cobbley#
5c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only
6eb8dc403SDave Cobbley#
7eb8dc403SDave Cobbley
8eb8dc403SDave Cobbley__all__ = ['ImagerPlugin', 'SourcePlugin']
9eb8dc403SDave Cobbley
10eb8dc403SDave Cobbleyimport os
11eb8dc403SDave Cobbleyimport logging
12*595f6308SAndrew Geisslerimport types
13eb8dc403SDave Cobbley
14eb8dc403SDave Cobbleyfrom collections import defaultdict
15*595f6308SAndrew Geisslerimport importlib
16*595f6308SAndrew Geisslerimport importlib.util
17eb8dc403SDave Cobbley
18eb8dc403SDave Cobbleyfrom wic import WicError
19eb8dc403SDave Cobbleyfrom wic.misc import get_bitbake_var
20eb8dc403SDave Cobbley
21eb8dc403SDave CobbleyPLUGIN_TYPES = ["imager", "source"]
22eb8dc403SDave Cobbley
2382c905dcSAndrew GeisslerSCRIPTS_PLUGIN_DIR = ["scripts/lib/wic/plugins", "lib/wic/plugins"]
24eb8dc403SDave Cobbley
25eb8dc403SDave Cobbleylogger = logging.getLogger('wic')
26eb8dc403SDave Cobbley
27eb8dc403SDave CobbleyPLUGINS = defaultdict(dict)
28eb8dc403SDave Cobbley
29eb8dc403SDave Cobbleyclass PluginMgr:
30eb8dc403SDave Cobbley    _plugin_dirs = []
31eb8dc403SDave Cobbley
32eb8dc403SDave Cobbley    @classmethod
33eb8dc403SDave Cobbley    def get_plugins(cls, ptype):
34eb8dc403SDave Cobbley        """Get dictionary of <plugin_name>:<class> pairs."""
35eb8dc403SDave Cobbley        if ptype not in PLUGIN_TYPES:
36eb8dc403SDave Cobbley            raise WicError('%s is not valid plugin type' % ptype)
37eb8dc403SDave Cobbley
38eb8dc403SDave Cobbley        # collect plugin directories
39eb8dc403SDave Cobbley        if not cls._plugin_dirs:
40eb8dc403SDave Cobbley            cls._plugin_dirs = [os.path.join(os.path.dirname(__file__), 'plugins')]
41eb8dc403SDave Cobbley            layers = get_bitbake_var("BBLAYERS") or ''
42eb8dc403SDave Cobbley            for layer_path in layers.split():
4382c905dcSAndrew Geissler                for script_plugin_dir in SCRIPTS_PLUGIN_DIR:
4482c905dcSAndrew Geissler                    path = os.path.join(layer_path, script_plugin_dir)
45eb8dc403SDave Cobbley                    path = os.path.abspath(os.path.expanduser(path))
46eb8dc403SDave Cobbley                    if path not in cls._plugin_dirs and os.path.isdir(path):
47eb8dc403SDave Cobbley                        cls._plugin_dirs.insert(0, path)
48eb8dc403SDave Cobbley
49eb8dc403SDave Cobbley        if ptype not in PLUGINS:
50eb8dc403SDave Cobbley            # load all ptype plugins
51eb8dc403SDave Cobbley            for pdir in cls._plugin_dirs:
52eb8dc403SDave Cobbley                ppath = os.path.join(pdir, ptype)
53eb8dc403SDave Cobbley                if os.path.isdir(ppath):
54eb8dc403SDave Cobbley                    for fname in os.listdir(ppath):
55eb8dc403SDave Cobbley                        if fname.endswith('.py'):
56eb8dc403SDave Cobbley                            mname = fname[:-3]
57eb8dc403SDave Cobbley                            mpath = os.path.join(ppath, fname)
58eb8dc403SDave Cobbley                            logger.debug("loading plugin module %s", mpath)
59*595f6308SAndrew Geissler                            spec = importlib.util.spec_from_file_location(mname, mpath)
60*595f6308SAndrew Geissler                            module = importlib.util.module_from_spec(spec)
61*595f6308SAndrew Geissler                            spec.loader.exec_module(module)
62eb8dc403SDave Cobbley
63eb8dc403SDave Cobbley        return PLUGINS.get(ptype)
64eb8dc403SDave Cobbley
65eb8dc403SDave Cobbleyclass PluginMeta(type):
66eb8dc403SDave Cobbley    def __new__(cls, name, bases, attrs):
67eb8dc403SDave Cobbley        class_type = type.__new__(cls, name, bases, attrs)
68eb8dc403SDave Cobbley        if 'name' in attrs:
69eb8dc403SDave Cobbley            PLUGINS[class_type.wic_plugin_type][attrs['name']] = class_type
70eb8dc403SDave Cobbley
71eb8dc403SDave Cobbley        return class_type
72eb8dc403SDave Cobbley
73eb8dc403SDave Cobbleyclass ImagerPlugin(metaclass=PluginMeta):
74eb8dc403SDave Cobbley    wic_plugin_type = "imager"
75eb8dc403SDave Cobbley
76eb8dc403SDave Cobbley    def do_create(self):
77eb8dc403SDave Cobbley        raise WicError("Method %s.do_create is not implemented" %
78eb8dc403SDave Cobbley                       self.__class__.__name__)
79eb8dc403SDave Cobbley
80eb8dc403SDave Cobbleyclass SourcePlugin(metaclass=PluginMeta):
81eb8dc403SDave Cobbley    wic_plugin_type = "source"
82eb8dc403SDave Cobbley    """
83eb8dc403SDave Cobbley    The methods that can be implemented by --source plugins.
84eb8dc403SDave Cobbley
85eb8dc403SDave Cobbley    Any methods not implemented in a subclass inherit these.
86eb8dc403SDave Cobbley    """
87eb8dc403SDave Cobbley
88eb8dc403SDave Cobbley    @classmethod
89eb8dc403SDave Cobbley    def do_install_disk(cls, disk, disk_name, creator, workdir, oe_builddir,
90eb8dc403SDave Cobbley                        bootimg_dir, kernel_dir, native_sysroot):
91eb8dc403SDave Cobbley        """
92eb8dc403SDave Cobbley        Called after all partitions have been prepared and assembled into a
93eb8dc403SDave Cobbley        disk image.  This provides a hook to allow finalization of a
94eb8dc403SDave Cobbley        disk image e.g. to write an MBR to it.
95eb8dc403SDave Cobbley        """
96eb8dc403SDave Cobbley        logger.debug("SourcePlugin: do_install_disk: disk: %s", disk_name)
97eb8dc403SDave Cobbley
98eb8dc403SDave Cobbley    @classmethod
99eb8dc403SDave Cobbley    def do_stage_partition(cls, part, source_params, creator, cr_workdir,
100eb8dc403SDave Cobbley                           oe_builddir, bootimg_dir, kernel_dir,
101eb8dc403SDave Cobbley                           native_sysroot):
102eb8dc403SDave Cobbley        """
103eb8dc403SDave Cobbley        Special content staging hook called before do_prepare_partition(),
104eb8dc403SDave Cobbley        normally empty.
105eb8dc403SDave Cobbley
106eb8dc403SDave Cobbley        Typically, a partition will just use the passed-in parame e.g
107eb8dc403SDave Cobbley        straight bootimg_dir, etc, but in some cases, things need to
108eb8dc403SDave Cobbley        be more tailored e.g. to use a deploy dir + /boot, etc.  This
109eb8dc403SDave Cobbley        hook allows those files to be staged in a customized fashion.
110eb8dc403SDave Cobbley        Not that get_bitbake_var() allows you to acces non-standard
111eb8dc403SDave Cobbley        variables that you might want to use for this.
112eb8dc403SDave Cobbley        """
113eb8dc403SDave Cobbley        logger.debug("SourcePlugin: do_stage_partition: part: %s", part)
114eb8dc403SDave Cobbley
115eb8dc403SDave Cobbley    @classmethod
116eb8dc403SDave Cobbley    def do_configure_partition(cls, part, source_params, creator, cr_workdir,
117eb8dc403SDave Cobbley                               oe_builddir, bootimg_dir, kernel_dir,
118eb8dc403SDave Cobbley                               native_sysroot):
119eb8dc403SDave Cobbley        """
120eb8dc403SDave Cobbley        Called before do_prepare_partition(), typically used to create
121eb8dc403SDave Cobbley        custom configuration files for a partition, for example
122eb8dc403SDave Cobbley        syslinux or grub config files.
123eb8dc403SDave Cobbley        """
124eb8dc403SDave Cobbley        logger.debug("SourcePlugin: do_configure_partition: part: %s", part)
125eb8dc403SDave Cobbley
126eb8dc403SDave Cobbley    @classmethod
127eb8dc403SDave Cobbley    def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
128eb8dc403SDave Cobbley                             oe_builddir, bootimg_dir, kernel_dir, rootfs_dir,
129eb8dc403SDave Cobbley                             native_sysroot):
130eb8dc403SDave Cobbley        """
131eb8dc403SDave Cobbley        Called to do the actual content population for a partition i.e. it
132eb8dc403SDave Cobbley        'prepares' the partition to be incorporated into the image.
133eb8dc403SDave Cobbley        """
134eb8dc403SDave Cobbley        logger.debug("SourcePlugin: do_prepare_partition: part: %s", part)
135eb8dc403SDave Cobbley
136eb8dc403SDave Cobbley    @classmethod
137eb8dc403SDave Cobbley    def do_post_partition(cls, part, source_params, creator, cr_workdir,
138eb8dc403SDave Cobbley                             oe_builddir, bootimg_dir, kernel_dir, rootfs_dir,
139eb8dc403SDave Cobbley                             native_sysroot):
140eb8dc403SDave Cobbley        """
141eb8dc403SDave Cobbley        Called after the partition is created. It is useful to add post
142eb8dc403SDave Cobbley        operations e.g. security signing the partition.
143eb8dc403SDave Cobbley        """
144eb8dc403SDave Cobbley        logger.debug("SourcePlugin: do_post_partition: part: %s", part)
145