blob: f7c88f9a09820c43776f40cc349503c8515bd6d9 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
Patrick Williamsc124f4f2015-09-15 14:41:29 -05005from abc import ABCMeta, abstractmethod
6import os
7import re
8import bb
9
10
Patrick Williamsc0f7c042017-02-23 20:41:17 -060011class Manifest(object, metaclass=ABCMeta):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012 """
13 This is an abstract class. Do not instantiate this directly.
14 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015
16 PKG_TYPE_MUST_INSTALL = "mip"
17 PKG_TYPE_MULTILIB = "mlp"
18 PKG_TYPE_LANGUAGE = "lgp"
19 PKG_TYPE_ATTEMPT_ONLY = "aop"
20
21 MANIFEST_TYPE_IMAGE = "image"
22 MANIFEST_TYPE_SDK_HOST = "sdk_host"
23 MANIFEST_TYPE_SDK_TARGET = "sdk_target"
24
25 var_maps = {
26 MANIFEST_TYPE_IMAGE: {
27 "PACKAGE_INSTALL": PKG_TYPE_MUST_INSTALL,
28 "PACKAGE_INSTALL_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY,
29 "LINGUAS_INSTALL": PKG_TYPE_LANGUAGE
30 },
31 MANIFEST_TYPE_SDK_HOST: {
32 "TOOLCHAIN_HOST_TASK": PKG_TYPE_MUST_INSTALL,
33 "TOOLCHAIN_HOST_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY
34 },
35 MANIFEST_TYPE_SDK_TARGET: {
36 "TOOLCHAIN_TARGET_TASK": PKG_TYPE_MUST_INSTALL,
37 "TOOLCHAIN_TARGET_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY
38 }
39 }
40
41 INSTALL_ORDER = [
42 PKG_TYPE_LANGUAGE,
43 PKG_TYPE_MUST_INSTALL,
44 PKG_TYPE_ATTEMPT_ONLY,
45 PKG_TYPE_MULTILIB
46 ]
47
48 initial_manifest_file_header = \
49 "# This file was generated automatically and contains the packages\n" \
50 "# passed on to the package manager in order to create the rootfs.\n\n" \
51 "# Format:\n" \
52 "# <package_type>,<package_name>\n" \
53 "# where:\n" \
54 "# <package_type> can be:\n" \
55 "# 'mip' = must install package\n" \
56 "# 'aop' = attempt only package\n" \
57 "# 'mlp' = multilib package\n" \
58 "# 'lgp' = language package\n\n"
59
60 def __init__(self, d, manifest_dir=None, manifest_type=MANIFEST_TYPE_IMAGE):
61 self.d = d
62 self.manifest_type = manifest_type
63
64 if manifest_dir is None:
65 if manifest_type != self.MANIFEST_TYPE_IMAGE:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050066 self.manifest_dir = self.d.getVar('SDK_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050067 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050068 self.manifest_dir = self.d.getVar('WORKDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 else:
70 self.manifest_dir = manifest_dir
71
72 bb.utils.mkdirhier(self.manifest_dir)
73
74 self.initial_manifest = os.path.join(self.manifest_dir, "%s_initial_manifest" % manifest_type)
75 self.final_manifest = os.path.join(self.manifest_dir, "%s_final_manifest" % manifest_type)
76 self.full_manifest = os.path.join(self.manifest_dir, "%s_full_manifest" % manifest_type)
77
78 # packages in the following vars will be split in 'must install' and
79 # 'multilib'
80 self.vars_to_split = ["PACKAGE_INSTALL",
81 "TOOLCHAIN_HOST_TASK",
82 "TOOLCHAIN_TARGET_TASK"]
83
84 """
85 This creates a standard initial manifest for core-image-(minimal|sato|sato-sdk).
86 This will be used for testing until the class is implemented properly!
87 """
88 def _create_dummy_initial(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050089 image_rootfs = self.d.getVar('IMAGE_ROOTFS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 pkg_list = dict()
91 if image_rootfs.find("core-image-sato-sdk") > 0:
92 pkg_list[self.PKG_TYPE_MUST_INSTALL] = \
93 "packagegroup-core-x11-sato-games packagegroup-base-extended " \
94 "packagegroup-core-x11-sato packagegroup-core-x11-base " \
95 "packagegroup-core-sdk packagegroup-core-tools-debug " \
96 "packagegroup-core-boot packagegroup-core-tools-testapps " \
97 "packagegroup-core-eclipse-debug packagegroup-core-qt-demoapps " \
98 "apt packagegroup-core-tools-profile psplash " \
99 "packagegroup-core-standalone-sdk-target " \
100 "packagegroup-core-ssh-openssh dpkg kernel-dev"
101 pkg_list[self.PKG_TYPE_LANGUAGE] = \
102 "locale-base-en-us locale-base-en-gb"
103 elif image_rootfs.find("core-image-sato") > 0:
104 pkg_list[self.PKG_TYPE_MUST_INSTALL] = \
105 "packagegroup-core-ssh-dropbear packagegroup-core-x11-sato-games " \
106 "packagegroup-core-x11-base psplash apt dpkg packagegroup-base-extended " \
107 "packagegroup-core-x11-sato packagegroup-core-boot"
108 pkg_list['lgp'] = \
109 "locale-base-en-us locale-base-en-gb"
110 elif image_rootfs.find("core-image-minimal") > 0:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500111 pkg_list[self.PKG_TYPE_MUST_INSTALL] = "packagegroup-core-boot"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112
113 with open(self.initial_manifest, "w+") as manifest:
114 manifest.write(self.initial_manifest_file_header)
115
116 for pkg_type in pkg_list:
117 for pkg in pkg_list[pkg_type].split():
118 manifest.write("%s,%s\n" % (pkg_type, pkg))
119
120 """
121 This will create the initial manifest which will be used by Rootfs class to
122 generate the rootfs
123 """
124 @abstractmethod
125 def create_initial(self):
126 pass
127
128 """
129 This creates the manifest after everything has been installed.
130 """
131 @abstractmethod
132 def create_final(self):
133 pass
134
135 """
136 This creates the manifest after the package in initial manifest has been
137 dummy installed. It lists all *to be installed* packages. There is no real
138 installation, just a test.
139 """
140 @abstractmethod
141 def create_full(self, pm):
142 pass
143
144 """
145 The following function parses an initial manifest and returns a dictionary
146 object with the must install, attempt only, multilib and language packages.
147 """
148 def parse_initial_manifest(self):
149 pkgs = dict()
150
151 with open(self.initial_manifest) as manifest:
152 for line in manifest.read().split('\n'):
153 comment = re.match("^#.*", line)
154 pattern = "^(%s|%s|%s|%s),(.*)$" % \
155 (self.PKG_TYPE_MUST_INSTALL,
156 self.PKG_TYPE_ATTEMPT_ONLY,
157 self.PKG_TYPE_MULTILIB,
158 self.PKG_TYPE_LANGUAGE)
159 pkg = re.match(pattern, line)
160
161 if comment is not None:
162 continue
163
164 if pkg is not None:
165 pkg_type = pkg.group(1)
166 pkg_name = pkg.group(2)
167
168 if not pkg_type in pkgs:
169 pkgs[pkg_type] = [pkg_name]
170 else:
171 pkgs[pkg_type].append(pkg_name)
172
173 return pkgs
174
175 '''
176 This following function parses a full manifest and return a list
177 object with packages.
178 '''
179 def parse_full_manifest(self):
180 installed_pkgs = list()
181 if not os.path.exists(self.full_manifest):
182 bb.note('full manifest not exist')
183 return installed_pkgs
184
185 with open(self.full_manifest, 'r') as manifest:
186 for pkg in manifest.read().split('\n'):
187 installed_pkgs.append(pkg.strip())
188
189 return installed_pkgs
190
191
192class RpmManifest(Manifest):
193 """
194 Returns a dictionary object with mip and mlp packages.
195 """
196 def _split_multilib(self, pkg_list):
197 pkgs = dict()
198
199 for pkg in pkg_list.split():
200 pkg_type = self.PKG_TYPE_MUST_INSTALL
201
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500202 ml_variants = self.d.getVar('MULTILIB_VARIANTS').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500203
204 for ml_variant in ml_variants:
205 if pkg.startswith(ml_variant + '-'):
206 pkg_type = self.PKG_TYPE_MULTILIB
207
208 if not pkg_type in pkgs:
209 pkgs[pkg_type] = pkg
210 else:
211 pkgs[pkg_type] += " " + pkg
212
213 return pkgs
214
215 def create_initial(self):
216 pkgs = dict()
217
218 with open(self.initial_manifest, "w+") as manifest:
219 manifest.write(self.initial_manifest_file_header)
220
221 for var in self.var_maps[self.manifest_type]:
222 if var in self.vars_to_split:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500223 split_pkgs = self._split_multilib(self.d.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224 if split_pkgs is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600225 pkgs = dict(list(pkgs.items()) + list(split_pkgs.items()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500226 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500227 pkg_list = self.d.getVar(var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500228 if pkg_list is not None:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500229 pkgs[self.var_maps[self.manifest_type][var]] = self.d.getVar(var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500230
231 for pkg_type in pkgs:
232 for pkg in pkgs[pkg_type].split():
233 manifest.write("%s,%s\n" % (pkg_type, pkg))
234
235 def create_final(self):
236 pass
237
238 def create_full(self, pm):
239 pass
240
241
242class OpkgManifest(Manifest):
243 """
244 Returns a dictionary object with mip and mlp packages.
245 """
246 def _split_multilib(self, pkg_list):
247 pkgs = dict()
248
249 for pkg in pkg_list.split():
250 pkg_type = self.PKG_TYPE_MUST_INSTALL
251
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500252 ml_variants = self.d.getVar('MULTILIB_VARIANTS').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500253
254 for ml_variant in ml_variants:
255 if pkg.startswith(ml_variant + '-'):
256 pkg_type = self.PKG_TYPE_MULTILIB
257
258 if not pkg_type in pkgs:
259 pkgs[pkg_type] = pkg
260 else:
261 pkgs[pkg_type] += " " + pkg
262
263 return pkgs
264
265 def create_initial(self):
266 pkgs = dict()
267
268 with open(self.initial_manifest, "w+") as manifest:
269 manifest.write(self.initial_manifest_file_header)
270
271 for var in self.var_maps[self.manifest_type]:
272 if var in self.vars_to_split:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500273 split_pkgs = self._split_multilib(self.d.getVar(var))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500274 if split_pkgs is not None:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600275 pkgs = dict(list(pkgs.items()) + list(split_pkgs.items()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500276 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500277 pkg_list = self.d.getVar(var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500278 if pkg_list is not None:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500279 pkgs[self.var_maps[self.manifest_type][var]] = self.d.getVar(var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280
Brad Bishop316dfdd2018-06-25 12:45:53 -0400281 for pkg_type in sorted(pkgs):
282 for pkg in sorted(pkgs[pkg_type].split()):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500283 manifest.write("%s,%s\n" % (pkg_type, pkg))
284
285 def create_final(self):
286 pass
287
288 def create_full(self, pm):
289 if not os.path.exists(self.initial_manifest):
290 self.create_initial()
291
292 initial_manifest = self.parse_initial_manifest()
293 pkgs_to_install = list()
294 for pkg_type in initial_manifest:
295 pkgs_to_install += initial_manifest[pkg_type]
296 if len(pkgs_to_install) == 0:
297 return
298
299 output = pm.dummy_install(pkgs_to_install)
300
301 with open(self.full_manifest, 'w+') as manifest:
302 pkg_re = re.compile('^Installing ([^ ]+) [^ ].*')
303 for line in set(output.split('\n')):
304 m = pkg_re.match(line)
305 if m:
306 manifest.write(m.group(1) + '\n')
307
308 return
309
310
311class DpkgManifest(Manifest):
312 def create_initial(self):
313 with open(self.initial_manifest, "w+") as manifest:
314 manifest.write(self.initial_manifest_file_header)
315
316 for var in self.var_maps[self.manifest_type]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500317 pkg_list = self.d.getVar(var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500318
319 if pkg_list is None:
320 continue
321
322 for pkg in pkg_list.split():
323 manifest.write("%s,%s\n" %
324 (self.var_maps[self.manifest_type][var], pkg))
325
326 def create_final(self):
327 pass
328
329 def create_full(self, pm):
330 pass
331
332
333def create_manifest(d, final_manifest=False, manifest_dir=None,
334 manifest_type=Manifest.MANIFEST_TYPE_IMAGE):
335 manifest_map = {'rpm': RpmManifest,
336 'ipk': OpkgManifest,
337 'deb': DpkgManifest}
338
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500339 manifest = manifest_map[d.getVar('IMAGE_PKGTYPE')](d, manifest_dir, manifest_type)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500340
341 if final_manifest:
342 manifest.create_final()
343 else:
344 manifest.create_initial()
345
346
347if __name__ == "__main__":
348 pass