summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/fetch2/__init__.py
diff options
context:
space:
mode:
authorAlberto Pianon <alberto@pianon.eu>2023-10-01 09:52:25 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-10-15 09:12:43 +0100
commitef3e46afd910d4b7727d42c4c18b501525c65695 (patch)
tree7ee4e4edcf1de85190f766bda4a92a5e6f201f1a /bitbake/lib/bb/fetch2/__init__.py
parent3a09f0d184683b5d38941e112cc25906d6999771 (diff)
downloadpoky-ef3e46afd910d4b7727d42c4c18b501525c65695.tar.gz
bitbake: fetch2: Add API for upstream source tracing
This patch adds an API to bb.fetch2 to enable users to plug in an unpack tracer that can trace each source file back to its corresponding upstream source url, even when multiple upstream sources are combined together in the same unpack directory. This may be required for software composition analysis, license compliance, and detailed SBoM generation. This patch provides only the needed hooks in bb.fetch2 code and a dummy abstract class defining the API; users may load their own unpack tracer class by setting the BB_UNPACK_TRACER_CLASS config parameter. (Bitbake rev: 05051152cc42acc52bcf9af9a696f632fac4307f) Signed-off-by: Alberto Pianon <alberto@pianon.eu> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/fetch2/__init__.py')
-rw-r--r--bitbake/lib/bb/fetch2/__init__.py78
1 files changed, 78 insertions, 0 deletions
diff --git a/bitbake/lib/bb/fetch2/__init__.py b/bitbake/lib/bb/fetch2/__init__.py
index ffb1a92b26..35e9ca96b7 100644
--- a/bitbake/lib/bb/fetch2/__init__.py
+++ b/bitbake/lib/bb/fetch2/__init__.py
@@ -1579,6 +1579,7 @@ class FetchMethod(object):
1579 unpackdir = rootdir 1579 unpackdir = rootdir
1580 1580
1581 if not unpack or not cmd: 1581 if not unpack or not cmd:
1582 urldata.unpack_tracer.unpack("file-copy", unpackdir)
1582 # If file == dest, then avoid any copies, as we already put the file into dest! 1583 # If file == dest, then avoid any copies, as we already put the file into dest!
1583 dest = os.path.join(unpackdir, os.path.basename(file)) 1584 dest = os.path.join(unpackdir, os.path.basename(file))
1584 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)): 1585 if file != dest and not (os.path.exists(dest) and os.path.samefile(file, dest)):
@@ -1593,6 +1594,8 @@ class FetchMethod(object):
1593 destdir = urlpath.rsplit("/", 1)[0] + '/' 1594 destdir = urlpath.rsplit("/", 1)[0] + '/'
1594 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir)) 1595 bb.utils.mkdirhier("%s/%s" % (unpackdir, destdir))
1595 cmd = 'cp -fpPRH "%s" "%s"' % (file, destdir) 1596 cmd = 'cp -fpPRH "%s" "%s"' % (file, destdir)
1597 else:
1598 urldata.unpack_tracer.unpack("archive-extract", unpackdir)
1596 1599
1597 if not cmd: 1600 if not cmd:
1598 return 1601 return
@@ -1684,6 +1687,55 @@ class FetchMethod(object):
1684 """ 1687 """
1685 return [] 1688 return []
1686 1689
1690
1691class DummyUnpackTracer(object):
1692 """
1693 Abstract API definition for a class that traces unpacked source files back
1694 to their respective upstream SRC_URI entries, for software composition
1695 analysis, license compliance and detailed SBOM generation purposes.
1696 User may load their own unpack tracer class (instead of the dummy
1697 one) by setting the BB_UNPACK_TRACER_CLASS config parameter.
1698 """
1699 def start(self, unpackdir, urldata_dict, d):
1700 """
1701 Start tracing the core Fetch.unpack process, using an index to map
1702 unpacked files to each SRC_URI entry.
1703 This method is called by Fetch.unpack and it may receive nested calls by
1704 gitsm and npmsw fetchers, that expand SRC_URI entries by adding implicit
1705 URLs and by recursively calling Fetch.unpack from new (nested) Fetch
1706 instances.
1707 """
1708 return
1709 def start_url(self, url):
1710 """Start tracing url unpack process.
1711 This method is called by Fetch.unpack before the fetcher-specific unpack
1712 method starts, and it may receive nested calls by gitsm and npmsw
1713 fetchers.
1714 """
1715 return
1716 def unpack(self, unpack_type, destdir):
1717 """
1718 Set unpack_type and destdir for current url.
1719 This method is called by the fetcher-specific unpack method after url
1720 tracing started.
1721 """
1722 return
1723 def finish_url(self, url):
1724 """Finish tracing url unpack process and update the file index.
1725 This method is called by Fetch.unpack after the fetcher-specific unpack
1726 method finished its job, and it may receive nested calls by gitsm
1727 and npmsw fetchers.
1728 """
1729 return
1730 def complete(self):
1731 """
1732 Finish tracing the Fetch.unpack process, and check if all nested
1733 Fecth.unpack calls (if any) have been completed; if so, save collected
1734 metadata.
1735 """
1736 return
1737
1738
1687class Fetch(object): 1739class Fetch(object):
1688 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None): 1740 def __init__(self, urls, d, cache = True, localonly = False, connection_cache = None):
1689 if localonly and cache: 1741 if localonly and cache:
@@ -1704,10 +1756,30 @@ class Fetch(object):
1704 if key in urldata_cache: 1756 if key in urldata_cache:
1705 self.ud = urldata_cache[key] 1757 self.ud = urldata_cache[key]
1706 1758
1759 # the unpack_tracer object needs to be made available to possible nested
1760 # Fetch instances (when those are created by gitsm and npmsw fetchers)
1761 # so we set it as a global variable
1762 global unpack_tracer
1763 try:
1764 unpack_tracer
1765 except NameError:
1766 class_path = d.getVar("BB_UNPACK_TRACER_CLASS")
1767 if class_path:
1768 # use user-defined unpack tracer class
1769 import importlib
1770 module_name, _, class_name = class_path.rpartition(".")
1771 module = importlib.import_module(module_name)
1772 class_ = getattr(module, class_name)
1773 unpack_tracer = class_()
1774 else:
1775 # fall back to the dummy/abstract class
1776 unpack_tracer = DummyUnpackTracer()
1777
1707 for url in urls: 1778 for url in urls:
1708 if url not in self.ud: 1779 if url not in self.ud:
1709 try: 1780 try:
1710 self.ud[url] = FetchData(url, d, localonly) 1781 self.ud[url] = FetchData(url, d, localonly)
1782 self.ud[url].unpack_tracer = unpack_tracer
1711 except NonLocalMethod: 1783 except NonLocalMethod:
1712 if localonly: 1784 if localonly:
1713 self.ud[url] = None 1785 self.ud[url] = None
@@ -1883,6 +1955,8 @@ class Fetch(object):
1883 if not urls: 1955 if not urls:
1884 urls = self.urls 1956 urls = self.urls
1885 1957
1958 unpack_tracer.start(root, self.ud, self.d)
1959
1886 for u in urls: 1960 for u in urls:
1887 ud = self.ud[u] 1961 ud = self.ud[u]
1888 ud.setup_localpath(self.d) 1962 ud.setup_localpath(self.d)
@@ -1890,11 +1964,15 @@ class Fetch(object):
1890 if ud.lockfile: 1964 if ud.lockfile:
1891 lf = bb.utils.lockfile(ud.lockfile) 1965 lf = bb.utils.lockfile(ud.lockfile)
1892 1966
1967 unpack_tracer.start_url(u)
1893 ud.method.unpack(ud, root, self.d) 1968 ud.method.unpack(ud, root, self.d)
1969 unpack_tracer.finish_url(u)
1894 1970
1895 if ud.lockfile: 1971 if ud.lockfile:
1896 bb.utils.unlockfile(lf) 1972 bb.utils.unlockfile(lf)
1897 1973
1974 unpack_tracer.complete()
1975
1898 def clean(self, urls=None): 1976 def clean(self, urls=None):
1899 """ 1977 """
1900 Clean files that the fetcher gets or places 1978 Clean files that the fetcher gets or places