xref: /openbmc/openbmc/poky/meta/lib/oe/manifest.py (revision 92b42cb3)
1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: GPL-2.0-only
5#
6
7from abc import ABCMeta, abstractmethod
8import os
9import re
10import bb
11
12class Manifest(object, metaclass=ABCMeta):
13    """
14    This is an abstract class. Do not instantiate this directly.
15    """
16
17    PKG_TYPE_MUST_INSTALL = "mip"
18    PKG_TYPE_MULTILIB = "mlp"
19    PKG_TYPE_LANGUAGE = "lgp"
20    PKG_TYPE_ATTEMPT_ONLY = "aop"
21
22    MANIFEST_TYPE_IMAGE = "image"
23    MANIFEST_TYPE_SDK_HOST = "sdk_host"
24    MANIFEST_TYPE_SDK_TARGET = "sdk_target"
25
26    var_maps = {
27        MANIFEST_TYPE_IMAGE: {
28            "PACKAGE_INSTALL": PKG_TYPE_MUST_INSTALL,
29            "PACKAGE_INSTALL_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY,
30            "LINGUAS_INSTALL": PKG_TYPE_LANGUAGE
31        },
32        MANIFEST_TYPE_SDK_HOST: {
33            "TOOLCHAIN_HOST_TASK": PKG_TYPE_MUST_INSTALL,
34            "TOOLCHAIN_HOST_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY
35        },
36        MANIFEST_TYPE_SDK_TARGET: {
37            "TOOLCHAIN_TARGET_TASK": PKG_TYPE_MUST_INSTALL,
38            "TOOLCHAIN_TARGET_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY
39        }
40    }
41
42    INSTALL_ORDER = [
43        PKG_TYPE_LANGUAGE,
44        PKG_TYPE_MUST_INSTALL,
45        PKG_TYPE_ATTEMPT_ONLY,
46        PKG_TYPE_MULTILIB
47    ]
48
49    initial_manifest_file_header = \
50        "# This file was generated automatically and contains the packages\n" \
51        "# passed on to the package manager in order to create the rootfs.\n\n" \
52        "# Format:\n" \
53        "#  <package_type>,<package_name>\n" \
54        "# where:\n" \
55        "#   <package_type> can be:\n" \
56        "#      'mip' = must install package\n" \
57        "#      'aop' = attempt only package\n" \
58        "#      'mlp' = multilib package\n" \
59        "#      'lgp' = language package\n\n"
60
61    def __init__(self, d, manifest_dir=None, manifest_type=MANIFEST_TYPE_IMAGE):
62        self.d = d
63        self.manifest_type = manifest_type
64
65        if manifest_dir is None:
66            if manifest_type != self.MANIFEST_TYPE_IMAGE:
67                self.manifest_dir = self.d.getVar('SDK_DIR')
68            else:
69                self.manifest_dir = self.d.getVar('WORKDIR')
70        else:
71            self.manifest_dir = manifest_dir
72
73        bb.utils.mkdirhier(self.manifest_dir)
74
75        self.initial_manifest = os.path.join(self.manifest_dir, "%s_initial_manifest" % manifest_type)
76        self.final_manifest = os.path.join(self.manifest_dir, "%s_final_manifest" % manifest_type)
77        self.full_manifest = os.path.join(self.manifest_dir, "%s_full_manifest" % manifest_type)
78
79        # packages in the following vars will be split in 'must install' and
80        # 'multilib'
81        self.vars_to_split = ["PACKAGE_INSTALL",
82                              "TOOLCHAIN_HOST_TASK",
83                              "TOOLCHAIN_TARGET_TASK"]
84
85    """
86    This creates a standard initial manifest for core-image-(minimal|sato|sato-sdk).
87    This will be used for testing until the class is implemented properly!
88    """
89    def _create_dummy_initial(self):
90        image_rootfs = self.d.getVar('IMAGE_ROOTFS')
91        pkg_list = dict()
92        if image_rootfs.find("core-image-sato-sdk") > 0:
93            pkg_list[self.PKG_TYPE_MUST_INSTALL] = \
94                "packagegroup-core-x11-sato-games packagegroup-base-extended " \
95                "packagegroup-core-x11-sato packagegroup-core-x11-base " \
96                "packagegroup-core-sdk packagegroup-core-tools-debug " \
97                "packagegroup-core-boot packagegroup-core-tools-testapps " \
98                "packagegroup-core-eclipse-debug packagegroup-core-qt-demoapps " \
99                "apt packagegroup-core-tools-profile psplash " \
100                "packagegroup-core-standalone-sdk-target " \
101                "packagegroup-core-ssh-openssh dpkg kernel-dev"
102            pkg_list[self.PKG_TYPE_LANGUAGE] = \
103                "locale-base-en-us locale-base-en-gb"
104        elif image_rootfs.find("core-image-sato") > 0:
105            pkg_list[self.PKG_TYPE_MUST_INSTALL] = \
106                "packagegroup-core-ssh-dropbear packagegroup-core-x11-sato-games " \
107                "packagegroup-core-x11-base psplash apt dpkg packagegroup-base-extended " \
108                "packagegroup-core-x11-sato packagegroup-core-boot"
109            pkg_list['lgp'] = \
110                "locale-base-en-us locale-base-en-gb"
111        elif image_rootfs.find("core-image-minimal") > 0:
112            pkg_list[self.PKG_TYPE_MUST_INSTALL] = "packagegroup-core-boot"
113
114        with open(self.initial_manifest, "w+") as manifest:
115            manifest.write(self.initial_manifest_file_header)
116
117            for pkg_type in pkg_list:
118                for pkg in pkg_list[pkg_type].split():
119                    manifest.write("%s,%s\n" % (pkg_type, pkg))
120
121    """
122    This will create the initial manifest which will be used by Rootfs class to
123    generate the rootfs
124    """
125    @abstractmethod
126    def create_initial(self):
127        pass
128
129    """
130    This creates the manifest after everything has been installed.
131    """
132    @abstractmethod
133    def create_final(self):
134        pass
135
136    """
137    This creates the manifest after the package in initial manifest has been
138    dummy installed. It lists all *to be installed* packages. There is no real
139    installation, just a test.
140    """
141    @abstractmethod
142    def create_full(self, pm):
143        pass
144
145    """
146    The following function parses an initial manifest and returns a dictionary
147    object with the must install, attempt only, multilib and language packages.
148    """
149    def parse_initial_manifest(self):
150        pkgs = dict()
151
152        with open(self.initial_manifest) as manifest:
153            for line in manifest.read().split('\n'):
154                comment = re.match("^#.*", line)
155                pattern = "^(%s|%s|%s|%s),(.*)$" % \
156                          (self.PKG_TYPE_MUST_INSTALL,
157                           self.PKG_TYPE_ATTEMPT_ONLY,
158                           self.PKG_TYPE_MULTILIB,
159                           self.PKG_TYPE_LANGUAGE)
160                pkg = re.match(pattern, line)
161
162                if comment is not None:
163                    continue
164
165                if pkg is not None:
166                    pkg_type = pkg.group(1)
167                    pkg_name = pkg.group(2)
168
169                    if not pkg_type in pkgs:
170                        pkgs[pkg_type] = [pkg_name]
171                    else:
172                        pkgs[pkg_type].append(pkg_name)
173
174        return pkgs
175
176    '''
177    This following function parses a full manifest and return a list
178    object with packages.
179    '''
180    def parse_full_manifest(self):
181        installed_pkgs = list()
182        if not os.path.exists(self.full_manifest):
183            bb.note('full manifest not exist')
184            return installed_pkgs
185
186        with open(self.full_manifest, 'r') as manifest:
187            for pkg in manifest.read().split('\n'):
188                installed_pkgs.append(pkg.strip())
189
190        return installed_pkgs
191
192
193
194def create_manifest(d, final_manifest=False, manifest_dir=None,
195                    manifest_type=Manifest.MANIFEST_TYPE_IMAGE):
196    import importlib
197    manifest = importlib.import_module('oe.package_manager.' + d.getVar('IMAGE_PKGTYPE') + '.manifest').PkgManifest(d, manifest_dir, manifest_type)
198
199    if final_manifest:
200        manifest.create_final()
201    else:
202        manifest.create_initial()
203
204
205if __name__ == "__main__":
206    pass
207