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