diff options
Diffstat (limited to 'meta/lib/oe/packagedata.py')
-rw-r--r-- | meta/lib/oe/packagedata.py | 276 |
1 files changed, 272 insertions, 4 deletions
diff --git a/meta/lib/oe/packagedata.py b/meta/lib/oe/packagedata.py index a82085a792..2d1d6ddeb7 100644 --- a/meta/lib/oe/packagedata.py +++ b/meta/lib/oe/packagedata.py | |||
@@ -1,9 +1,16 @@ | |||
1 | # | 1 | # |
2 | # Copyright OpenEmbedded Contributors | ||
3 | # | ||
2 | # SPDX-License-Identifier: GPL-2.0-only | 4 | # SPDX-License-Identifier: GPL-2.0-only |
3 | # | 5 | # |
4 | 6 | ||
5 | import codecs | 7 | import codecs |
6 | import os | 8 | import os |
9 | import json | ||
10 | import bb.compress.zstd | ||
11 | import oe.path | ||
12 | |||
13 | from glob import glob | ||
7 | 14 | ||
8 | def packaged(pkg, d): | 15 | def packaged(pkg, d): |
9 | return os.access(get_subpkgedata_fn(pkg, d) + '.packaged', os.R_OK) | 16 | return os.access(get_subpkgedata_fn(pkg, d) + '.packaged', os.R_OK) |
@@ -19,7 +26,7 @@ def read_pkgdatafile(fn): | |||
19 | import re | 26 | import re |
20 | with open(fn, 'r') as f: | 27 | with open(fn, 'r') as f: |
21 | lines = f.readlines() | 28 | lines = f.readlines() |
22 | r = re.compile("([^:]+):\s*(.*)") | 29 | r = re.compile(r"(^.+?):\s+(.*)") |
23 | for l in lines: | 30 | for l in lines: |
24 | m = r.match(l) | 31 | m = r.match(l) |
25 | if m: | 32 | if m: |
@@ -45,18 +52,30 @@ def read_pkgdata(pn, d): | |||
45 | return read_pkgdatafile(fn) | 52 | return read_pkgdatafile(fn) |
46 | 53 | ||
47 | # | 54 | # |
48 | # Collapse FOO_pkg variables into FOO | 55 | # Collapse FOO:pkg variables into FOO |
49 | # | 56 | # |
50 | def read_subpkgdata_dict(pkg, d): | 57 | def read_subpkgdata_dict(pkg, d): |
51 | ret = {} | 58 | ret = {} |
52 | subd = read_pkgdatafile(get_subpkgedata_fn(pkg, d)) | 59 | subd = read_pkgdatafile(get_subpkgedata_fn(pkg, d)) |
53 | for var in subd: | 60 | for var in subd: |
54 | newvar = var.replace("_" + pkg, "") | 61 | newvar = var.replace(":" + pkg, "") |
55 | if newvar == var and var + "_" + pkg in subd: | 62 | if newvar == var and var + ":" + pkg in subd: |
56 | continue | 63 | continue |
57 | ret[newvar] = subd[var] | 64 | ret[newvar] = subd[var] |
58 | return ret | 65 | return ret |
59 | 66 | ||
67 | def read_subpkgdata_extended(pkg, d): | ||
68 | import json | ||
69 | import bb.compress.zstd | ||
70 | |||
71 | fn = d.expand("${PKGDATA_DIR}/extended/%s.json.zstd" % pkg) | ||
72 | try: | ||
73 | num_threads = int(d.getVar("BB_NUMBER_THREADS")) | ||
74 | with bb.compress.zstd.open(fn, "rt", encoding="utf-8", num_threads=num_threads) as f: | ||
75 | return json.load(f) | ||
76 | except FileNotFoundError: | ||
77 | return None | ||
78 | |||
60 | def _pkgmap(d): | 79 | def _pkgmap(d): |
61 | """Return a dictionary mapping package to recipe name.""" | 80 | """Return a dictionary mapping package to recipe name.""" |
62 | 81 | ||
@@ -96,3 +115,252 @@ def recipename(pkg, d): | |||
96 | """Return the recipe name for the given binary package name.""" | 115 | """Return the recipe name for the given binary package name.""" |
97 | 116 | ||
98 | return pkgmap(d).get(pkg) | 117 | return pkgmap(d).get(pkg) |
118 | |||
119 | def foreach_runtime_provider_pkgdata(d, rdep, include_rdep=False): | ||
120 | pkgdata_dir = d.getVar("PKGDATA_DIR") | ||
121 | possibles = set() | ||
122 | try: | ||
123 | possibles |= set(os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdep))) | ||
124 | except OSError: | ||
125 | pass | ||
126 | |||
127 | if include_rdep: | ||
128 | possibles.add(rdep) | ||
129 | |||
130 | for p in sorted(list(possibles)): | ||
131 | rdep_data = read_subpkgdata(p, d) | ||
132 | yield p, rdep_data | ||
133 | |||
134 | def get_package_mapping(pkg, basepkg, d, depversions=None): | ||
135 | import oe.packagedata | ||
136 | |||
137 | data = oe.packagedata.read_subpkgdata(pkg, d) | ||
138 | key = "PKG:%s" % pkg | ||
139 | |||
140 | if key in data: | ||
141 | if bb.data.inherits_class('allarch', d) and bb.data.inherits_class('packagegroup', d) and pkg != data[key]: | ||
142 | bb.error("An allarch packagegroup shouldn't depend on packages which are dynamically renamed (%s to %s)" % (pkg, data[key])) | ||
143 | # Have to avoid undoing the write_extra_pkgs(global_variants...) | ||
144 | if bb.data.inherits_class('allarch', d) and not d.getVar('MULTILIB_VARIANTS') \ | ||
145 | and data[key] == basepkg: | ||
146 | return pkg | ||
147 | if depversions == []: | ||
148 | # Avoid returning a mapping if the renamed package rprovides its original name | ||
149 | rprovkey = "RPROVIDES:%s" % pkg | ||
150 | if rprovkey in data: | ||
151 | if pkg in bb.utils.explode_dep_versions2(data[rprovkey]): | ||
152 | bb.note("%s rprovides %s, not replacing the latter" % (data[key], pkg)) | ||
153 | return pkg | ||
154 | # Do map to rewritten package name | ||
155 | return data[key] | ||
156 | |||
157 | return pkg | ||
158 | |||
159 | def get_package_additional_metadata(pkg_type, d): | ||
160 | base_key = "PACKAGE_ADD_METADATA" | ||
161 | for key in ("%s_%s" % (base_key, pkg_type.upper()), base_key): | ||
162 | if d.getVar(key, False) is None: | ||
163 | continue | ||
164 | d.setVarFlag(key, "type", "list") | ||
165 | if d.getVarFlag(key, "separator") is None: | ||
166 | d.setVarFlag(key, "separator", "\\n") | ||
167 | metadata_fields = [field.strip() for field in oe.data.typed_value(key, d)] | ||
168 | return "\n".join(metadata_fields).strip() | ||
169 | |||
170 | def runtime_mapping_rename(varname, pkg, d): | ||
171 | #bb.note("%s before: %s" % (varname, d.getVar(varname))) | ||
172 | |||
173 | new_depends = {} | ||
174 | deps = bb.utils.explode_dep_versions2(d.getVar(varname) or "") | ||
175 | for depend, depversions in deps.items(): | ||
176 | new_depend = get_package_mapping(depend, pkg, d, depversions) | ||
177 | if depend != new_depend: | ||
178 | bb.note("package name mapping done: %s -> %s" % (depend, new_depend)) | ||
179 | new_depends[new_depend] = deps[depend] | ||
180 | |||
181 | d.setVar(varname, bb.utils.join_deps(new_depends, commasep=False)) | ||
182 | |||
183 | #bb.note("%s after: %s" % (varname, d.getVar(varname))) | ||
184 | |||
185 | def emit_pkgdata(pkgfiles, d): | ||
186 | def process_postinst_on_target(pkg, mlprefix): | ||
187 | pkgval = d.getVar('PKG:%s' % pkg) | ||
188 | if pkgval is None: | ||
189 | pkgval = pkg | ||
190 | |||
191 | defer_fragment = """ | ||
192 | if [ -n "$D" ]; then | ||
193 | $INTERCEPT_DIR/postinst_intercept delay_to_first_boot %s mlprefix=%s | ||
194 | exit 0 | ||
195 | fi | ||
196 | """ % (pkgval, mlprefix) | ||
197 | |||
198 | postinst = d.getVar('pkg_postinst:%s' % pkg) | ||
199 | postinst_ontarget = d.getVar('pkg_postinst_ontarget:%s' % pkg) | ||
200 | |||
201 | if postinst_ontarget: | ||
202 | bb.debug(1, 'adding deferred pkg_postinst_ontarget() to pkg_postinst() for %s' % pkg) | ||
203 | if not postinst: | ||
204 | postinst = '#!/bin/sh\n' | ||
205 | postinst += defer_fragment | ||
206 | postinst += postinst_ontarget | ||
207 | d.setVar('pkg_postinst:%s' % pkg, postinst) | ||
208 | |||
209 | def add_set_e_to_scriptlets(pkg): | ||
210 | for scriptlet_name in ('pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm'): | ||
211 | scriptlet = d.getVar('%s:%s' % (scriptlet_name, pkg)) | ||
212 | if scriptlet: | ||
213 | scriptlet_split = scriptlet.split('\n') | ||
214 | if scriptlet_split[0].startswith("#!"): | ||
215 | scriptlet = scriptlet_split[0] + "\nset -e\n" + "\n".join(scriptlet_split[1:]) | ||
216 | else: | ||
217 | scriptlet = "set -e\n" + "\n".join(scriptlet_split[0:]) | ||
218 | d.setVar('%s:%s' % (scriptlet_name, pkg), scriptlet) | ||
219 | |||
220 | def write_if_exists(f, pkg, var): | ||
221 | def encode(str): | ||
222 | import codecs | ||
223 | c = codecs.getencoder("unicode_escape") | ||
224 | return c(str)[0].decode("latin1") | ||
225 | |||
226 | val = d.getVar('%s:%s' % (var, pkg)) | ||
227 | if val: | ||
228 | f.write('%s:%s: %s\n' % (var, pkg, encode(val))) | ||
229 | return val | ||
230 | val = d.getVar('%s' % (var)) | ||
231 | if val: | ||
232 | f.write('%s: %s\n' % (var, encode(val))) | ||
233 | return val | ||
234 | |||
235 | def write_extra_pkgs(variants, pn, packages, pkgdatadir): | ||
236 | for variant in variants: | ||
237 | with open("%s/%s-%s" % (pkgdatadir, variant, pn), 'w') as fd: | ||
238 | fd.write("PACKAGES: %s\n" % ' '.join( | ||
239 | map(lambda pkg: '%s-%s' % (variant, pkg), packages.split()))) | ||
240 | |||
241 | def write_extra_runtime_pkgs(variants, packages, pkgdatadir): | ||
242 | for variant in variants: | ||
243 | for pkg in packages.split(): | ||
244 | ml_pkg = "%s-%s" % (variant, pkg) | ||
245 | subdata_file = "%s/runtime/%s" % (pkgdatadir, ml_pkg) | ||
246 | with open(subdata_file, 'w') as fd: | ||
247 | fd.write("PKG:%s: %s" % (ml_pkg, pkg)) | ||
248 | |||
249 | packages = d.getVar('PACKAGES') | ||
250 | pkgdest = d.getVar('PKGDEST') | ||
251 | pkgdatadir = d.getVar('PKGDESTWORK') | ||
252 | |||
253 | data_file = pkgdatadir + d.expand("/${PN}") | ||
254 | with open(data_file, 'w') as fd: | ||
255 | fd.write("PACKAGES: %s\n" % packages) | ||
256 | |||
257 | pkgdebugsource = d.getVar("PKGDEBUGSOURCES") or [] | ||
258 | |||
259 | pn = d.getVar('PN') | ||
260 | global_variants = (d.getVar('MULTILIB_GLOBAL_VARIANTS') or "").split() | ||
261 | variants = (d.getVar('MULTILIB_VARIANTS') or "").split() | ||
262 | |||
263 | if bb.data.inherits_class('kernel', d) or bb.data.inherits_class('module-base', d): | ||
264 | write_extra_pkgs(variants, pn, packages, pkgdatadir) | ||
265 | |||
266 | if bb.data.inherits_class('allarch', d) and not variants \ | ||
267 | and not bb.data.inherits_class('packagegroup', d): | ||
268 | write_extra_pkgs(global_variants, pn, packages, pkgdatadir) | ||
269 | |||
270 | workdir = d.getVar('WORKDIR') | ||
271 | |||
272 | for pkg in packages.split(): | ||
273 | pkgval = d.getVar('PKG:%s' % pkg) | ||
274 | if pkgval is None: | ||
275 | pkgval = pkg | ||
276 | d.setVar('PKG:%s' % pkg, pkg) | ||
277 | |||
278 | extended_data = { | ||
279 | "files_info": {} | ||
280 | } | ||
281 | |||
282 | pkgdestpkg = os.path.join(pkgdest, pkg) | ||
283 | files = {} | ||
284 | files_extra = {} | ||
285 | total_size = 0 | ||
286 | seen = set() | ||
287 | for f in pkgfiles[pkg]: | ||
288 | fpath = os.sep + os.path.relpath(f, pkgdestpkg) | ||
289 | |||
290 | fstat = os.lstat(f) | ||
291 | files[fpath] = fstat.st_size | ||
292 | |||
293 | extended_data["files_info"].setdefault(fpath, {}) | ||
294 | extended_data["files_info"][fpath]['size'] = fstat.st_size | ||
295 | |||
296 | if fstat.st_ino not in seen: | ||
297 | seen.add(fstat.st_ino) | ||
298 | total_size += fstat.st_size | ||
299 | |||
300 | if fpath in pkgdebugsource: | ||
301 | extended_data["files_info"][fpath]['debugsrc'] = pkgdebugsource[fpath] | ||
302 | del pkgdebugsource[fpath] | ||
303 | |||
304 | d.setVar('FILES_INFO:' + pkg , json.dumps(files, sort_keys=True)) | ||
305 | |||
306 | process_postinst_on_target(pkg, d.getVar("MLPREFIX")) | ||
307 | add_set_e_to_scriptlets(pkg) | ||
308 | |||
309 | subdata_file = pkgdatadir + "/runtime/%s" % pkg | ||
310 | with open(subdata_file, 'w') as sf: | ||
311 | for var in (d.getVar('PKGDATA_VARS') or "").split(): | ||
312 | val = write_if_exists(sf, pkg, var) | ||
313 | |||
314 | write_if_exists(sf, pkg, 'FILERPROVIDESFLIST') | ||
315 | for dfile in sorted((d.getVar('FILERPROVIDESFLIST:' + pkg) or "").split()): | ||
316 | write_if_exists(sf, pkg, 'FILERPROVIDES:' + dfile) | ||
317 | |||
318 | write_if_exists(sf, pkg, 'FILERDEPENDSFLIST') | ||
319 | for dfile in sorted((d.getVar('FILERDEPENDSFLIST:' + pkg) or "").split()): | ||
320 | write_if_exists(sf, pkg, 'FILERDEPENDS:' + dfile) | ||
321 | |||
322 | sf.write('%s:%s: %d\n' % ('PKGSIZE', pkg, total_size)) | ||
323 | |||
324 | subdata_extended_file = pkgdatadir + "/extended/%s.json.zstd" % pkg | ||
325 | num_threads = int(d.getVar("BB_NUMBER_THREADS")) | ||
326 | with bb.compress.zstd.open(subdata_extended_file, "wt", encoding="utf-8", num_threads=num_threads) as f: | ||
327 | json.dump(extended_data, f, sort_keys=True, separators=(",", ":")) | ||
328 | |||
329 | # Symlinks needed for rprovides lookup | ||
330 | rprov = d.getVar('RPROVIDES:%s' % pkg) or d.getVar('RPROVIDES') | ||
331 | if rprov: | ||
332 | for p in bb.utils.explode_deps(rprov): | ||
333 | subdata_sym = pkgdatadir + "/runtime-rprovides/%s/%s" % (p, pkg) | ||
334 | bb.utils.mkdirhier(os.path.dirname(subdata_sym)) | ||
335 | oe.path.relsymlink(subdata_file, subdata_sym, True) | ||
336 | |||
337 | allow_empty = d.getVar('ALLOW_EMPTY:%s' % pkg) | ||
338 | if not allow_empty: | ||
339 | allow_empty = d.getVar('ALLOW_EMPTY') | ||
340 | root = "%s/%s" % (pkgdest, pkg) | ||
341 | os.chdir(root) | ||
342 | g = glob('*') | ||
343 | if g or allow_empty == "1": | ||
344 | # Symlinks needed for reverse lookups (from the final package name) | ||
345 | subdata_sym = pkgdatadir + "/runtime-reverse/%s" % pkgval | ||
346 | oe.path.relsymlink(subdata_file, subdata_sym, True) | ||
347 | |||
348 | packagedfile = pkgdatadir + '/runtime/%s.packaged' % pkg | ||
349 | open(packagedfile, 'w').close() | ||
350 | |||
351 | if bb.data.inherits_class('kernel', d) or bb.data.inherits_class('module-base', d): | ||
352 | write_extra_runtime_pkgs(variants, packages, pkgdatadir) | ||
353 | |||
354 | if bb.data.inherits_class('allarch', d) and not variants \ | ||
355 | and not bb.data.inherits_class('packagegroup', d): | ||
356 | write_extra_runtime_pkgs(global_variants, packages, pkgdatadir) | ||
357 | |||
358 | def mapping_rename_hook(d): | ||
359 | """ | ||
360 | Rewrite variables to account for package renaming in things | ||
361 | like debian.bbclass or manual PKG variable name changes | ||
362 | """ | ||
363 | pkg = d.getVar("PKG") | ||
364 | oe.packagedata.runtime_mapping_rename("RDEPENDS", pkg, d) | ||
365 | oe.packagedata.runtime_mapping_rename("RRECOMMENDS", pkg, d) | ||
366 | oe.packagedata.runtime_mapping_rename("RSUGGESTS", pkg, d) | ||