blob: 81a2060b68db0786c117fd280c241ee292fcfa2c [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7inherit package
8
9IMAGE_PKGTYPE ?= "rpm"
10
11RPM="rpm"
12RPMBUILD="rpmbuild"
13
14PKGWRITEDIRRPM = "${WORKDIR}/deploy-rpms"
15
16# Maintaining the perfile dependencies has singificant overhead when writing the
17# packages. When set, this value merges them for efficiency.
18MERGEPERFILEDEPS = "1"
19
20# Filter dependencies based on a provided function.
21def filter_deps(var, f):
22 import collections
23
24 depends_dict = bb.utils.explode_dep_versions2(var)
25 newdeps_dict = collections.OrderedDict()
26 for dep in depends_dict:
27 if f(dep):
28 newdeps_dict[dep] = depends_dict[dep]
29 return bb.utils.join_deps(newdeps_dict, commasep=False)
30
31# Filter out absolute paths (typically /bin/sh and /usr/bin/env) and any perl
32# dependencies for nativesdk packages.
33def filter_nativesdk_deps(srcname, var):
34 if var and srcname.startswith("nativesdk-"):
35 var = filter_deps(var, lambda dep: not dep.startswith('/') and dep != 'perl' and not dep.startswith('perl('))
36 return var
37
38# Construct per file dependencies file
39def write_rpm_perfiledata(srcname, d):
40 workdir = d.getVar('WORKDIR')
41 packages = d.getVar('PACKAGES')
42 pkgd = d.getVar('PKGD')
43
44 def dump_filerdeps(varname, outfile, d):
45 outfile.write("#!/usr/bin/env python3\n\n")
46 outfile.write("# Dependency table\n")
47 outfile.write('deps = {\n')
48 for pkg in packages.split():
49 dependsflist_key = 'FILE' + varname + 'FLIST' + ":" + pkg
50 dependsflist = (d.getVar(dependsflist_key) or "")
51 for dfile in dependsflist.split():
52 key = "FILE" + varname + ":" + dfile + ":" + pkg
53 deps = filter_nativesdk_deps(srcname, d.getVar(key) or "")
54 depends_dict = bb.utils.explode_dep_versions(deps)
55 file = dfile.replace("@underscore@", "_")
56 file = file.replace("@closebrace@", "]")
57 file = file.replace("@openbrace@", "[")
58 file = file.replace("@tab@", "\t")
59 file = file.replace("@space@", " ")
60 file = file.replace("@at@", "@")
61 outfile.write('"' + pkgd + file + '" : "')
62 for dep in depends_dict:
63 ver = depends_dict[dep]
64 if dep and ver:
65 ver = ver.replace("(","")
66 ver = ver.replace(")","")
67 outfile.write(dep + " " + ver + " ")
68 else:
69 outfile.write(dep + " ")
70 outfile.write('",\n')
71 outfile.write('}\n\n')
72 outfile.write("import sys\n")
73 outfile.write("while 1:\n")
74 outfile.write("\tline = sys.stdin.readline().strip()\n")
75 outfile.write("\tif not line:\n")
76 outfile.write("\t\tsys.exit(0)\n")
77 outfile.write("\tif line in deps:\n")
78 outfile.write("\t\tprint(deps[line] + '\\n')\n")
79
80 # OE-core dependencies a.k.a. RPM requires
81 outdepends = workdir + "/" + srcname + ".requires"
82
83 dependsfile = open(outdepends, 'w')
84
85 dump_filerdeps('RDEPENDS', dependsfile, d)
86
87 dependsfile.close()
88 os.chmod(outdepends, 0o755)
89
90 # OE-core / RPM Provides
91 outprovides = workdir + "/" + srcname + ".provides"
92
93 providesfile = open(outprovides, 'w')
94
95 dump_filerdeps('RPROVIDES', providesfile, d)
96
97 providesfile.close()
98 os.chmod(outprovides, 0o755)
99
100 return (outdepends, outprovides)
101
102
103python write_specfile () {
104 import oe.packagedata
105
106 # append information for logs and patches to %prep
107 def add_prep(d,spec_files_bottom):
108 if d.getVarFlag('ARCHIVER_MODE', 'srpm') == '1' and bb.data.inherits_class('archiver', d):
109 spec_files_bottom.append('%%prep -n %s' % d.getVar('PN') )
110 spec_files_bottom.append('%s' % "echo \"include logs and patches, Please check them in SOURCES\"")
111 spec_files_bottom.append('')
112
113 # append the name of tarball to key word 'SOURCE' in xxx.spec.
114 def tail_source(d):
115 if d.getVarFlag('ARCHIVER_MODE', 'srpm') == '1' and bb.data.inherits_class('archiver', d):
116 ar_outdir = d.getVar('ARCHIVER_OUTDIR')
117 if not os.path.exists(ar_outdir):
118 return
119 source_list = os.listdir(ar_outdir)
120 source_number = 0
121 for source in source_list:
122 # do_deploy_archives may have already run (from sstate) meaning a .src.rpm may already
123 # exist in ARCHIVER_OUTDIR so skip if present.
124 if source.endswith(".src.rpm"):
125 continue
126 # The rpmbuild doesn't need the root permission, but it needs
127 # to know the file's user and group name, the only user and
128 # group in fakeroot is "root" when working in fakeroot.
129 f = os.path.join(ar_outdir, source)
130 os.chown(f, 0, 0)
131 spec_preamble_top.append('Source%s: %s' % (source_number, source))
132 source_number += 1
133
134 # In RPM, dependencies are of the format: pkg <>= Epoch:Version-Release
135 # This format is similar to OE, however there are restrictions on the
136 # characters that can be in a field. In the Version field, "-"
137 # characters are not allowed. "-" is allowed in the Release field.
138 #
139 # We translate the "-" in the version to a "+", by loading the PKGV
140 # from the dependent recipe, replacing the - with a +, and then using
141 # that value to do a replace inside of this recipe's dependencies.
142 # This preserves the "-" separator between the version and release, as
143 # well as any "-" characters inside of the release field.
144 #
145 # All of this has to happen BEFORE the mapping_rename_hook as
146 # after renaming we cannot look up the dependencies in the packagedata
147 # store.
148 def translate_vers(varname, d):
149 depends = d.getVar(varname)
150 if depends:
151 depends_dict = bb.utils.explode_dep_versions2(depends)
152 newdeps_dict = {}
153 for dep in depends_dict:
154 verlist = []
155 for ver in depends_dict[dep]:
156 if '-' in ver:
157 subd = oe.packagedata.read_subpkgdata_dict(dep, d)
158 if 'PKGV' in subd:
159 pv = subd['PV']
160 pkgv = subd['PKGV']
161 reppv = pkgv.replace('-', '+')
162 ver = ver.replace(pv, reppv).replace(pkgv, reppv)
163 if 'PKGR' in subd:
164 # Make sure PKGR rather than PR in ver
165 pr = '-' + subd['PR']
166 pkgr = '-' + subd['PKGR']
167 if pkgr not in ver:
168 ver = ver.replace(pr, pkgr)
169 verlist.append(ver)
170 else:
171 verlist.append(ver)
172 newdeps_dict[dep] = verlist
173 depends = bb.utils.join_deps(newdeps_dict)
174 d.setVar(varname, depends.strip())
175
176 # We need to change the style the dependency from BB to RPM
177 # This needs to happen AFTER the mapping_rename_hook
178 def print_deps(variable, tag, array, d):
179 depends = variable
180 if depends:
181 depends_dict = bb.utils.explode_dep_versions2(depends)
182 for dep in depends_dict:
183 for ver in depends_dict[dep]:
184 ver = ver.replace('(', '')
185 ver = ver.replace(')', '')
186 array.append("%s: %s %s" % (tag, dep, ver))
187 if not len(depends_dict[dep]):
188 array.append("%s: %s" % (tag, dep))
189
190 def walk_files(walkpath, target, conffiles, dirfiles):
191 # We can race against the ipk/deb backends which create CONTROL or DEBIAN directories
192 # when packaging. We just ignore these files which are created in
193 # packages-split/ and not package/
194 # We have the odd situation where the CONTROL/DEBIAN directory can be removed in the middle of
195 # of the walk, the isdir() test would then fail and the walk code would assume its a file
196 # hence we check for the names in files too.
197 for rootpath, dirs, files in os.walk(walkpath):
198 path = rootpath.replace(walkpath, "")
199 if path.endswith("DEBIAN") or path.endswith("CONTROL"):
200 continue
201 path = path.replace("%", "%%%%%%%%")
202
203 # Treat all symlinks to directories as normal files.
204 # os.walk() lists them as directories.
205 def move_to_files(dir):
206 if os.path.islink(os.path.join(rootpath, dir)):
207 files.append(dir)
208 return True
209 else:
210 return False
211 dirs[:] = [dir for dir in dirs if not move_to_files(dir)]
212
213 # Directory handling can happen in two ways, either DIRFILES is not set at all
214 # in which case we fall back to the older behaviour of packages owning all their
215 # directories
216 if dirfiles is None:
217 for dir in dirs:
218 if dir == "CONTROL" or dir == "DEBIAN":
219 continue
220 dir = dir.replace("%", "%%%%%%%%")
221 # All packages own the directories their files are in...
222 target.append('%dir "' + path + '/' + dir + '"')
223 else:
224 # packages own only empty directories or explict directory.
225 # This will prevent the overlapping of security permission.
226 if path and not files and not dirs:
227 target.append('%dir "' + path + '"')
228 elif path and path in dirfiles:
229 target.append('%dir "' + path + '"')
230
231 for file in files:
232 if file == "CONTROL" or file == "DEBIAN":
233 continue
234 file = file.replace("%", "%%%%%%%%")
235 if conffiles.count(path + '/' + file):
236 target.append('%config "' + path + '/' + file + '"')
237 else:
238 target.append('"' + path + '/' + file + '"')
239
240 # Prevent the prerm/postrm scripts from being run during an upgrade
241 def wrap_uninstall(scriptvar):
242 scr = scriptvar.strip()
243 if scr.startswith("#!"):
244 pos = scr.find("\n") + 1
245 else:
246 pos = 0
247 scr = scr[:pos] + 'if [ "$1" = "0" ] ; then\n' + scr[pos:] + '\nfi'
248 return scr
249
250 def get_perfile(varname, pkg, d):
251 deps = []
252 dependsflist_key = 'FILE' + varname + 'FLIST' + ":" + pkg
253 dependsflist = (d.getVar(dependsflist_key) or "")
254 for dfile in dependsflist.split():
255 key = "FILE" + varname + ":" + dfile + ":" + pkg
256 depends = d.getVar(key)
257 if depends:
258 deps.append(depends)
259 return " ".join(deps)
260
261 def append_description(spec_preamble, text):
262 """
263 Add the description to the spec file.
264 """
265 import textwrap
266 dedent_text = textwrap.dedent(text).strip()
267 # Bitbake saves "\n" as "\\n"
268 if '\\n' in dedent_text:
269 for t in dedent_text.split('\\n'):
270 spec_preamble.append(t.strip())
271 else:
272 spec_preamble.append('%s' % textwrap.fill(dedent_text, width=75))
273
274 packages = d.getVar('PACKAGES')
275 if not packages or packages == '':
276 bb.debug(1, "No packages; nothing to do")
277 return
278
279 pkgdest = d.getVar('PKGDEST')
280 if not pkgdest:
281 bb.fatal("No PKGDEST")
282
283 outspecfile = d.getVar('OUTSPECFILE')
284 if not outspecfile:
285 bb.fatal("No OUTSPECFILE")
286
287 # Construct the SPEC file...
288 srcname = d.getVar('PN')
289 localdata = bb.data.createCopy(d)
290 localdata.setVar('OVERRIDES', d.getVar("OVERRIDES", False) + ":" + srcname)
291 srcsummary = (localdata.getVar('SUMMARY') or localdata.getVar('DESCRIPTION') or ".")
292 srcversion = localdata.getVar('PKGV').replace('-', '+')
293 srcrelease = localdata.getVar('PKGR')
294 srcepoch = (localdata.getVar('PKGE') or "")
295 srclicense = localdata.getVar('LICENSE')
296 srcsection = localdata.getVar('SECTION')
297 srcmaintainer = localdata.getVar('MAINTAINER')
298 srchomepage = localdata.getVar('HOMEPAGE')
299 srcdescription = localdata.getVar('DESCRIPTION') or "."
300 srccustomtagschunk = get_package_additional_metadata("rpm", localdata)
301
302 srcdepends = d.getVar('DEPENDS')
303 srcrdepends = ""
304 srcrrecommends = ""
305 srcrsuggests = ""
306 srcrprovides = ""
307 srcrreplaces = ""
308 srcrconflicts = ""
309 srcrobsoletes = ""
310
311 srcrpreinst = []
312 srcrpostinst = []
313 srcrprerm = []
314 srcrpostrm = []
315
316 spec_preamble_top = []
317 spec_preamble_bottom = []
318
319 spec_scriptlets_top = []
320 spec_scriptlets_bottom = []
321
322 spec_files_top = []
323 spec_files_bottom = []
324
325 perfiledeps = (d.getVar("MERGEPERFILEDEPS") or "0") == "0"
326 extra_pkgdata = (d.getVar("RPM_EXTRA_PKGDATA") or "0") == "1"
327
328 for pkg in packages.split():
329 localdata = bb.data.createCopy(d)
330
331 root = "%s/%s" % (pkgdest, pkg)
332
333 localdata.setVar('ROOT', '')
334 localdata.setVar('ROOT_%s' % pkg, root)
335 pkgname = localdata.getVar('PKG:%s' % pkg)
336 if not pkgname:
337 pkgname = pkg
338 localdata.setVar('PKG', pkgname)
339
340 localdata.setVar('OVERRIDES', d.getVar("OVERRIDES", False) + ":" + pkg)
341
342 conffiles = get_conffiles(pkg, d)
343 dirfiles = localdata.getVar('DIRFILES')
344 if dirfiles is not None:
345 dirfiles = dirfiles.split()
346
347 splitname = pkgname
348
349 splitsummary = (localdata.getVar('SUMMARY') or localdata.getVar('DESCRIPTION') or ".")
350 splitversion = (localdata.getVar('PKGV') or "").replace('-', '+')
351 splitrelease = (localdata.getVar('PKGR') or "")
352 splitepoch = (localdata.getVar('PKGE') or "")
353 splitlicense = (localdata.getVar('LICENSE') or "")
354 splitsection = (localdata.getVar('SECTION') or "")
355 splitdescription = (localdata.getVar('DESCRIPTION') or ".")
356 splitcustomtagschunk = get_package_additional_metadata("rpm", localdata)
357
358 translate_vers('RDEPENDS', localdata)
359 translate_vers('RRECOMMENDS', localdata)
360 translate_vers('RSUGGESTS', localdata)
361 translate_vers('RPROVIDES', localdata)
362 translate_vers('RREPLACES', localdata)
363 translate_vers('RCONFLICTS', localdata)
364
365 # Map the dependencies into their final form
366 mapping_rename_hook(localdata)
367
368 splitrdepends = localdata.getVar('RDEPENDS') or ""
369 splitrrecommends = localdata.getVar('RRECOMMENDS') or ""
370 splitrsuggests = localdata.getVar('RSUGGESTS') or ""
371 splitrprovides = localdata.getVar('RPROVIDES') or ""
372 splitrreplaces = localdata.getVar('RREPLACES') or ""
373 splitrconflicts = localdata.getVar('RCONFLICTS') or ""
374 splitrobsoletes = ""
375
376 splitrpreinst = localdata.getVar('pkg_preinst')
377 splitrpostinst = localdata.getVar('pkg_postinst')
378 splitrprerm = localdata.getVar('pkg_prerm')
379 splitrpostrm = localdata.getVar('pkg_postrm')
380
381
382 if not perfiledeps:
383 # Add in summary of per file dependencies
384 splitrdepends = splitrdepends + " " + get_perfile('RDEPENDS', pkg, d)
385 splitrprovides = splitrprovides + " " + get_perfile('RPROVIDES', pkg, d)
386
387 splitrdepends = filter_nativesdk_deps(srcname, splitrdepends)
388
389 # Gather special src/first package data
390 if srcname == splitname:
391 archiving = d.getVarFlag('ARCHIVER_MODE', 'srpm') == '1' and \
392 bb.data.inherits_class('archiver', d)
393 if archiving and srclicense != splitlicense:
394 bb.warn("The SRPM produced may not have the correct overall source license in the License tag. This is due to the LICENSE for the primary package and SRPM conflicting.")
395
396 srclicense = splitlicense
397 srcrdepends = splitrdepends
398 srcrrecommends = splitrrecommends
399 srcrsuggests = splitrsuggests
400 srcrprovides = splitrprovides
401 srcrreplaces = splitrreplaces
402 srcrconflicts = splitrconflicts
403
404 srcrpreinst = splitrpreinst
405 srcrpostinst = splitrpostinst
406 srcrprerm = splitrprerm
407 srcrpostrm = splitrpostrm
408
409 file_list = []
410 walk_files(root, file_list, conffiles, dirfiles)
411 if not file_list and localdata.getVar('ALLOW_EMPTY', False) != "1":
412 bb.note("Not creating empty RPM package for %s" % splitname)
413 else:
414 spec_files_top.append('%files')
415 if extra_pkgdata:
416 package_rpm_extra_pkgdata(splitname, spec_files_top, localdata)
417 spec_files_top.append('%defattr(-,-,-,-)')
418 if file_list:
419 bb.note("Creating RPM package for %s" % splitname)
420 spec_files_top.extend(file_list)
421 else:
422 bb.note("Creating empty RPM package for %s" % splitname)
423 spec_files_top.append('')
424 continue
425
426 # Process subpackage data
427 spec_preamble_bottom.append('%%package -n %s' % splitname)
428 spec_preamble_bottom.append('Summary: %s' % splitsummary)
429 if srcversion != splitversion:
430 spec_preamble_bottom.append('Version: %s' % splitversion)
431 if srcrelease != splitrelease:
432 spec_preamble_bottom.append('Release: %s' % splitrelease)
433 if srcepoch != splitepoch:
434 spec_preamble_bottom.append('Epoch: %s' % splitepoch)
435 spec_preamble_bottom.append('License: %s' % splitlicense)
436 spec_preamble_bottom.append('Group: %s' % splitsection)
437
438 if srccustomtagschunk != splitcustomtagschunk:
439 spec_preamble_bottom.append(splitcustomtagschunk)
440
441 # Replaces == Obsoletes && Provides
442 robsoletes = bb.utils.explode_dep_versions2(splitrobsoletes)
443 rprovides = bb.utils.explode_dep_versions2(splitrprovides)
444 rreplaces = bb.utils.explode_dep_versions2(splitrreplaces)
445 for dep in rreplaces:
446 if not dep in robsoletes:
447 robsoletes[dep] = rreplaces[dep]
448 if not dep in rprovides:
449 rprovides[dep] = rreplaces[dep]
450 splitrobsoletes = bb.utils.join_deps(robsoletes, commasep=False)
451 splitrprovides = bb.utils.join_deps(rprovides, commasep=False)
452
453 print_deps(splitrdepends, "Requires", spec_preamble_bottom, d)
454 if splitrpreinst:
455 print_deps(splitrdepends, "Requires(pre)", spec_preamble_bottom, d)
456 if splitrpostinst:
457 print_deps(splitrdepends, "Requires(post)", spec_preamble_bottom, d)
458 if splitrprerm:
459 print_deps(splitrdepends, "Requires(preun)", spec_preamble_bottom, d)
460 if splitrpostrm:
461 print_deps(splitrdepends, "Requires(postun)", spec_preamble_bottom, d)
462
463 print_deps(splitrrecommends, "Recommends", spec_preamble_bottom, d)
464 print_deps(splitrsuggests, "Suggests", spec_preamble_bottom, d)
465 print_deps(splitrprovides, "Provides", spec_preamble_bottom, d)
466 print_deps(splitrobsoletes, "Obsoletes", spec_preamble_bottom, d)
467 print_deps(splitrconflicts, "Conflicts", spec_preamble_bottom, d)
468
469 spec_preamble_bottom.append('')
470
471 spec_preamble_bottom.append('%%description -n %s' % splitname)
472 append_description(spec_preamble_bottom, splitdescription)
473
474 spec_preamble_bottom.append('')
475
476 # Now process scriptlets
477 if splitrpreinst:
478 spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
479 spec_scriptlets_bottom.append('# %s - preinst' % splitname)
480 spec_scriptlets_bottom.append(splitrpreinst)
481 spec_scriptlets_bottom.append('')
482 if splitrpostinst:
483 spec_scriptlets_bottom.append('%%post -n %s' % splitname)
484 spec_scriptlets_bottom.append('# %s - postinst' % splitname)
485 spec_scriptlets_bottom.append(splitrpostinst)
486 spec_scriptlets_bottom.append('')
487 if splitrprerm:
488 spec_scriptlets_bottom.append('%%preun -n %s' % splitname)
489 spec_scriptlets_bottom.append('# %s - prerm' % splitname)
490 scriptvar = wrap_uninstall(splitrprerm)
491 spec_scriptlets_bottom.append(scriptvar)
492 spec_scriptlets_bottom.append('')
493 if splitrpostrm:
494 spec_scriptlets_bottom.append('%%postun -n %s' % splitname)
495 spec_scriptlets_bottom.append('# %s - postrm' % splitname)
496 scriptvar = wrap_uninstall(splitrpostrm)
497 spec_scriptlets_bottom.append(scriptvar)
498 spec_scriptlets_bottom.append('')
499
500 # Now process files
501 file_list = []
502 walk_files(root, file_list, conffiles, dirfiles)
503 if not file_list and localdata.getVar('ALLOW_EMPTY', False) != "1":
504 bb.note("Not creating empty RPM package for %s" % splitname)
505 else:
506 spec_files_bottom.append('%%files -n %s' % splitname)
507 if extra_pkgdata:
508 package_rpm_extra_pkgdata(splitname, spec_files_bottom, localdata)
509 spec_files_bottom.append('%defattr(-,-,-,-)')
510 if file_list:
511 bb.note("Creating RPM package for %s" % splitname)
512 spec_files_bottom.extend(file_list)
513 else:
514 bb.note("Creating empty RPM package for %s" % splitname)
515 spec_files_bottom.append('')
516
517 del localdata
518
519 add_prep(d,spec_files_bottom)
520 spec_preamble_top.append('Summary: %s' % srcsummary)
521 spec_preamble_top.append('Name: %s' % srcname)
522 spec_preamble_top.append('Version: %s' % srcversion)
523 spec_preamble_top.append('Release: %s' % srcrelease)
524 if srcepoch and srcepoch.strip() != "":
525 spec_preamble_top.append('Epoch: %s' % srcepoch)
526 spec_preamble_top.append('License: %s' % srclicense)
527 spec_preamble_top.append('Group: %s' % srcsection)
528 spec_preamble_top.append('Packager: %s' % srcmaintainer)
529 if srchomepage:
530 spec_preamble_top.append('URL: %s' % srchomepage)
531 if srccustomtagschunk:
532 spec_preamble_top.append(srccustomtagschunk)
533 tail_source(d)
534
535 # Replaces == Obsoletes && Provides
536 robsoletes = bb.utils.explode_dep_versions2(srcrobsoletes)
537 rprovides = bb.utils.explode_dep_versions2(srcrprovides)
538 rreplaces = bb.utils.explode_dep_versions2(srcrreplaces)
539 for dep in rreplaces:
540 if not dep in robsoletes:
541 robsoletes[dep] = rreplaces[dep]
542 if not dep in rprovides:
543 rprovides[dep] = rreplaces[dep]
544 srcrobsoletes = bb.utils.join_deps(robsoletes, commasep=False)
545 srcrprovides = bb.utils.join_deps(rprovides, commasep=False)
546
547 print_deps(srcdepends, "BuildRequires", spec_preamble_top, d)
548 print_deps(srcrdepends, "Requires", spec_preamble_top, d)
549 if srcrpreinst:
550 print_deps(srcrdepends, "Requires(pre)", spec_preamble_top, d)
551 if srcrpostinst:
552 print_deps(srcrdepends, "Requires(post)", spec_preamble_top, d)
553 if srcrprerm:
554 print_deps(srcrdepends, "Requires(preun)", spec_preamble_top, d)
555 if srcrpostrm:
556 print_deps(srcrdepends, "Requires(postun)", spec_preamble_top, d)
557
558 print_deps(srcrrecommends, "Recommends", spec_preamble_top, d)
559 print_deps(srcrsuggests, "Suggests", spec_preamble_top, d)
560 print_deps(srcrprovides, "Provides", spec_preamble_top, d)
561 print_deps(srcrobsoletes, "Obsoletes", spec_preamble_top, d)
562 print_deps(srcrconflicts, "Conflicts", spec_preamble_top, d)
563
564 spec_preamble_top.append('')
565
566 spec_preamble_top.append('%description')
567 append_description(spec_preamble_top, srcdescription)
568
569 spec_preamble_top.append('')
570
571 if srcrpreinst:
572 spec_scriptlets_top.append('%pre')
573 spec_scriptlets_top.append('# %s - preinst' % srcname)
574 spec_scriptlets_top.append(srcrpreinst)
575 spec_scriptlets_top.append('')
576 if srcrpostinst:
577 spec_scriptlets_top.append('%post')
578 spec_scriptlets_top.append('# %s - postinst' % srcname)
579 spec_scriptlets_top.append(srcrpostinst)
580 spec_scriptlets_top.append('')
581 if srcrprerm:
582 spec_scriptlets_top.append('%preun')
583 spec_scriptlets_top.append('# %s - prerm' % srcname)
584 scriptvar = wrap_uninstall(srcrprerm)
585 spec_scriptlets_top.append(scriptvar)
586 spec_scriptlets_top.append('')
587 if srcrpostrm:
588 spec_scriptlets_top.append('%postun')
589 spec_scriptlets_top.append('# %s - postrm' % srcname)
590 scriptvar = wrap_uninstall(srcrpostrm)
591 spec_scriptlets_top.append(scriptvar)
592 spec_scriptlets_top.append('')
593
594 # Write the SPEC file
595 specfile = open(outspecfile, 'w')
596
597 # RPMSPEC_PREAMBLE is a way to add arbitrary text to the top
598 # of the generated spec file
599 external_preamble = d.getVar("RPMSPEC_PREAMBLE")
600 if external_preamble:
601 specfile.write(external_preamble + "\n")
602
603 for line in spec_preamble_top:
604 specfile.write(line + "\n")
605
606 for line in spec_preamble_bottom:
607 specfile.write(line + "\n")
608
609 for line in spec_scriptlets_top:
610 specfile.write(line + "\n")
611
612 for line in spec_scriptlets_bottom:
613 specfile.write(line + "\n")
614
615 for line in spec_files_top:
616 specfile.write(line + "\n")
617
618 for line in spec_files_bottom:
619 specfile.write(line + "\n")
620
621 specfile.close()
622}
623# Otherwise allarch packages may change depending on override configuration
624write_specfile[vardepsexclude] = "OVERRIDES"
625
626# Have to list any variables referenced as X_<pkg> that aren't in pkgdata here
627RPMEXTRAVARS = "PACKAGE_ADD_METADATA_RPM"
628write_specfile[vardeps] += "${@gen_packagevar(d, 'RPMEXTRAVARS')}"
629
630python do_package_rpm () {
631 workdir = d.getVar('WORKDIR')
632 tmpdir = d.getVar('TMPDIR')
633 pkgd = d.getVar('PKGD')
634 pkgdest = d.getVar('PKGDEST')
635 if not workdir or not pkgd or not tmpdir:
636 bb.error("Variables incorrectly set, unable to package")
637 return
638
639 packages = d.getVar('PACKAGES')
640 if not packages or packages == '':
641 bb.debug(1, "No packages; nothing to do")
642 return
643
644 # Construct the spec file...
645 # If the spec file already exist, and has not been stored into
646 # pseudo's files.db, it maybe cause rpmbuild src.rpm fail,
647 # so remove it before doing rpmbuild src.rpm.
648 srcname = d.getVar('PN')
649 outspecfile = workdir + "/" + srcname + ".spec"
650 if os.path.isfile(outspecfile):
651 os.remove(outspecfile)
652 d.setVar('OUTSPECFILE', outspecfile)
653 bb.build.exec_func('write_specfile', d)
654
655 perfiledeps = (d.getVar("MERGEPERFILEDEPS") or "0") == "0"
656 if perfiledeps:
657 outdepends, outprovides = write_rpm_perfiledata(srcname, d)
658
659 # Setup the rpmbuild arguments...
660 rpmbuild = d.getVar('RPMBUILD')
661 targetsys = d.getVar('TARGET_SYS')
662 targetvendor = d.getVar('HOST_VENDOR')
663
664 # Too many places in dnf stack assume that arch-independent packages are "noarch".
665 # Let's not fight against this.
666 package_arch = (d.getVar('PACKAGE_ARCH') or "").replace("-", "_")
667 if package_arch == "all":
668 package_arch = "noarch"
669
670 sdkpkgsuffix = (d.getVar('SDKPKGSUFFIX') or "nativesdk").replace("-", "_")
671 d.setVar('PACKAGE_ARCH_EXTEND', package_arch)
672 pkgwritedir = d.expand('${PKGWRITEDIRRPM}/${PACKAGE_ARCH_EXTEND}')
673 d.setVar('RPM_PKGWRITEDIR', pkgwritedir)
674 bb.debug(1, 'PKGWRITEDIR: %s' % d.getVar('RPM_PKGWRITEDIR'))
675 pkgarch = d.expand('${PACKAGE_ARCH_EXTEND}${HOST_VENDOR}-linux')
676 bb.utils.mkdirhier(pkgwritedir)
677 os.chmod(pkgwritedir, 0o755)
678
679 cmd = rpmbuild
680 cmd = cmd + " --noclean --nodeps --short-circuit --target " + pkgarch + " --buildroot " + pkgd
681 cmd = cmd + " --define '_topdir " + workdir + "' --define '_rpmdir " + pkgwritedir + "'"
682 cmd = cmd + " --define '_builddir " + d.getVar('B') + "'"
683 cmd = cmd + " --define '_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm'"
684 cmd = cmd + " --define '_use_internal_dependency_generator 0'"
685 cmd = cmd + " --define '_binaries_in_noarch_packages_terminate_build 0'"
686 cmd = cmd + " --define '_build_id_links none'"
687 cmd = cmd + " --define '_binary_payload w19T%d.zstdio'" % int(d.getVar("ZSTD_THREADS"))
688 cmd = cmd + " --define '_source_payload w19T%d.zstdio'" % int(d.getVar("ZSTD_THREADS"))
689 cmd = cmd + " --define 'clamp_mtime_to_source_date_epoch 1'"
690 cmd = cmd + " --define 'use_source_date_epoch_as_buildtime 1'"
691 cmd = cmd + " --define '_buildhost reproducible'"
692 cmd = cmd + " --define '__font_provides %{nil}'"
693 if perfiledeps:
694 cmd = cmd + " --define '__find_requires " + outdepends + "'"
695 cmd = cmd + " --define '__find_provides " + outprovides + "'"
696 else:
697 cmd = cmd + " --define '__find_requires %{nil}'"
698 cmd = cmd + " --define '__find_provides %{nil}'"
699 cmd = cmd + " --define '_unpackaged_files_terminate_build 0'"
700 cmd = cmd + " --define 'debug_package %{nil}'"
701 cmd = cmd + " --define '_tmppath " + workdir + "'"
702 if d.getVarFlag('ARCHIVER_MODE', 'srpm') == '1' and bb.data.inherits_class('archiver', d):
703 cmd = cmd + " --define '_sourcedir " + d.getVar('ARCHIVER_OUTDIR') + "'"
704 cmdsrpm = cmd + " --define '_srcrpmdir " + d.getVar('ARCHIVER_RPMOUTDIR') + "'"
705 cmdsrpm = cmdsrpm + " -bs " + outspecfile
706 # Build the .src.rpm
707 d.setVar('SBUILDSPEC', cmdsrpm + "\n")
708 d.setVarFlag('SBUILDSPEC', 'func', '1')
709 bb.build.exec_func('SBUILDSPEC', d)
710 cmd = cmd + " -bb " + outspecfile
711
712 # rpm 4 creates various empty directories in _topdir, let's clean them up
713 cleanupcmd = "rm -rf %s/BUILDROOT %s/SOURCES %s/SPECS %s/SRPMS" % (workdir, workdir, workdir, workdir)
714
715 # Build the rpm package!
716 d.setVar('BUILDSPEC', cmd + "\n" + cleanupcmd + "\n")
717 d.setVarFlag('BUILDSPEC', 'func', '1')
718 bb.build.exec_func('BUILDSPEC', d)
719
720 if d.getVar('RPM_SIGN_PACKAGES') == '1':
721 bb.build.exec_func("sign_rpm", d)
722}
723
724python () {
725 if d.getVar('PACKAGES') != '':
726 deps = ' rpm-native:do_populate_sysroot virtual/fakeroot-native:do_populate_sysroot'
727 d.appendVarFlag('do_package_write_rpm', 'depends', deps)
728 d.setVarFlag('do_package_write_rpm', 'fakeroot', '1')
729}
730
731SSTATETASKS += "do_package_write_rpm"
732do_package_write_rpm[sstate-inputdirs] = "${PKGWRITEDIRRPM}"
733do_package_write_rpm[sstate-outputdirs] = "${DEPLOY_DIR_RPM}"
734# Take a shared lock, we can write multiple packages at the same time...
735# but we need to stop the rootfs/solver from running while we do...
736do_package_write_rpm[sstate-lockfile-shared] += "${DEPLOY_DIR_RPM}/rpm.lock"
737
738python do_package_write_rpm_setscene () {
739 sstate_setscene(d)
740}
741addtask do_package_write_rpm_setscene
742
743python do_package_write_rpm () {
744 bb.build.exec_func("read_subpackage_metadata", d)
745 bb.build.exec_func("do_package_rpm", d)
746}
747
748do_package_write_rpm[dirs] = "${PKGWRITEDIRRPM}"
749do_package_write_rpm[cleandirs] = "${PKGWRITEDIRRPM}"
750do_package_write_rpm[depends] += "${@oe.utils.build_depends_string(d.getVar('PACKAGE_WRITE_DEPS'), 'do_populate_sysroot')}"
751addtask package_write_rpm after do_packagedata do_package do_deploy_source_date_epoch before do_build
752do_build[rdeptask] += "do_package_write_rpm"
753
754PACKAGEINDEXDEPS += "rpm-native:do_populate_sysroot"
755PACKAGEINDEXDEPS += "createrepo-c-native:do_populate_sysroot"