blob: 85d0bd7fce9536c977a4f43830d90a0ab6b5ba45 [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('-', '+')
Andrew Geissler517393d2023-01-13 08:55:19 -0600162 if ver.startswith(pv):
163 ver = ver.replace(pv, reppv)
164 ver = ver.replace(pkgv, reppv)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500165 if 'PKGR' in subd:
166 # Make sure PKGR rather than PR in ver
167 pr = '-' + subd['PR']
168 pkgr = '-' + subd['PKGR']
169 if pkgr not in ver:
170 ver = ver.replace(pr, pkgr)
171 verlist.append(ver)
172 else:
173 verlist.append(ver)
174 newdeps_dict[dep] = verlist
175 depends = bb.utils.join_deps(newdeps_dict)
176 d.setVar(varname, depends.strip())
177
178 # We need to change the style the dependency from BB to RPM
179 # This needs to happen AFTER the mapping_rename_hook
180 def print_deps(variable, tag, array, d):
181 depends = variable
182 if depends:
183 depends_dict = bb.utils.explode_dep_versions2(depends)
184 for dep in depends_dict:
185 for ver in depends_dict[dep]:
186 ver = ver.replace('(', '')
187 ver = ver.replace(')', '')
188 array.append("%s: %s %s" % (tag, dep, ver))
189 if not len(depends_dict[dep]):
190 array.append("%s: %s" % (tag, dep))
191
192 def walk_files(walkpath, target, conffiles, dirfiles):
193 # We can race against the ipk/deb backends which create CONTROL or DEBIAN directories
194 # when packaging. We just ignore these files which are created in
195 # packages-split/ and not package/
196 # We have the odd situation where the CONTROL/DEBIAN directory can be removed in the middle of
197 # of the walk, the isdir() test would then fail and the walk code would assume its a file
198 # hence we check for the names in files too.
199 for rootpath, dirs, files in os.walk(walkpath):
200 path = rootpath.replace(walkpath, "")
201 if path.endswith("DEBIAN") or path.endswith("CONTROL"):
202 continue
203 path = path.replace("%", "%%%%%%%%")
204
205 # Treat all symlinks to directories as normal files.
206 # os.walk() lists them as directories.
207 def move_to_files(dir):
208 if os.path.islink(os.path.join(rootpath, dir)):
209 files.append(dir)
210 return True
211 else:
212 return False
213 dirs[:] = [dir for dir in dirs if not move_to_files(dir)]
214
215 # Directory handling can happen in two ways, either DIRFILES is not set at all
216 # in which case we fall back to the older behaviour of packages owning all their
217 # directories
218 if dirfiles is None:
219 for dir in dirs:
220 if dir == "CONTROL" or dir == "DEBIAN":
221 continue
222 dir = dir.replace("%", "%%%%%%%%")
223 # All packages own the directories their files are in...
224 target.append('%dir "' + path + '/' + dir + '"')
225 else:
226 # packages own only empty directories or explict directory.
227 # This will prevent the overlapping of security permission.
228 if path and not files and not dirs:
229 target.append('%dir "' + path + '"')
230 elif path and path in dirfiles:
231 target.append('%dir "' + path + '"')
232
233 for file in files:
234 if file == "CONTROL" or file == "DEBIAN":
235 continue
236 file = file.replace("%", "%%%%%%%%")
237 if conffiles.count(path + '/' + file):
238 target.append('%config "' + path + '/' + file + '"')
239 else:
240 target.append('"' + path + '/' + file + '"')
241
242 # Prevent the prerm/postrm scripts from being run during an upgrade
243 def wrap_uninstall(scriptvar):
244 scr = scriptvar.strip()
245 if scr.startswith("#!"):
246 pos = scr.find("\n") + 1
247 else:
248 pos = 0
249 scr = scr[:pos] + 'if [ "$1" = "0" ] ; then\n' + scr[pos:] + '\nfi'
250 return scr
251
252 def get_perfile(varname, pkg, d):
253 deps = []
254 dependsflist_key = 'FILE' + varname + 'FLIST' + ":" + pkg
255 dependsflist = (d.getVar(dependsflist_key) or "")
256 for dfile in dependsflist.split():
257 key = "FILE" + varname + ":" + dfile + ":" + pkg
258 depends = d.getVar(key)
259 if depends:
260 deps.append(depends)
261 return " ".join(deps)
262
263 def append_description(spec_preamble, text):
264 """
265 Add the description to the spec file.
266 """
267 import textwrap
268 dedent_text = textwrap.dedent(text).strip()
269 # Bitbake saves "\n" as "\\n"
270 if '\\n' in dedent_text:
271 for t in dedent_text.split('\\n'):
272 spec_preamble.append(t.strip())
273 else:
274 spec_preamble.append('%s' % textwrap.fill(dedent_text, width=75))
275
276 packages = d.getVar('PACKAGES')
277 if not packages or packages == '':
278 bb.debug(1, "No packages; nothing to do")
279 return
280
281 pkgdest = d.getVar('PKGDEST')
282 if not pkgdest:
283 bb.fatal("No PKGDEST")
284
285 outspecfile = d.getVar('OUTSPECFILE')
286 if not outspecfile:
287 bb.fatal("No OUTSPECFILE")
288
289 # Construct the SPEC file...
290 srcname = d.getVar('PN')
291 localdata = bb.data.createCopy(d)
292 localdata.setVar('OVERRIDES', d.getVar("OVERRIDES", False) + ":" + srcname)
293 srcsummary = (localdata.getVar('SUMMARY') or localdata.getVar('DESCRIPTION') or ".")
294 srcversion = localdata.getVar('PKGV').replace('-', '+')
295 srcrelease = localdata.getVar('PKGR')
296 srcepoch = (localdata.getVar('PKGE') or "")
297 srclicense = localdata.getVar('LICENSE')
298 srcsection = localdata.getVar('SECTION')
299 srcmaintainer = localdata.getVar('MAINTAINER')
300 srchomepage = localdata.getVar('HOMEPAGE')
301 srcdescription = localdata.getVar('DESCRIPTION') or "."
Andrew Geissler517393d2023-01-13 08:55:19 -0600302 srccustomtagschunk = oe.packagedata.get_package_additional_metadata("rpm", localdata)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500303
304 srcdepends = d.getVar('DEPENDS')
305 srcrdepends = ""
306 srcrrecommends = ""
307 srcrsuggests = ""
308 srcrprovides = ""
309 srcrreplaces = ""
310 srcrconflicts = ""
311 srcrobsoletes = ""
312
313 srcrpreinst = []
314 srcrpostinst = []
315 srcrprerm = []
316 srcrpostrm = []
317
318 spec_preamble_top = []
319 spec_preamble_bottom = []
320
321 spec_scriptlets_top = []
322 spec_scriptlets_bottom = []
323
324 spec_files_top = []
325 spec_files_bottom = []
326
327 perfiledeps = (d.getVar("MERGEPERFILEDEPS") or "0") == "0"
328 extra_pkgdata = (d.getVar("RPM_EXTRA_PKGDATA") or "0") == "1"
329
330 for pkg in packages.split():
331 localdata = bb.data.createCopy(d)
332
333 root = "%s/%s" % (pkgdest, pkg)
334
335 localdata.setVar('ROOT', '')
336 localdata.setVar('ROOT_%s' % pkg, root)
337 pkgname = localdata.getVar('PKG:%s' % pkg)
338 if not pkgname:
339 pkgname = pkg
340 localdata.setVar('PKG', pkgname)
341
342 localdata.setVar('OVERRIDES', d.getVar("OVERRIDES", False) + ":" + pkg)
343
Andrew Geissler517393d2023-01-13 08:55:19 -0600344 conffiles = oe.package.get_conffiles(pkg, d)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500345 dirfiles = localdata.getVar('DIRFILES')
346 if dirfiles is not None:
347 dirfiles = dirfiles.split()
348
349 splitname = pkgname
350
351 splitsummary = (localdata.getVar('SUMMARY') or localdata.getVar('DESCRIPTION') or ".")
352 splitversion = (localdata.getVar('PKGV') or "").replace('-', '+')
353 splitrelease = (localdata.getVar('PKGR') or "")
354 splitepoch = (localdata.getVar('PKGE') or "")
355 splitlicense = (localdata.getVar('LICENSE') or "")
356 splitsection = (localdata.getVar('SECTION') or "")
357 splitdescription = (localdata.getVar('DESCRIPTION') or ".")
Andrew Geissler517393d2023-01-13 08:55:19 -0600358 splitcustomtagschunk = oe.packagedata.get_package_additional_metadata("rpm", localdata)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500359
360 translate_vers('RDEPENDS', localdata)
361 translate_vers('RRECOMMENDS', localdata)
362 translate_vers('RSUGGESTS', localdata)
363 translate_vers('RPROVIDES', localdata)
364 translate_vers('RREPLACES', localdata)
365 translate_vers('RCONFLICTS', localdata)
366
367 # Map the dependencies into their final form
Andrew Geissler517393d2023-01-13 08:55:19 -0600368 oe.packagedata.mapping_rename_hook(localdata)
Patrick Williams92b42cb2022-09-03 06:53:57 -0500369
370 splitrdepends = localdata.getVar('RDEPENDS') or ""
371 splitrrecommends = localdata.getVar('RRECOMMENDS') or ""
372 splitrsuggests = localdata.getVar('RSUGGESTS') or ""
373 splitrprovides = localdata.getVar('RPROVIDES') or ""
374 splitrreplaces = localdata.getVar('RREPLACES') or ""
375 splitrconflicts = localdata.getVar('RCONFLICTS') or ""
376 splitrobsoletes = ""
377
378 splitrpreinst = localdata.getVar('pkg_preinst')
379 splitrpostinst = localdata.getVar('pkg_postinst')
380 splitrprerm = localdata.getVar('pkg_prerm')
381 splitrpostrm = localdata.getVar('pkg_postrm')
382
383
384 if not perfiledeps:
385 # Add in summary of per file dependencies
386 splitrdepends = splitrdepends + " " + get_perfile('RDEPENDS', pkg, d)
387 splitrprovides = splitrprovides + " " + get_perfile('RPROVIDES', pkg, d)
388
389 splitrdepends = filter_nativesdk_deps(srcname, splitrdepends)
390
391 # Gather special src/first package data
392 if srcname == splitname:
393 archiving = d.getVarFlag('ARCHIVER_MODE', 'srpm') == '1' and \
394 bb.data.inherits_class('archiver', d)
395 if archiving and srclicense != splitlicense:
396 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.")
397
398 srclicense = splitlicense
399 srcrdepends = splitrdepends
400 srcrrecommends = splitrrecommends
401 srcrsuggests = splitrsuggests
402 srcrprovides = splitrprovides
403 srcrreplaces = splitrreplaces
404 srcrconflicts = splitrconflicts
405
406 srcrpreinst = splitrpreinst
407 srcrpostinst = splitrpostinst
408 srcrprerm = splitrprerm
409 srcrpostrm = splitrpostrm
410
411 file_list = []
412 walk_files(root, file_list, conffiles, dirfiles)
413 if not file_list and localdata.getVar('ALLOW_EMPTY', False) != "1":
414 bb.note("Not creating empty RPM package for %s" % splitname)
415 else:
416 spec_files_top.append('%files')
417 if extra_pkgdata:
418 package_rpm_extra_pkgdata(splitname, spec_files_top, localdata)
419 spec_files_top.append('%defattr(-,-,-,-)')
420 if file_list:
421 bb.note("Creating RPM package for %s" % splitname)
422 spec_files_top.extend(file_list)
423 else:
424 bb.note("Creating empty RPM package for %s" % splitname)
425 spec_files_top.append('')
426 continue
427
428 # Process subpackage data
429 spec_preamble_bottom.append('%%package -n %s' % splitname)
430 spec_preamble_bottom.append('Summary: %s' % splitsummary)
431 if srcversion != splitversion:
432 spec_preamble_bottom.append('Version: %s' % splitversion)
433 if srcrelease != splitrelease:
434 spec_preamble_bottom.append('Release: %s' % splitrelease)
435 if srcepoch != splitepoch:
436 spec_preamble_bottom.append('Epoch: %s' % splitepoch)
437 spec_preamble_bottom.append('License: %s' % splitlicense)
438 spec_preamble_bottom.append('Group: %s' % splitsection)
439
440 if srccustomtagschunk != splitcustomtagschunk:
441 spec_preamble_bottom.append(splitcustomtagschunk)
442
443 # Replaces == Obsoletes && Provides
444 robsoletes = bb.utils.explode_dep_versions2(splitrobsoletes)
445 rprovides = bb.utils.explode_dep_versions2(splitrprovides)
446 rreplaces = bb.utils.explode_dep_versions2(splitrreplaces)
447 for dep in rreplaces:
448 if not dep in robsoletes:
449 robsoletes[dep] = rreplaces[dep]
450 if not dep in rprovides:
451 rprovides[dep] = rreplaces[dep]
452 splitrobsoletes = bb.utils.join_deps(robsoletes, commasep=False)
453 splitrprovides = bb.utils.join_deps(rprovides, commasep=False)
454
455 print_deps(splitrdepends, "Requires", spec_preamble_bottom, d)
456 if splitrpreinst:
457 print_deps(splitrdepends, "Requires(pre)", spec_preamble_bottom, d)
458 if splitrpostinst:
459 print_deps(splitrdepends, "Requires(post)", spec_preamble_bottom, d)
460 if splitrprerm:
461 print_deps(splitrdepends, "Requires(preun)", spec_preamble_bottom, d)
462 if splitrpostrm:
463 print_deps(splitrdepends, "Requires(postun)", spec_preamble_bottom, d)
464
465 print_deps(splitrrecommends, "Recommends", spec_preamble_bottom, d)
466 print_deps(splitrsuggests, "Suggests", spec_preamble_bottom, d)
467 print_deps(splitrprovides, "Provides", spec_preamble_bottom, d)
468 print_deps(splitrobsoletes, "Obsoletes", spec_preamble_bottom, d)
469 print_deps(splitrconflicts, "Conflicts", spec_preamble_bottom, d)
470
471 spec_preamble_bottom.append('')
472
473 spec_preamble_bottom.append('%%description -n %s' % splitname)
474 append_description(spec_preamble_bottom, splitdescription)
475
476 spec_preamble_bottom.append('')
477
478 # Now process scriptlets
479 if splitrpreinst:
480 spec_scriptlets_bottom.append('%%pre -n %s' % splitname)
481 spec_scriptlets_bottom.append('# %s - preinst' % splitname)
482 spec_scriptlets_bottom.append(splitrpreinst)
483 spec_scriptlets_bottom.append('')
484 if splitrpostinst:
485 spec_scriptlets_bottom.append('%%post -n %s' % splitname)
486 spec_scriptlets_bottom.append('# %s - postinst' % splitname)
487 spec_scriptlets_bottom.append(splitrpostinst)
488 spec_scriptlets_bottom.append('')
489 if splitrprerm:
490 spec_scriptlets_bottom.append('%%preun -n %s' % splitname)
491 spec_scriptlets_bottom.append('# %s - prerm' % splitname)
492 scriptvar = wrap_uninstall(splitrprerm)
493 spec_scriptlets_bottom.append(scriptvar)
494 spec_scriptlets_bottom.append('')
495 if splitrpostrm:
496 spec_scriptlets_bottom.append('%%postun -n %s' % splitname)
497 spec_scriptlets_bottom.append('# %s - postrm' % splitname)
498 scriptvar = wrap_uninstall(splitrpostrm)
499 spec_scriptlets_bottom.append(scriptvar)
500 spec_scriptlets_bottom.append('')
501
502 # Now process files
503 file_list = []
504 walk_files(root, file_list, conffiles, dirfiles)
505 if not file_list and localdata.getVar('ALLOW_EMPTY', False) != "1":
506 bb.note("Not creating empty RPM package for %s" % splitname)
507 else:
508 spec_files_bottom.append('%%files -n %s' % splitname)
509 if extra_pkgdata:
510 package_rpm_extra_pkgdata(splitname, spec_files_bottom, localdata)
511 spec_files_bottom.append('%defattr(-,-,-,-)')
512 if file_list:
513 bb.note("Creating RPM package for %s" % splitname)
514 spec_files_bottom.extend(file_list)
515 else:
516 bb.note("Creating empty RPM package for %s" % splitname)
517 spec_files_bottom.append('')
518
519 del localdata
520
521 add_prep(d,spec_files_bottom)
522 spec_preamble_top.append('Summary: %s' % srcsummary)
523 spec_preamble_top.append('Name: %s' % srcname)
524 spec_preamble_top.append('Version: %s' % srcversion)
525 spec_preamble_top.append('Release: %s' % srcrelease)
526 if srcepoch and srcepoch.strip() != "":
527 spec_preamble_top.append('Epoch: %s' % srcepoch)
528 spec_preamble_top.append('License: %s' % srclicense)
529 spec_preamble_top.append('Group: %s' % srcsection)
530 spec_preamble_top.append('Packager: %s' % srcmaintainer)
531 if srchomepage:
532 spec_preamble_top.append('URL: %s' % srchomepage)
533 if srccustomtagschunk:
534 spec_preamble_top.append(srccustomtagschunk)
535 tail_source(d)
536
537 # Replaces == Obsoletes && Provides
538 robsoletes = bb.utils.explode_dep_versions2(srcrobsoletes)
539 rprovides = bb.utils.explode_dep_versions2(srcrprovides)
540 rreplaces = bb.utils.explode_dep_versions2(srcrreplaces)
541 for dep in rreplaces:
542 if not dep in robsoletes:
543 robsoletes[dep] = rreplaces[dep]
544 if not dep in rprovides:
545 rprovides[dep] = rreplaces[dep]
546 srcrobsoletes = bb.utils.join_deps(robsoletes, commasep=False)
547 srcrprovides = bb.utils.join_deps(rprovides, commasep=False)
548
549 print_deps(srcdepends, "BuildRequires", spec_preamble_top, d)
550 print_deps(srcrdepends, "Requires", spec_preamble_top, d)
551 if srcrpreinst:
552 print_deps(srcrdepends, "Requires(pre)", spec_preamble_top, d)
553 if srcrpostinst:
554 print_deps(srcrdepends, "Requires(post)", spec_preamble_top, d)
555 if srcrprerm:
556 print_deps(srcrdepends, "Requires(preun)", spec_preamble_top, d)
557 if srcrpostrm:
558 print_deps(srcrdepends, "Requires(postun)", spec_preamble_top, d)
559
560 print_deps(srcrrecommends, "Recommends", spec_preamble_top, d)
561 print_deps(srcrsuggests, "Suggests", spec_preamble_top, d)
562 print_deps(srcrprovides, "Provides", spec_preamble_top, d)
563 print_deps(srcrobsoletes, "Obsoletes", spec_preamble_top, d)
564 print_deps(srcrconflicts, "Conflicts", spec_preamble_top, d)
565
566 spec_preamble_top.append('')
567
568 spec_preamble_top.append('%description')
569 append_description(spec_preamble_top, srcdescription)
570
571 spec_preamble_top.append('')
572
573 if srcrpreinst:
574 spec_scriptlets_top.append('%pre')
575 spec_scriptlets_top.append('# %s - preinst' % srcname)
576 spec_scriptlets_top.append(srcrpreinst)
577 spec_scriptlets_top.append('')
578 if srcrpostinst:
579 spec_scriptlets_top.append('%post')
580 spec_scriptlets_top.append('# %s - postinst' % srcname)
581 spec_scriptlets_top.append(srcrpostinst)
582 spec_scriptlets_top.append('')
583 if srcrprerm:
584 spec_scriptlets_top.append('%preun')
585 spec_scriptlets_top.append('# %s - prerm' % srcname)
586 scriptvar = wrap_uninstall(srcrprerm)
587 spec_scriptlets_top.append(scriptvar)
588 spec_scriptlets_top.append('')
589 if srcrpostrm:
590 spec_scriptlets_top.append('%postun')
591 spec_scriptlets_top.append('# %s - postrm' % srcname)
592 scriptvar = wrap_uninstall(srcrpostrm)
593 spec_scriptlets_top.append(scriptvar)
594 spec_scriptlets_top.append('')
595
596 # Write the SPEC file
597 specfile = open(outspecfile, 'w')
598
599 # RPMSPEC_PREAMBLE is a way to add arbitrary text to the top
600 # of the generated spec file
601 external_preamble = d.getVar("RPMSPEC_PREAMBLE")
602 if external_preamble:
603 specfile.write(external_preamble + "\n")
604
605 for line in spec_preamble_top:
606 specfile.write(line + "\n")
607
608 for line in spec_preamble_bottom:
609 specfile.write(line + "\n")
610
611 for line in spec_scriptlets_top:
612 specfile.write(line + "\n")
613
614 for line in spec_scriptlets_bottom:
615 specfile.write(line + "\n")
616
617 for line in spec_files_top:
618 specfile.write(line + "\n")
619
620 for line in spec_files_bottom:
621 specfile.write(line + "\n")
622
623 specfile.close()
624}
625# Otherwise allarch packages may change depending on override configuration
626write_specfile[vardepsexclude] = "OVERRIDES"
627
628# Have to list any variables referenced as X_<pkg> that aren't in pkgdata here
629RPMEXTRAVARS = "PACKAGE_ADD_METADATA_RPM"
630write_specfile[vardeps] += "${@gen_packagevar(d, 'RPMEXTRAVARS')}"
631
632python do_package_rpm () {
633 workdir = d.getVar('WORKDIR')
634 tmpdir = d.getVar('TMPDIR')
635 pkgd = d.getVar('PKGD')
636 pkgdest = d.getVar('PKGDEST')
637 if not workdir or not pkgd or not tmpdir:
638 bb.error("Variables incorrectly set, unable to package")
639 return
640
641 packages = d.getVar('PACKAGES')
642 if not packages or packages == '':
643 bb.debug(1, "No packages; nothing to do")
644 return
645
646 # Construct the spec file...
647 # If the spec file already exist, and has not been stored into
648 # pseudo's files.db, it maybe cause rpmbuild src.rpm fail,
649 # so remove it before doing rpmbuild src.rpm.
650 srcname = d.getVar('PN')
651 outspecfile = workdir + "/" + srcname + ".spec"
652 if os.path.isfile(outspecfile):
653 os.remove(outspecfile)
654 d.setVar('OUTSPECFILE', outspecfile)
655 bb.build.exec_func('write_specfile', d)
656
657 perfiledeps = (d.getVar("MERGEPERFILEDEPS") or "0") == "0"
658 if perfiledeps:
659 outdepends, outprovides = write_rpm_perfiledata(srcname, d)
660
661 # Setup the rpmbuild arguments...
662 rpmbuild = d.getVar('RPMBUILD')
663 targetsys = d.getVar('TARGET_SYS')
664 targetvendor = d.getVar('HOST_VENDOR')
665
666 # Too many places in dnf stack assume that arch-independent packages are "noarch".
667 # Let's not fight against this.
668 package_arch = (d.getVar('PACKAGE_ARCH') or "").replace("-", "_")
669 if package_arch == "all":
670 package_arch = "noarch"
671
672 sdkpkgsuffix = (d.getVar('SDKPKGSUFFIX') or "nativesdk").replace("-", "_")
673 d.setVar('PACKAGE_ARCH_EXTEND', package_arch)
674 pkgwritedir = d.expand('${PKGWRITEDIRRPM}/${PACKAGE_ARCH_EXTEND}')
675 d.setVar('RPM_PKGWRITEDIR', pkgwritedir)
676 bb.debug(1, 'PKGWRITEDIR: %s' % d.getVar('RPM_PKGWRITEDIR'))
677 pkgarch = d.expand('${PACKAGE_ARCH_EXTEND}${HOST_VENDOR}-linux')
678 bb.utils.mkdirhier(pkgwritedir)
679 os.chmod(pkgwritedir, 0o755)
680
681 cmd = rpmbuild
682 cmd = cmd + " --noclean --nodeps --short-circuit --target " + pkgarch + " --buildroot " + pkgd
683 cmd = cmd + " --define '_topdir " + workdir + "' --define '_rpmdir " + pkgwritedir + "'"
684 cmd = cmd + " --define '_builddir " + d.getVar('B') + "'"
685 cmd = cmd + " --define '_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm'"
686 cmd = cmd + " --define '_use_internal_dependency_generator 0'"
687 cmd = cmd + " --define '_binaries_in_noarch_packages_terminate_build 0'"
688 cmd = cmd + " --define '_build_id_links none'"
689 cmd = cmd + " --define '_binary_payload w19T%d.zstdio'" % int(d.getVar("ZSTD_THREADS"))
690 cmd = cmd + " --define '_source_payload w19T%d.zstdio'" % int(d.getVar("ZSTD_THREADS"))
691 cmd = cmd + " --define 'clamp_mtime_to_source_date_epoch 1'"
692 cmd = cmd + " --define 'use_source_date_epoch_as_buildtime 1'"
693 cmd = cmd + " --define '_buildhost reproducible'"
694 cmd = cmd + " --define '__font_provides %{nil}'"
695 if perfiledeps:
696 cmd = cmd + " --define '__find_requires " + outdepends + "'"
697 cmd = cmd + " --define '__find_provides " + outprovides + "'"
698 else:
699 cmd = cmd + " --define '__find_requires %{nil}'"
700 cmd = cmd + " --define '__find_provides %{nil}'"
701 cmd = cmd + " --define '_unpackaged_files_terminate_build 0'"
702 cmd = cmd + " --define 'debug_package %{nil}'"
703 cmd = cmd + " --define '_tmppath " + workdir + "'"
704 if d.getVarFlag('ARCHIVER_MODE', 'srpm') == '1' and bb.data.inherits_class('archiver', d):
705 cmd = cmd + " --define '_sourcedir " + d.getVar('ARCHIVER_OUTDIR') + "'"
706 cmdsrpm = cmd + " --define '_srcrpmdir " + d.getVar('ARCHIVER_RPMOUTDIR') + "'"
707 cmdsrpm = cmdsrpm + " -bs " + outspecfile
708 # Build the .src.rpm
709 d.setVar('SBUILDSPEC', cmdsrpm + "\n")
710 d.setVarFlag('SBUILDSPEC', 'func', '1')
711 bb.build.exec_func('SBUILDSPEC', d)
712 cmd = cmd + " -bb " + outspecfile
713
714 # rpm 4 creates various empty directories in _topdir, let's clean them up
715 cleanupcmd = "rm -rf %s/BUILDROOT %s/SOURCES %s/SPECS %s/SRPMS" % (workdir, workdir, workdir, workdir)
716
717 # Build the rpm package!
718 d.setVar('BUILDSPEC', cmd + "\n" + cleanupcmd + "\n")
719 d.setVarFlag('BUILDSPEC', 'func', '1')
720 bb.build.exec_func('BUILDSPEC', d)
721
722 if d.getVar('RPM_SIGN_PACKAGES') == '1':
723 bb.build.exec_func("sign_rpm", d)
724}
725
726python () {
727 if d.getVar('PACKAGES') != '':
728 deps = ' rpm-native:do_populate_sysroot virtual/fakeroot-native:do_populate_sysroot'
729 d.appendVarFlag('do_package_write_rpm', 'depends', deps)
730 d.setVarFlag('do_package_write_rpm', 'fakeroot', '1')
731}
732
733SSTATETASKS += "do_package_write_rpm"
734do_package_write_rpm[sstate-inputdirs] = "${PKGWRITEDIRRPM}"
735do_package_write_rpm[sstate-outputdirs] = "${DEPLOY_DIR_RPM}"
736# Take a shared lock, we can write multiple packages at the same time...
737# but we need to stop the rootfs/solver from running while we do...
738do_package_write_rpm[sstate-lockfile-shared] += "${DEPLOY_DIR_RPM}/rpm.lock"
739
740python do_package_write_rpm_setscene () {
741 sstate_setscene(d)
742}
743addtask do_package_write_rpm_setscene
744
745python do_package_write_rpm () {
746 bb.build.exec_func("read_subpackage_metadata", d)
747 bb.build.exec_func("do_package_rpm", d)
748}
749
750do_package_write_rpm[dirs] = "${PKGWRITEDIRRPM}"
751do_package_write_rpm[cleandirs] = "${PKGWRITEDIRRPM}"
752do_package_write_rpm[depends] += "${@oe.utils.build_depends_string(d.getVar('PACKAGE_WRITE_DEPS'), 'do_populate_sysroot')}"
753addtask package_write_rpm after do_packagedata do_package do_deploy_source_date_epoch before do_build
754do_build[rdeptask] += "do_package_write_rpm"
755
756PACKAGEINDEXDEPS += "rpm-native:do_populate_sysroot"
757PACKAGEINDEXDEPS += "createrepo-c-native:do_populate_sysroot"