| Message ID | 20240610214456.2757397-3-JPEWhacker@gmail.com |
|---|---|
| State | New |
| Headers | show |
| Series | Add SPDX 3.0 support | expand |
On Mon, 2024-06-10 at 15:41 -0600, Joshua Watt via lists.openembedded.org wrote: > Moves SPDX code that can be shared between different SPDX versions > into > a common class > > Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> > --- > meta/classes/create-spdx-2.2.bbclass | 259 ++----------------------- > -- > meta/classes/spdx-common.bbclass | 256 > ++++++++++++++++++++++++++ > 2 files changed, 266 insertions(+), 249 deletions(-) > create mode 100644 meta/classes/spdx-common.bbclass > > diff --git a/meta/classes/create-spdx-2.2.bbclass > b/meta/classes/create-spdx-2.2.bbclass > index 7c8a0b8b0f7..94a172fbc94 100644 > --- a/meta/classes/create-spdx-2.2.bbclass > +++ b/meta/classes/create-spdx-2.2.bbclass > @@ -4,65 +4,13 @@ > # SPDX-License-Identifier: GPL-2.0-only > # > > -DEPLOY_DIR_SPDX ??= "${DEPLOY_DIR}/spdx" > - > -# The product name that the CVE database uses. Defaults to BPN, but > may need to > -# be overriden per recipe (for example tiff.bb sets > CVE_PRODUCT=libtiff). > -CVE_PRODUCT ??= "${BPN}" > -CVE_VERSION ??= "${PV}" > - > -SPDXDIR ??= "${WORKDIR}/spdx" > -SPDXDEPLOY = "${SPDXDIR}/deploy" > -SPDXWORK = "${SPDXDIR}/work" > -SPDXIMAGEWORK = "${SPDXDIR}/image-work" > -SPDXSDKWORK = "${SPDXDIR}/sdk-work" > -SPDXDEPS = "${SPDXDIR}/deps.json" > - > -SPDX_TOOL_NAME ??= "oe-spdx-creator" > -SPDX_TOOL_VERSION ??= "1.0" > - > -SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" > - > -SPDX_INCLUDE_SOURCES ??= "0" > -SPDX_ARCHIVE_SOURCES ??= "0" > -SPDX_ARCHIVE_PACKAGED ??= "0" > - > -SPDX_UUID_NAMESPACE ??= "sbom.openembedded.org" > -SPDX_NAMESPACE_PREFIX ??= "http://spdx.org/spdxdocs" > -SPDX_PRETTY ??= "0" > - > -SPDX_LICENSES ??= "${COREBASE}/meta/files/spdx-licenses.json" > - > -SPDX_CUSTOM_ANNOTATION_VARS ??= "" > - > -SPDX_ORG ??= "OpenEmbedded ()" > -SPDX_SUPPLIER ??= "Organization: ${SPDX_ORG}" > -SPDX_SUPPLIER[doc] = "The SPDX PackageSupplier field for SPDX > packages created from \ > - this recipe. For SPDX documents create using this class during > the build, this \ > - is the contact information for the person or organization who is > doing the \ > - build." > - > -def extract_licenses(filename): > - import re > - > - lic_regex = re.compile(rb'^\W*SPDX-License-Identifier:\s*([ > \w\d.()+-]+?)(?:\s+\W*)?$', re.MULTILINE) > - > - try: > - with open(filename, 'rb') as f: > - size = min(15000, os.stat(filename).st_size) > - txt = f.read(size) > - licenses = re.findall(lic_regex, txt) > - if licenses: > - ascii_licenses = [lic.decode('ascii') for lic in > licenses] > - return ascii_licenses > - except Exception as e: > - bb.warn(f"Exception reading {filename}: {e}") > - return None > - > -def get_doc_namespace(d, doc): > +inherit spdx-common > + > +def get_namespace(d, name): > import uuid > namespace_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, > d.getVar("SPDX_UUID_NAMESPACE")) > - return "%s/%s-%s" % (d.getVar("SPDX_NAMESPACE_PREFIX"), > doc.name, str(uuid.uuid5(namespace_uuid, doc.name))) > + return "%s/%s-%s" % (d.getVar("SPDX_NAMESPACE_PREFIX"), name, > str(uuid.uuid5(namespace_uuid, name))) > + > > def create_annotation(d, comment): > from datetime import datetime, timezone > @@ -80,26 +28,6 @@ def recipe_spdx_is_native(d, recipe): > a.annotator == "Tool: %s - %s" % (d.getVar("SPDX_TOOL_NAME"), > d.getVar("SPDX_TOOL_VERSION")) and > a.comment == "isNative" for a in recipe.annotations) > > -def is_work_shared_spdx(d): > - return bb.data.inherits_class('kernel', d) or ('work-shared' in > d.getVar('WORKDIR')) > - > -def get_json_indent(d): > - if d.getVar("SPDX_PRETTY") == "1": > - return 2 > - return None > - > -python() { > - import json > - if d.getVar("SPDX_LICENSE_DATA"): > - return > - > - with open(d.getVar("SPDX_LICENSES"), "r") as f: > - data = json.load(f) > - # Transform the license array to a dictionary > - data["licenses"] = {l["licenseId"]: l for l in > data["licenses"]} > - d.setVar("SPDX_LICENSE_DATA", data) > -} > - > def convert_license_to_spdx(lic, document, d, existing={}): > from pathlib import Path > import oe.spdx > @@ -172,34 +100,6 @@ def convert_license_to_spdx(lic, document, d, > existing={}): > > return ' '.join(convert(l) for l in lic_split) > > -def process_sources(d): > - pn = d.getVar('PN') > - assume_provided = (d.getVar("ASSUME_PROVIDED") or "").split() > - if pn in assume_provided: > - for p in d.getVar("PROVIDES").split(): > - if p != pn: > - pn = p > - break > - > - # glibc-locale: do_fetch, do_unpack and do_patch tasks have been > deleted, > - # so avoid archiving source here. > - if pn.startswith('glibc-locale'): > - return False > - if d.getVar('PN') == "libtool-cross": > - return False > - if d.getVar('PN') == "libgcc-initial": > - return False > - if d.getVar('PN') == "shadow-sysroot": > - return False > - > - # We just archive gcc-source for all the gcc related recipes > - if d.getVar('BPN') in ['gcc', 'libgcc']: > - bb.debug(1, 'spdx: There is bug in scan of %s is, do > nothing' % pn) > - return False > - > - return True > - > - > def add_package_files(d, doc, spdx_pkg, topdir, get_spdxid, > get_types, *, archive=None, ignore_dirs=[], > ignore_top_level_dirs=[]): > from pathlib import Path > import oe.spdx > @@ -348,14 +248,12 @@ def collect_dep_recipes(d, doc, spdx_recipe): > import oe.spdx > > deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) > - spdx_deps_file = Path(d.getVar("SPDXDEPS")) > package_archs = d.getVar("SSTATE_ARCHS").split() > package_archs.reverse() > > dep_recipes = [] > > - with spdx_deps_file.open("r") as f: > - deps = json.load(f) > + deps = get_spdx_deps(d) > > for dep_pn, dep_hashfn, in_taskhash in deps: > # If this dependency is not calculated in the taskhash skip > it. > @@ -468,51 +366,6 @@ def add_download_packages(d, doc, recipe): > # but this should be sufficient for now > doc.add_relationship(package, "BUILD_DEPENDENCY_OF", > recipe) > > -def collect_direct_deps(d, dep_task): > - current_task = "do_" + d.getVar("BB_CURRENTTASK") > - pn = d.getVar("PN") > - > - taskdepdata = d.getVar("BB_TASKDEPDATA", False) > - > - for this_dep in taskdepdata.values(): > - if this_dep[0] == pn and this_dep[1] == current_task: > - break > - else: > - bb.fatal(f"Unable to find this {pn}:{current_task} in > taskdepdata") > - > - deps = set() > - for dep_name in this_dep[3]: > - dep_data = taskdepdata[dep_name] > - if dep_data[1] == dep_task and dep_data[0] != pn: > - deps.add((dep_data[0], dep_data[7], dep_name in > this_dep[8])) > - > - return sorted(deps) > - > -collect_direct_deps[vardepsexclude] += "BB_TASKDEPDATA" > -collect_direct_deps[vardeps] += "DEPENDS" > - > -python do_collect_spdx_deps() { > - # This task calculates the build time dependencies of the > recipe, and is > - # required because while a task can deptask on itself, those > dependencies > - # do not show up in BB_TASKDEPDATA. To work around that, this > task does the > - # deptask on do_create_spdx and writes out the dependencies it > finds, then > - # do_create_spdx reads in the found dependencies when writing > the actual > - # SPDX document > - import json > - from pathlib import Path > - > - spdx_deps_file = Path(d.getVar("SPDXDEPS")) > - > - deps = collect_direct_deps(d, "do_create_spdx") > - > - with spdx_deps_file.open("w") as f: > - json.dump(deps, f) > -} > -# NOTE: depending on do_unpack is a hack that is necessary to get > it's dependencies for archive the source > -addtask do_collect_spdx_deps after do_unpack > -do_collect_spdx_deps[depends] += "${PATCHDEPENDENCY}" > -do_collect_spdx_deps[deptask] = "do_create_spdx" > -do_collect_spdx_deps[dirs] = "${SPDXDIR}" > > python do_create_spdx() { > from datetime import datetime, timezone > @@ -551,7 +404,7 @@ python do_create_spdx() { > doc = oe.spdx.SPDXDocument() > > doc.name = "recipe-" + d.getVar("PN") > - doc.documentNamespace = get_doc_namespace(d, doc) > + doc.documentNamespace = get_namespace(d, doc.name) > doc.creationInfo.created = creation_time > doc.creationInfo.comment = "This document was created by > analyzing recipe files during the build." > doc.creationInfo.licenseListVersion = > d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] > @@ -655,7 +508,7 @@ python do_create_spdx() { > package_doc = oe.spdx.SPDXDocument() > pkg_name = d.getVar("PKG:%s" % package) or package > package_doc.name = pkg_name > - package_doc.documentNamespace = get_doc_namespace(d, > package_doc) > + package_doc.documentNamespace = get_namespace(d, > package_doc.name) > package_doc.creationInfo.created = creation_time > package_doc.creationInfo.comment = "This document was > created by analyzing packages created during the build." > package_doc.creationInfo.licenseListVersion = > d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] > @@ -716,44 +569,6 @@ do_create_spdx[dirs] = "${SPDXWORK}" > do_create_spdx[cleandirs] = "${SPDXDEPLOY} ${SPDXWORK}" > do_create_spdx[depends] += "${PATCHDEPENDENCY}" > > -def collect_package_providers(d): > - from pathlib import Path > - import oe.sbom > - import oe.spdx > - import json > - > - deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) > - > - providers = {} > - > - deps = collect_direct_deps(d, "do_create_spdx") > - deps.append((d.getVar("PN"), d.getVar("BB_HASHFILENAME"), True)) > - > - for dep_pn, dep_hashfn, _ in deps: > - localdata = d > - recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) > - if not recipe_data: > - localdata = bb.data.createCopy(d) > - localdata.setVar("PKGDATA_DIR", "${PKGDATA_DIR_SDK}") > - recipe_data = oe.packagedata.read_pkgdata(dep_pn, > localdata) > - > - for pkg in recipe_data.get("PACKAGES", "").split(): > - > - pkg_data = oe.packagedata.read_subpkgdata_dict(pkg, > localdata) > - rprovides = set(n for n, _ in > bb.utils.explode_dep_versions2(pkg_data.get("RPROVIDES", > "")).items()) > - rprovides.add(pkg) > - > - if "PKG" in pkg_data: > - pkg = pkg_data["PKG"] > - rprovides.add(pkg) > - > - for r in rprovides: > - providers[r] = (pkg, dep_hashfn) > - > - return providers > - > -collect_package_providers[vardepsexclude] += "BB_TASKDEPDATA" > - > python do_create_runtime_spdx() { > from datetime import datetime, timezone > import oe.sbom > @@ -800,7 +615,7 @@ python do_create_runtime_spdx() { > > runtime_doc = oe.spdx.SPDXDocument() > runtime_doc.name = "runtime-" + pkg_name > - runtime_doc.documentNamespace = > get_doc_namespace(localdata, runtime_doc) > + runtime_doc.documentNamespace = get_namespace(localdata, > runtime_doc.name) > runtime_doc.creationInfo.created = creation_time > runtime_doc.creationInfo.comment = "This document was > created by analyzing package runtime dependencies." > runtime_doc.creationInfo.licenseListVersion = > d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] > @@ -891,60 +706,6 @@ do_create_runtime_spdx[dirs] = > "${SPDXRUNTIMEDEPLOY}" > do_create_runtime_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" > do_create_runtime_spdx[rdeptask] = "do_create_spdx" > > -def spdx_get_src(d): > - """ > - save patched source of the recipe in SPDX_WORKDIR. > - """ > - import shutil > - spdx_workdir = d.getVar('SPDXWORK') > - spdx_sysroot_native = d.getVar('STAGING_DIR_NATIVE') > - pn = d.getVar('PN') > - > - workdir = d.getVar("WORKDIR") > - > - try: > - # The kernel class functions require it to be on work- > shared, so we dont change WORKDIR > - if not is_work_shared_spdx(d): > - # Change the WORKDIR to make do_unpack do_patch run in > another dir. > - d.setVar('WORKDIR', spdx_workdir) > - # Restore the original path to recipe's native sysroot > (it's relative to WORKDIR). > - d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) > - > - # The changed 'WORKDIR' also caused 'B' changed, create > dir 'B' for the > - # possibly requiring of the following tasks (such as > some recipes's > - # do_patch required 'B' existed). > - bb.utils.mkdirhier(d.getVar('B')) > - > - bb.build.exec_func('do_unpack', d) > - # Copy source of kernel to spdx_workdir > - if is_work_shared_spdx(d): > - share_src = d.getVar('WORKDIR') > - d.setVar('WORKDIR', spdx_workdir) > - d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) > - src_dir = spdx_workdir + "/" + d.getVar('PN')+ "-" + > d.getVar('PV') + "-" + d.getVar('PR') > - bb.utils.mkdirhier(src_dir) > - if bb.data.inherits_class('kernel',d): > - share_src = d.getVar('STAGING_KERNEL_DIR') > - cmd_copy_share = "cp -rf " + share_src + "/* " + src_dir > + "/" > - cmd_copy_shared_res = os.popen(cmd_copy_share).read() > - bb.note("cmd_copy_shared_result = " + > cmd_copy_shared_res) > - > - git_path = src_dir + "/.git" > - if os.path.exists(git_path): import os.path is missing > - shutils.rmtree(git_path) Should be: shutil.rmtree(git_path) Thank you for SPDX 3.0 support. Adrian > - > - # Make sure gcc and kernel sources are patched only once > - if not (d.getVar('SRC_URI') == "" or > is_work_shared_spdx(d)): > - bb.build.exec_func('do_patch', d) > - > - # Some userland has no source. > - if not os.path.exists( spdx_workdir ): > - bb.utils.mkdirhier(spdx_workdir) > - finally: > - d.setVar("WORKDIR", workdir) > - > -spdx_get_src[vardepsexclude] += "STAGING_KERNEL_DIR" > - > do_rootfs[recrdeptask] += "do_create_spdx do_create_runtime_spdx" > do_rootfs[cleandirs] += "${SPDXIMAGEWORK}" > > @@ -1019,7 +780,7 @@ def combine_spdx(d, rootfs_name, > rootfs_deploydir, rootfs_spdxid, packages, spdx > > doc = oe.spdx.SPDXDocument() > doc.name = rootfs_name > - doc.documentNamespace = get_doc_namespace(d, doc) > + doc.documentNamespace = get_namespace(d, doc.name) > doc.creationInfo.created = creation_time > doc.creationInfo.comment = "This document was created by > analyzing the source of the Yocto recipe during the build." > doc.creationInfo.licenseListVersion = > d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] > diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx- > common.bbclass > new file mode 100644 > index 00000000000..468a11ca3e2 > --- /dev/null > +++ b/meta/classes/spdx-common.bbclass > @@ -0,0 +1,256 @@ > +# > +# Copyright OpenEmbedded Contributors > +# > +# SPDX-License-Identifier: GPL-2.0-only > +# > + > +DEPLOY_DIR_SPDX ??= "${DEPLOY_DIR}/spdx" > + > +# The product name that the CVE database uses. Defaults to BPN, but > may need to > +# be overriden per recipe (for example tiff.bb sets > CVE_PRODUCT=libtiff). > +CVE_PRODUCT ??= "${BPN}" > +CVE_VERSION ??= "${PV}" > + > +SPDXDIR ??= "${WORKDIR}/spdx" > +SPDXDEPLOY = "${SPDXDIR}/deploy" > +SPDXWORK = "${SPDXDIR}/work" > +SPDXIMAGEWORK = "${SPDXDIR}/image-work" > +SPDXSDKWORK = "${SPDXDIR}/sdk-work" > +SPDXDEPS = "${SPDXDIR}/deps.json" > + > +SPDX_TOOL_NAME ??= "oe-spdx-creator" > +SPDX_TOOL_VERSION ??= "1.0" > + > +SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" > + > +SPDX_INCLUDE_SOURCES ??= "0" > +SPDX_ARCHIVE_SOURCES ??= "0" > +SPDX_ARCHIVE_PACKAGED ??= "0" > + > +SPDX_UUID_NAMESPACE ??= "sbom.openembedded.org" > +SPDX_NAMESPACE_PREFIX ??= "http://spdx.org/spdxdocs" > +SPDX_PRETTY ??= "0" > + > +SPDX_LICENSES ??= "${COREBASE}/meta/files/spdx-licenses.json" > + > +SPDX_CUSTOM_ANNOTATION_VARS ??= "" > + > +SPDX_ORG ??= "OpenEmbedded ()" > +SPDX_SUPPLIER ??= "Organization: ${SPDX_ORG}" > +SPDX_SUPPLIER[doc] = "The SPDX PackageSupplier field for SPDX > packages created from \ > + this recipe. For SPDX documents create using this class during > the build, this \ > + is the contact information for the person or organization who is > doing the \ > + build." > + > +def extract_licenses(filename): > + import re > + > + lic_regex = re.compile(rb'^\W*SPDX-License-Identifier:\s*([ > \w\d.()+-]+?)(?:\s+\W*)?$', re.MULTILINE) > + > + try: > + with open(filename, 'rb') as f: > + size = min(15000, os.stat(filename).st_size) > + txt = f.read(size) > + licenses = re.findall(lic_regex, txt) > + if licenses: > + ascii_licenses = [lic.decode('ascii') for lic in > licenses] > + return ascii_licenses > + except Exception as e: > + bb.warn(f"Exception reading {filename}: {e}") > + return None > + > +def is_work_shared_spdx(d): > + return bb.data.inherits_class('kernel', d) or ('work-shared' in > d.getVar('WORKDIR')) > + > +def get_json_indent(d): > + if d.getVar("SPDX_PRETTY") == "1": > + return 2 > + return None > + > +python() { > + import json > + if d.getVar("SPDX_LICENSE_DATA"): > + return > + > + with open(d.getVar("SPDX_LICENSES"), "r") as f: > + data = json.load(f) > + # Transform the license array to a dictionary > + data["licenses"] = {l["licenseId"]: l for l in > data["licenses"]} > + d.setVar("SPDX_LICENSE_DATA", data) > +} > + > +def process_sources(d): > + pn = d.getVar('PN') > + assume_provided = (d.getVar("ASSUME_PROVIDED") or "").split() > + if pn in assume_provided: > + for p in d.getVar("PROVIDES").split(): > + if p != pn: > + pn = p > + break > + > + # glibc-locale: do_fetch, do_unpack and do_patch tasks have been > deleted, > + # so avoid archiving source here. > + if pn.startswith('glibc-locale'): > + return False > + if d.getVar('PN') == "libtool-cross": > + return False > + if d.getVar('PN') == "libgcc-initial": > + return False > + if d.getVar('PN') == "shadow-sysroot": > + return False > + > + # We just archive gcc-source for all the gcc related recipes > + if d.getVar('BPN') in ['gcc', 'libgcc']: > + bb.debug(1, 'spdx: There is bug in scan of %s is, do > nothing' % pn) > + return False > + > + return True > + > +def collect_direct_deps(d, dep_task): > + current_task = "do_" + d.getVar("BB_CURRENTTASK") > + pn = d.getVar("PN") > + > + taskdepdata = d.getVar("BB_TASKDEPDATA", False) > + > + for this_dep in taskdepdata.values(): > + if this_dep[0] == pn and this_dep[1] == current_task: > + break > + else: > + bb.fatal(f"Unable to find this {pn}:{current_task} in > taskdepdata") > + > + deps = set() > + > + for dep_name in this_dep.deps: > + dep_data = taskdepdata[dep_name] > + if dep_data.taskname == dep_task and dep_data.pn != pn: > + deps.add((dep_data.pn, dep_data.hashfn, dep_name in > this_dep.taskhash_deps)) > + > + return sorted(deps) > + > +collect_direct_deps[vardepsexclude] += "BB_TASKDEPDATA" > +collect_direct_deps[vardeps] += "DEPENDS" > + > +python do_collect_spdx_deps() { > + # This task calculates the build time dependencies of the > recipe, and is > + # required because while a task can deptask on itself, those > dependencies > + # do not show up in BB_TASKDEPDATA. To work around that, this > task does the > + # deptask on do_create_spdx and writes out the dependencies it > finds, then > + # do_create_spdx reads in the found dependencies when writing > the actual > + # SPDX document > + import json > + from pathlib import Path > + > + spdx_deps_file = Path(d.getVar("SPDXDEPS")) > + > + deps = collect_direct_deps(d, "do_create_spdx") > + > + with spdx_deps_file.open("w") as f: > + json.dump(deps, f) > +} > +# NOTE: depending on do_unpack is a hack that is necessary to get > it's dependencies for archive the source > +addtask do_collect_spdx_deps after do_unpack > +do_collect_spdx_deps[depends] += "${PATCHDEPENDENCY}" > +do_collect_spdx_deps[deptask] = "do_create_spdx" > +do_collect_spdx_deps[dirs] = "${SPDXDIR}" > + > +def get_spdx_deps(d): > + import json > + from pathlib import Path > + > + spdx_deps_file = Path(d.getVar("SPDXDEPS")) > + > + with spdx_deps_file.open("r") as f: > + return json.load(f) > + > +def collect_package_providers(d): > + from pathlib import Path > + import oe.sbom > + import oe.spdx > + import json > + > + deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) > + > + providers = {} > + > + deps = collect_direct_deps(d, "do_create_spdx") > + deps.append((d.getVar("PN"), d.getVar("BB_HASHFILENAME"), True)) > + > + for dep_pn, dep_hashfn, _ in deps: > + localdata = d > + recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) > + if not recipe_data: > + localdata = bb.data.createCopy(d) > + localdata.setVar("PKGDATA_DIR", "${PKGDATA_DIR_SDK}") > + recipe_data = oe.packagedata.read_pkgdata(dep_pn, > localdata) > + > + for pkg in recipe_data.get("PACKAGES", "").split(): > + > + pkg_data = oe.packagedata.read_subpkgdata_dict(pkg, > localdata) > + rprovides = set(n for n, _ in > bb.utils.explode_dep_versions2(pkg_data.get("RPROVIDES", > "")).items()) > + rprovides.add(pkg) > + > + if "PKG" in pkg_data: > + pkg = pkg_data["PKG"] > + rprovides.add(pkg) > + > + for r in rprovides: > + providers[r] = (pkg, dep_hashfn) > + > + return providers > + > +collect_package_providers[vardepsexclude] += "BB_TASKDEPDATA" > + > +def spdx_get_src(d): > + """ > + save patched source of the recipe in SPDX_WORKDIR. > + """ > + import shutil > + spdx_workdir = d.getVar('SPDXWORK') > + spdx_sysroot_native = d.getVar('STAGING_DIR_NATIVE') > + pn = d.getVar('PN') > + > + workdir = d.getVar("WORKDIR") > + > + try: > + # The kernel class functions require it to be on work- > shared, so we dont change WORKDIR > + if not is_work_shared_spdx(d): > + # Change the WORKDIR to make do_unpack do_patch run in > another dir. > + d.setVar('WORKDIR', spdx_workdir) > + # Restore the original path to recipe's native sysroot > (it's relative to WORKDIR). > + d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) > + > + # The changed 'WORKDIR' also caused 'B' changed, create > dir 'B' for the > + # possibly requiring of the following tasks (such as > some recipes's > + # do_patch required 'B' existed). > + bb.utils.mkdirhier(d.getVar('B')) > + > + bb.build.exec_func('do_unpack', d) > + # Copy source of kernel to spdx_workdir > + if is_work_shared_spdx(d): > + share_src = d.getVar('WORKDIR') > + d.setVar('WORKDIR', spdx_workdir) > + d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) > + src_dir = spdx_workdir + "/" + d.getVar('PN')+ "-" + > d.getVar('PV') + "-" + d.getVar('PR') > + bb.utils.mkdirhier(src_dir) > + if bb.data.inherits_class('kernel',d): > + share_src = d.getVar('STAGING_KERNEL_DIR') > + cmd_copy_share = "cp -rf " + share_src + "/* " + src_dir > + "/" > + cmd_copy_shared_res = os.popen(cmd_copy_share).read() > + bb.note("cmd_copy_shared_result = " + > cmd_copy_shared_res) > + > + git_path = src_dir + "/.git" > + if os.path.exists(git_path): > + shutils.rmtree(git_path) > + > + # Make sure gcc and kernel sources are patched only once > + if not (d.getVar('SRC_URI') == "" or > is_work_shared_spdx(d)): > + bb.build.exec_func('do_patch', d) > + > + # Some userland has no source. > + if not os.path.exists( spdx_workdir ): > + bb.utils.mkdirhier(spdx_workdir) > + finally: > + d.setVar("WORKDIR", workdir) > + > +spdx_get_src[vardepsexclude] += "STAGING_KERNEL_DIR" > + > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#200486): > https://lists.openembedded.org/g/openembedded-core/message/200486 > Mute This Topic: https://lists.openembedded.org/mt/106602516/4454582 > Group Owner: openembedded-core+owner@lists.openembedded.org > Unsubscribe: > https://lists.openembedded.org/g/openembedded-core/unsub [ > adrian.freihofer@gmail.com] > -=-=-=-=-=-=-=-=-=-=-=- >
diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass index 7c8a0b8b0f7..94a172fbc94 100644 --- a/meta/classes/create-spdx-2.2.bbclass +++ b/meta/classes/create-spdx-2.2.bbclass @@ -4,65 +4,13 @@ # SPDX-License-Identifier: GPL-2.0-only # -DEPLOY_DIR_SPDX ??= "${DEPLOY_DIR}/spdx" - -# The product name that the CVE database uses. Defaults to BPN, but may need to -# be overriden per recipe (for example tiff.bb sets CVE_PRODUCT=libtiff). -CVE_PRODUCT ??= "${BPN}" -CVE_VERSION ??= "${PV}" - -SPDXDIR ??= "${WORKDIR}/spdx" -SPDXDEPLOY = "${SPDXDIR}/deploy" -SPDXWORK = "${SPDXDIR}/work" -SPDXIMAGEWORK = "${SPDXDIR}/image-work" -SPDXSDKWORK = "${SPDXDIR}/sdk-work" -SPDXDEPS = "${SPDXDIR}/deps.json" - -SPDX_TOOL_NAME ??= "oe-spdx-creator" -SPDX_TOOL_VERSION ??= "1.0" - -SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" - -SPDX_INCLUDE_SOURCES ??= "0" -SPDX_ARCHIVE_SOURCES ??= "0" -SPDX_ARCHIVE_PACKAGED ??= "0" - -SPDX_UUID_NAMESPACE ??= "sbom.openembedded.org" -SPDX_NAMESPACE_PREFIX ??= "http://spdx.org/spdxdocs" -SPDX_PRETTY ??= "0" - -SPDX_LICENSES ??= "${COREBASE}/meta/files/spdx-licenses.json" - -SPDX_CUSTOM_ANNOTATION_VARS ??= "" - -SPDX_ORG ??= "OpenEmbedded ()" -SPDX_SUPPLIER ??= "Organization: ${SPDX_ORG}" -SPDX_SUPPLIER[doc] = "The SPDX PackageSupplier field for SPDX packages created from \ - this recipe. For SPDX documents create using this class during the build, this \ - is the contact information for the person or organization who is doing the \ - build." - -def extract_licenses(filename): - import re - - lic_regex = re.compile(rb'^\W*SPDX-License-Identifier:\s*([ \w\d.()+-]+?)(?:\s+\W*)?$', re.MULTILINE) - - try: - with open(filename, 'rb') as f: - size = min(15000, os.stat(filename).st_size) - txt = f.read(size) - licenses = re.findall(lic_regex, txt) - if licenses: - ascii_licenses = [lic.decode('ascii') for lic in licenses] - return ascii_licenses - except Exception as e: - bb.warn(f"Exception reading {filename}: {e}") - return None - -def get_doc_namespace(d, doc): +inherit spdx-common + +def get_namespace(d, name): import uuid namespace_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, d.getVar("SPDX_UUID_NAMESPACE")) - return "%s/%s-%s" % (d.getVar("SPDX_NAMESPACE_PREFIX"), doc.name, str(uuid.uuid5(namespace_uuid, doc.name))) + return "%s/%s-%s" % (d.getVar("SPDX_NAMESPACE_PREFIX"), name, str(uuid.uuid5(namespace_uuid, name))) + def create_annotation(d, comment): from datetime import datetime, timezone @@ -80,26 +28,6 @@ def recipe_spdx_is_native(d, recipe): a.annotator == "Tool: %s - %s" % (d.getVar("SPDX_TOOL_NAME"), d.getVar("SPDX_TOOL_VERSION")) and a.comment == "isNative" for a in recipe.annotations) -def is_work_shared_spdx(d): - return bb.data.inherits_class('kernel', d) or ('work-shared' in d.getVar('WORKDIR')) - -def get_json_indent(d): - if d.getVar("SPDX_PRETTY") == "1": - return 2 - return None - -python() { - import json - if d.getVar("SPDX_LICENSE_DATA"): - return - - with open(d.getVar("SPDX_LICENSES"), "r") as f: - data = json.load(f) - # Transform the license array to a dictionary - data["licenses"] = {l["licenseId"]: l for l in data["licenses"]} - d.setVar("SPDX_LICENSE_DATA", data) -} - def convert_license_to_spdx(lic, document, d, existing={}): from pathlib import Path import oe.spdx @@ -172,34 +100,6 @@ def convert_license_to_spdx(lic, document, d, existing={}): return ' '.join(convert(l) for l in lic_split) -def process_sources(d): - pn = d.getVar('PN') - assume_provided = (d.getVar("ASSUME_PROVIDED") or "").split() - if pn in assume_provided: - for p in d.getVar("PROVIDES").split(): - if p != pn: - pn = p - break - - # glibc-locale: do_fetch, do_unpack and do_patch tasks have been deleted, - # so avoid archiving source here. - if pn.startswith('glibc-locale'): - return False - if d.getVar('PN') == "libtool-cross": - return False - if d.getVar('PN') == "libgcc-initial": - return False - if d.getVar('PN') == "shadow-sysroot": - return False - - # We just archive gcc-source for all the gcc related recipes - if d.getVar('BPN') in ['gcc', 'libgcc']: - bb.debug(1, 'spdx: There is bug in scan of %s is, do nothing' % pn) - return False - - return True - - def add_package_files(d, doc, spdx_pkg, topdir, get_spdxid, get_types, *, archive=None, ignore_dirs=[], ignore_top_level_dirs=[]): from pathlib import Path import oe.spdx @@ -348,14 +248,12 @@ def collect_dep_recipes(d, doc, spdx_recipe): import oe.spdx deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) - spdx_deps_file = Path(d.getVar("SPDXDEPS")) package_archs = d.getVar("SSTATE_ARCHS").split() package_archs.reverse() dep_recipes = [] - with spdx_deps_file.open("r") as f: - deps = json.load(f) + deps = get_spdx_deps(d) for dep_pn, dep_hashfn, in_taskhash in deps: # If this dependency is not calculated in the taskhash skip it. @@ -468,51 +366,6 @@ def add_download_packages(d, doc, recipe): # but this should be sufficient for now doc.add_relationship(package, "BUILD_DEPENDENCY_OF", recipe) -def collect_direct_deps(d, dep_task): - current_task = "do_" + d.getVar("BB_CURRENTTASK") - pn = d.getVar("PN") - - taskdepdata = d.getVar("BB_TASKDEPDATA", False) - - for this_dep in taskdepdata.values(): - if this_dep[0] == pn and this_dep[1] == current_task: - break - else: - bb.fatal(f"Unable to find this {pn}:{current_task} in taskdepdata") - - deps = set() - for dep_name in this_dep[3]: - dep_data = taskdepdata[dep_name] - if dep_data[1] == dep_task and dep_data[0] != pn: - deps.add((dep_data[0], dep_data[7], dep_name in this_dep[8])) - - return sorted(deps) - -collect_direct_deps[vardepsexclude] += "BB_TASKDEPDATA" -collect_direct_deps[vardeps] += "DEPENDS" - -python do_collect_spdx_deps() { - # This task calculates the build time dependencies of the recipe, and is - # required because while a task can deptask on itself, those dependencies - # do not show up in BB_TASKDEPDATA. To work around that, this task does the - # deptask on do_create_spdx and writes out the dependencies it finds, then - # do_create_spdx reads in the found dependencies when writing the actual - # SPDX document - import json - from pathlib import Path - - spdx_deps_file = Path(d.getVar("SPDXDEPS")) - - deps = collect_direct_deps(d, "do_create_spdx") - - with spdx_deps_file.open("w") as f: - json.dump(deps, f) -} -# NOTE: depending on do_unpack is a hack that is necessary to get it's dependencies for archive the source -addtask do_collect_spdx_deps after do_unpack -do_collect_spdx_deps[depends] += "${PATCHDEPENDENCY}" -do_collect_spdx_deps[deptask] = "do_create_spdx" -do_collect_spdx_deps[dirs] = "${SPDXDIR}" python do_create_spdx() { from datetime import datetime, timezone @@ -551,7 +404,7 @@ python do_create_spdx() { doc = oe.spdx.SPDXDocument() doc.name = "recipe-" + d.getVar("PN") - doc.documentNamespace = get_doc_namespace(d, doc) + doc.documentNamespace = get_namespace(d, doc.name) doc.creationInfo.created = creation_time doc.creationInfo.comment = "This document was created by analyzing recipe files during the build." doc.creationInfo.licenseListVersion = d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] @@ -655,7 +508,7 @@ python do_create_spdx() { package_doc = oe.spdx.SPDXDocument() pkg_name = d.getVar("PKG:%s" % package) or package package_doc.name = pkg_name - package_doc.documentNamespace = get_doc_namespace(d, package_doc) + package_doc.documentNamespace = get_namespace(d, package_doc.name) package_doc.creationInfo.created = creation_time package_doc.creationInfo.comment = "This document was created by analyzing packages created during the build." package_doc.creationInfo.licenseListVersion = d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] @@ -716,44 +569,6 @@ do_create_spdx[dirs] = "${SPDXWORK}" do_create_spdx[cleandirs] = "${SPDXDEPLOY} ${SPDXWORK}" do_create_spdx[depends] += "${PATCHDEPENDENCY}" -def collect_package_providers(d): - from pathlib import Path - import oe.sbom - import oe.spdx - import json - - deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) - - providers = {} - - deps = collect_direct_deps(d, "do_create_spdx") - deps.append((d.getVar("PN"), d.getVar("BB_HASHFILENAME"), True)) - - for dep_pn, dep_hashfn, _ in deps: - localdata = d - recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) - if not recipe_data: - localdata = bb.data.createCopy(d) - localdata.setVar("PKGDATA_DIR", "${PKGDATA_DIR_SDK}") - recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) - - for pkg in recipe_data.get("PACKAGES", "").split(): - - pkg_data = oe.packagedata.read_subpkgdata_dict(pkg, localdata) - rprovides = set(n for n, _ in bb.utils.explode_dep_versions2(pkg_data.get("RPROVIDES", "")).items()) - rprovides.add(pkg) - - if "PKG" in pkg_data: - pkg = pkg_data["PKG"] - rprovides.add(pkg) - - for r in rprovides: - providers[r] = (pkg, dep_hashfn) - - return providers - -collect_package_providers[vardepsexclude] += "BB_TASKDEPDATA" - python do_create_runtime_spdx() { from datetime import datetime, timezone import oe.sbom @@ -800,7 +615,7 @@ python do_create_runtime_spdx() { runtime_doc = oe.spdx.SPDXDocument() runtime_doc.name = "runtime-" + pkg_name - runtime_doc.documentNamespace = get_doc_namespace(localdata, runtime_doc) + runtime_doc.documentNamespace = get_namespace(localdata, runtime_doc.name) runtime_doc.creationInfo.created = creation_time runtime_doc.creationInfo.comment = "This document was created by analyzing package runtime dependencies." runtime_doc.creationInfo.licenseListVersion = d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] @@ -891,60 +706,6 @@ do_create_runtime_spdx[dirs] = "${SPDXRUNTIMEDEPLOY}" do_create_runtime_spdx[cleandirs] = "${SPDXRUNTIMEDEPLOY}" do_create_runtime_spdx[rdeptask] = "do_create_spdx" -def spdx_get_src(d): - """ - save patched source of the recipe in SPDX_WORKDIR. - """ - import shutil - spdx_workdir = d.getVar('SPDXWORK') - spdx_sysroot_native = d.getVar('STAGING_DIR_NATIVE') - pn = d.getVar('PN') - - workdir = d.getVar("WORKDIR") - - try: - # The kernel class functions require it to be on work-shared, so we dont change WORKDIR - if not is_work_shared_spdx(d): - # Change the WORKDIR to make do_unpack do_patch run in another dir. - d.setVar('WORKDIR', spdx_workdir) - # Restore the original path to recipe's native sysroot (it's relative to WORKDIR). - d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) - - # The changed 'WORKDIR' also caused 'B' changed, create dir 'B' for the - # possibly requiring of the following tasks (such as some recipes's - # do_patch required 'B' existed). - bb.utils.mkdirhier(d.getVar('B')) - - bb.build.exec_func('do_unpack', d) - # Copy source of kernel to spdx_workdir - if is_work_shared_spdx(d): - share_src = d.getVar('WORKDIR') - d.setVar('WORKDIR', spdx_workdir) - d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) - src_dir = spdx_workdir + "/" + d.getVar('PN')+ "-" + d.getVar('PV') + "-" + d.getVar('PR') - bb.utils.mkdirhier(src_dir) - if bb.data.inherits_class('kernel',d): - share_src = d.getVar('STAGING_KERNEL_DIR') - cmd_copy_share = "cp -rf " + share_src + "/* " + src_dir + "/" - cmd_copy_shared_res = os.popen(cmd_copy_share).read() - bb.note("cmd_copy_shared_result = " + cmd_copy_shared_res) - - git_path = src_dir + "/.git" - if os.path.exists(git_path): - shutils.rmtree(git_path) - - # Make sure gcc and kernel sources are patched only once - if not (d.getVar('SRC_URI') == "" or is_work_shared_spdx(d)): - bb.build.exec_func('do_patch', d) - - # Some userland has no source. - if not os.path.exists( spdx_workdir ): - bb.utils.mkdirhier(spdx_workdir) - finally: - d.setVar("WORKDIR", workdir) - -spdx_get_src[vardepsexclude] += "STAGING_KERNEL_DIR" - do_rootfs[recrdeptask] += "do_create_spdx do_create_runtime_spdx" do_rootfs[cleandirs] += "${SPDXIMAGEWORK}" @@ -1019,7 +780,7 @@ def combine_spdx(d, rootfs_name, rootfs_deploydir, rootfs_spdxid, packages, spdx doc = oe.spdx.SPDXDocument() doc.name = rootfs_name - doc.documentNamespace = get_doc_namespace(d, doc) + doc.documentNamespace = get_namespace(d, doc.name) doc.creationInfo.created = creation_time doc.creationInfo.comment = "This document was created by analyzing the source of the Yocto recipe during the build." doc.creationInfo.licenseListVersion = d.getVar("SPDX_LICENSE_DATA")["licenseListVersion"] diff --git a/meta/classes/spdx-common.bbclass b/meta/classes/spdx-common.bbclass new file mode 100644 index 00000000000..468a11ca3e2 --- /dev/null +++ b/meta/classes/spdx-common.bbclass @@ -0,0 +1,256 @@ +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: GPL-2.0-only +# + +DEPLOY_DIR_SPDX ??= "${DEPLOY_DIR}/spdx" + +# The product name that the CVE database uses. Defaults to BPN, but may need to +# be overriden per recipe (for example tiff.bb sets CVE_PRODUCT=libtiff). +CVE_PRODUCT ??= "${BPN}" +CVE_VERSION ??= "${PV}" + +SPDXDIR ??= "${WORKDIR}/spdx" +SPDXDEPLOY = "${SPDXDIR}/deploy" +SPDXWORK = "${SPDXDIR}/work" +SPDXIMAGEWORK = "${SPDXDIR}/image-work" +SPDXSDKWORK = "${SPDXDIR}/sdk-work" +SPDXDEPS = "${SPDXDIR}/deps.json" + +SPDX_TOOL_NAME ??= "oe-spdx-creator" +SPDX_TOOL_VERSION ??= "1.0" + +SPDXRUNTIMEDEPLOY = "${SPDXDIR}/runtime-deploy" + +SPDX_INCLUDE_SOURCES ??= "0" +SPDX_ARCHIVE_SOURCES ??= "0" +SPDX_ARCHIVE_PACKAGED ??= "0" + +SPDX_UUID_NAMESPACE ??= "sbom.openembedded.org" +SPDX_NAMESPACE_PREFIX ??= "http://spdx.org/spdxdocs" +SPDX_PRETTY ??= "0" + +SPDX_LICENSES ??= "${COREBASE}/meta/files/spdx-licenses.json" + +SPDX_CUSTOM_ANNOTATION_VARS ??= "" + +SPDX_ORG ??= "OpenEmbedded ()" +SPDX_SUPPLIER ??= "Organization: ${SPDX_ORG}" +SPDX_SUPPLIER[doc] = "The SPDX PackageSupplier field for SPDX packages created from \ + this recipe. For SPDX documents create using this class during the build, this \ + is the contact information for the person or organization who is doing the \ + build." + +def extract_licenses(filename): + import re + + lic_regex = re.compile(rb'^\W*SPDX-License-Identifier:\s*([ \w\d.()+-]+?)(?:\s+\W*)?$', re.MULTILINE) + + try: + with open(filename, 'rb') as f: + size = min(15000, os.stat(filename).st_size) + txt = f.read(size) + licenses = re.findall(lic_regex, txt) + if licenses: + ascii_licenses = [lic.decode('ascii') for lic in licenses] + return ascii_licenses + except Exception as e: + bb.warn(f"Exception reading {filename}: {e}") + return None + +def is_work_shared_spdx(d): + return bb.data.inherits_class('kernel', d) or ('work-shared' in d.getVar('WORKDIR')) + +def get_json_indent(d): + if d.getVar("SPDX_PRETTY") == "1": + return 2 + return None + +python() { + import json + if d.getVar("SPDX_LICENSE_DATA"): + return + + with open(d.getVar("SPDX_LICENSES"), "r") as f: + data = json.load(f) + # Transform the license array to a dictionary + data["licenses"] = {l["licenseId"]: l for l in data["licenses"]} + d.setVar("SPDX_LICENSE_DATA", data) +} + +def process_sources(d): + pn = d.getVar('PN') + assume_provided = (d.getVar("ASSUME_PROVIDED") or "").split() + if pn in assume_provided: + for p in d.getVar("PROVIDES").split(): + if p != pn: + pn = p + break + + # glibc-locale: do_fetch, do_unpack and do_patch tasks have been deleted, + # so avoid archiving source here. + if pn.startswith('glibc-locale'): + return False + if d.getVar('PN') == "libtool-cross": + return False + if d.getVar('PN') == "libgcc-initial": + return False + if d.getVar('PN') == "shadow-sysroot": + return False + + # We just archive gcc-source for all the gcc related recipes + if d.getVar('BPN') in ['gcc', 'libgcc']: + bb.debug(1, 'spdx: There is bug in scan of %s is, do nothing' % pn) + return False + + return True + +def collect_direct_deps(d, dep_task): + current_task = "do_" + d.getVar("BB_CURRENTTASK") + pn = d.getVar("PN") + + taskdepdata = d.getVar("BB_TASKDEPDATA", False) + + for this_dep in taskdepdata.values(): + if this_dep[0] == pn and this_dep[1] == current_task: + break + else: + bb.fatal(f"Unable to find this {pn}:{current_task} in taskdepdata") + + deps = set() + + for dep_name in this_dep.deps: + dep_data = taskdepdata[dep_name] + if dep_data.taskname == dep_task and dep_data.pn != pn: + deps.add((dep_data.pn, dep_data.hashfn, dep_name in this_dep.taskhash_deps)) + + return sorted(deps) + +collect_direct_deps[vardepsexclude] += "BB_TASKDEPDATA" +collect_direct_deps[vardeps] += "DEPENDS" + +python do_collect_spdx_deps() { + # This task calculates the build time dependencies of the recipe, and is + # required because while a task can deptask on itself, those dependencies + # do not show up in BB_TASKDEPDATA. To work around that, this task does the + # deptask on do_create_spdx and writes out the dependencies it finds, then + # do_create_spdx reads in the found dependencies when writing the actual + # SPDX document + import json + from pathlib import Path + + spdx_deps_file = Path(d.getVar("SPDXDEPS")) + + deps = collect_direct_deps(d, "do_create_spdx") + + with spdx_deps_file.open("w") as f: + json.dump(deps, f) +} +# NOTE: depending on do_unpack is a hack that is necessary to get it's dependencies for archive the source +addtask do_collect_spdx_deps after do_unpack +do_collect_spdx_deps[depends] += "${PATCHDEPENDENCY}" +do_collect_spdx_deps[deptask] = "do_create_spdx" +do_collect_spdx_deps[dirs] = "${SPDXDIR}" + +def get_spdx_deps(d): + import json + from pathlib import Path + + spdx_deps_file = Path(d.getVar("SPDXDEPS")) + + with spdx_deps_file.open("r") as f: + return json.load(f) + +def collect_package_providers(d): + from pathlib import Path + import oe.sbom + import oe.spdx + import json + + deploy_dir_spdx = Path(d.getVar("DEPLOY_DIR_SPDX")) + + providers = {} + + deps = collect_direct_deps(d, "do_create_spdx") + deps.append((d.getVar("PN"), d.getVar("BB_HASHFILENAME"), True)) + + for dep_pn, dep_hashfn, _ in deps: + localdata = d + recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) + if not recipe_data: + localdata = bb.data.createCopy(d) + localdata.setVar("PKGDATA_DIR", "${PKGDATA_DIR_SDK}") + recipe_data = oe.packagedata.read_pkgdata(dep_pn, localdata) + + for pkg in recipe_data.get("PACKAGES", "").split(): + + pkg_data = oe.packagedata.read_subpkgdata_dict(pkg, localdata) + rprovides = set(n for n, _ in bb.utils.explode_dep_versions2(pkg_data.get("RPROVIDES", "")).items()) + rprovides.add(pkg) + + if "PKG" in pkg_data: + pkg = pkg_data["PKG"] + rprovides.add(pkg) + + for r in rprovides: + providers[r] = (pkg, dep_hashfn) + + return providers + +collect_package_providers[vardepsexclude] += "BB_TASKDEPDATA" + +def spdx_get_src(d): + """ + save patched source of the recipe in SPDX_WORKDIR. + """ + import shutil + spdx_workdir = d.getVar('SPDXWORK') + spdx_sysroot_native = d.getVar('STAGING_DIR_NATIVE') + pn = d.getVar('PN') + + workdir = d.getVar("WORKDIR") + + try: + # The kernel class functions require it to be on work-shared, so we dont change WORKDIR + if not is_work_shared_spdx(d): + # Change the WORKDIR to make do_unpack do_patch run in another dir. + d.setVar('WORKDIR', spdx_workdir) + # Restore the original path to recipe's native sysroot (it's relative to WORKDIR). + d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) + + # The changed 'WORKDIR' also caused 'B' changed, create dir 'B' for the + # possibly requiring of the following tasks (such as some recipes's + # do_patch required 'B' existed). + bb.utils.mkdirhier(d.getVar('B')) + + bb.build.exec_func('do_unpack', d) + # Copy source of kernel to spdx_workdir + if is_work_shared_spdx(d): + share_src = d.getVar('WORKDIR') + d.setVar('WORKDIR', spdx_workdir) + d.setVar('STAGING_DIR_NATIVE', spdx_sysroot_native) + src_dir = spdx_workdir + "/" + d.getVar('PN')+ "-" + d.getVar('PV') + "-" + d.getVar('PR') + bb.utils.mkdirhier(src_dir) + if bb.data.inherits_class('kernel',d): + share_src = d.getVar('STAGING_KERNEL_DIR') + cmd_copy_share = "cp -rf " + share_src + "/* " + src_dir + "/" + cmd_copy_shared_res = os.popen(cmd_copy_share).read() + bb.note("cmd_copy_shared_result = " + cmd_copy_shared_res) + + git_path = src_dir + "/.git" + if os.path.exists(git_path): + shutils.rmtree(git_path) + + # Make sure gcc and kernel sources are patched only once + if not (d.getVar('SRC_URI') == "" or is_work_shared_spdx(d)): + bb.build.exec_func('do_patch', d) + + # Some userland has no source. + if not os.path.exists( spdx_workdir ): + bb.utils.mkdirhier(spdx_workdir) + finally: + d.setVar("WORKDIR", workdir) + +spdx_get_src[vardepsexclude] += "STAGING_KERNEL_DIR" +
Moves SPDX code that can be shared between different SPDX versions into a common class Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> --- meta/classes/create-spdx-2.2.bbclass | 259 ++------------------------- meta/classes/spdx-common.bbclass | 256 ++++++++++++++++++++++++++ 2 files changed, 266 insertions(+), 249 deletions(-) create mode 100644 meta/classes/spdx-common.bbclass