diff options
author | Enguerrand de Ribaucourt <enguerrand.de-ribaucourt@savoirfairelinux.com> | 2024-08-12 14:28:27 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2024-08-23 09:51:36 +0100 |
commit | 01d17cd5d42d1c9c349e1249bdacffb24d8446bb (patch) | |
tree | 9ea7ba3390225d6b420f81579c2e58700990c5c8 | |
parent | 1053035cbca82f177e6cf8a2d467786de7aa146c (diff) | |
download | poky-01d17cd5d42d1c9c349e1249bdacffb24d8446bb.tar.gz |
recipetool: create_npm: resolve licenses defined in package.json
Some npm packages do not copy the LICENSE or COPY file into their
git repository. They'll instead simply use SPDX identifiers in their
package.json. A fallback for those repositories attempted to match
the README file to a license file instead, which had a very low
probability of success.
This commit replaces this fallback with parsing the package.json and
looking for the license in COMMON_LICENSE_DIR. If the license is not
found, "Unknown" will still be produced.
This also generates "Unknown" for packages which had no README file,
which could silently not appear in the generated recipe. The user was
more likely to miss them.
Co-authored-by: Tanguy Raufflet <tanguy.raufflet@savoirfairelinux.com>
(From OE-Core rev: 445604cfc4a5813ea635f18053cd1f673bf0b830)
Signed-off-by: Tanguy Raufflet <tanguy.raufflet@savoirfairelinux.com>
Signed-off-by: Enguerrand de Ribaucourt <enguerrand.de-ribaucourt@savoirfairelinux.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | scripts/lib/recipetool/create_npm.py | 57 |
1 files changed, 41 insertions, 16 deletions
diff --git a/scripts/lib/recipetool/create_npm.py b/scripts/lib/recipetool/create_npm.py index 113a89f6a6..dd0ac01c3e 100644 --- a/scripts/lib/recipetool/create_npm.py +++ b/scripts/lib/recipetool/create_npm.py | |||
@@ -112,40 +112,52 @@ class NpmRecipeHandler(RecipeHandler): | |||
112 | """Return the extra license files and the list of packages""" | 112 | """Return the extra license files and the list of packages""" |
113 | licfiles = [] | 113 | licfiles = [] |
114 | packages = {} | 114 | packages = {} |
115 | # Licenses from package.json point to COMMON_LICENSE_DIR so we need | ||
116 | # to associate them explicitely for split_pkg_licenses() | ||
117 | fallback_licenses = dict() | ||
115 | 118 | ||
116 | # Handle the parent package | 119 | # Handle the parent package |
117 | packages["${PN}"] = "" | 120 | packages["${PN}"] = "" |
118 | 121 | ||
119 | def _licfiles_append_fallback_readme_files(destdir): | 122 | def _licfiles_append_fallback_package_files(destdir): |
120 | """Append README files as fallback to license files if a license files is missing""" | 123 | """Append package.json files as fallback to license files if a license files is missing""" |
124 | def _get_licenses_from_package_json(package_json): | ||
125 | with open(os.path.join(srctree, package_json), "r") as f: | ||
126 | data = json.load(f) | ||
127 | if "license" in data: | ||
128 | licenses = data["license"].split(" ") | ||
129 | licenses = [license.strip("()") for license in licenses if license != "OR" and license != "AND"] | ||
130 | return ["${COMMON_LICENSE_DIR}/" + license for license in licenses], licenses | ||
131 | else: | ||
132 | return [package_json], None | ||
121 | 133 | ||
122 | fallback = True | 134 | fallback = True |
123 | readmes = [] | ||
124 | basedir = os.path.join(srctree, destdir) | 135 | basedir = os.path.join(srctree, destdir) |
125 | for fn in os.listdir(basedir): | 136 | for fn in os.listdir(basedir): |
126 | upper = fn.upper() | 137 | upper = fn.upper() |
127 | if upper.startswith("README"): | ||
128 | fullpath = os.path.join(basedir, fn) | ||
129 | readmes.append(fullpath) | ||
130 | if upper.startswith("COPYING") or "LICENCE" in upper or "LICENSE" in upper: | 138 | if upper.startswith("COPYING") or "LICENCE" in upper or "LICENSE" in upper: |
131 | fallback = False | 139 | fallback = False |
132 | if fallback: | 140 | if fallback: |
133 | for readme in readmes: | 141 | pkg_json = os.path.join(basedir, "package.json") |
134 | licfiles.append(os.path.relpath(readme, srctree)) | 142 | return _get_licenses_from_package_json(pkg_json) |
143 | return [], None | ||
135 | 144 | ||
136 | # Handle the dependencies | 145 | # Handle the dependencies |
137 | def _handle_dependency(name, params, destdir): | 146 | def _handle_dependency(name, params, destdir): |
138 | deptree = destdir.split('node_modules/') | 147 | deptree = destdir.split('node_modules/') |
139 | suffix = "-".join([npm_package(dep) for dep in deptree]) | 148 | suffix = "-".join([npm_package(dep) for dep in deptree]) |
140 | packages["${PN}" + suffix] = destdir | 149 | packages["${PN}" + suffix] = destdir |
141 | _licfiles_append_fallback_readme_files(destdir) | 150 | (fallback_licfiles, common_lics) = _licfiles_append_fallback_package_files(destdir) |
151 | licfiles.extend(fallback_licfiles) | ||
152 | if common_lics: | ||
153 | fallback_licenses["${PN}" + suffix] = common_lics | ||
142 | 154 | ||
143 | with open(shrinkwrap_file, "r") as f: | 155 | with open(shrinkwrap_file, "r") as f: |
144 | shrinkwrap = json.load(f) | 156 | shrinkwrap = json.load(f) |
145 | 157 | ||
146 | foreach_dependencies(shrinkwrap, _handle_dependency, dev) | 158 | foreach_dependencies(shrinkwrap, _handle_dependency, dev) |
147 | 159 | ||
148 | return licfiles, packages | 160 | return licfiles, packages, fallback_licenses |
149 | 161 | ||
150 | # Handle the peer dependencies | 162 | # Handle the peer dependencies |
151 | def _handle_peer_dependency(self, shrinkwrap_file): | 163 | def _handle_peer_dependency(self, shrinkwrap_file): |
@@ -266,18 +278,31 @@ class NpmRecipeHandler(RecipeHandler): | |||
266 | fetcher.unpack(srctree) | 278 | fetcher.unpack(srctree) |
267 | 279 | ||
268 | bb.note("Handling licences ...") | 280 | bb.note("Handling licences ...") |
269 | (licfiles, packages) = self._handle_licenses(srctree, shrinkwrap_file, dev) | 281 | (licfiles, packages, fallback_licenses) = self._handle_licenses(srctree, shrinkwrap_file, dev) |
270 | 282 | ||
271 | def _guess_odd_license(licfiles): | 283 | def _guess_odd_license(licfiles): |
272 | import bb | 284 | import bb |
273 | 285 | ||
274 | md5sums = get_license_md5sums(d, linenumbers=True) | 286 | md5sums = get_license_md5sums(d, linenumbers=True) |
275 | 287 | ||
288 | def _resolve_licfile(srctree, licfile): | ||
289 | match = re.search(r'\$\{COMMON_LICENSE_DIR\}/(.+)$', licfile) | ||
290 | if match: | ||
291 | license = match.group(1) | ||
292 | commonlicdir = d.getVar('COMMON_LICENSE_DIR') | ||
293 | return os.path.join(commonlicdir, license) | ||
294 | |||
295 | return os.path.join(srctree, licfile) | ||
296 | |||
276 | chksums = [] | 297 | chksums = [] |
277 | licenses = [] | 298 | licenses = [] |
299 | md5value = None | ||
278 | for licfile in licfiles: | 300 | for licfile in licfiles: |
279 | f = os.path.join(srctree, licfile) | 301 | f = _resolve_licfile(srctree, licfile) |
280 | md5value = bb.utils.md5_file(f) | 302 | try: |
303 | md5value = bb.utils.md5_file(f) | ||
304 | except FileNotFoundError: | ||
305 | logger.info("Could not determine license for '%s'" % licfile) | ||
281 | (license, beginline, endline, md5) = md5sums.get(md5value, | 306 | (license, beginline, endline, md5) = md5sums.get(md5value, |
282 | (None, "", "", "")) | 307 | (None, "", "", "")) |
283 | if not license: | 308 | if not license: |
@@ -292,10 +317,10 @@ class NpmRecipeHandler(RecipeHandler): | |||
292 | ";endline=%s" % (endline) if endline else "", | 317 | ";endline=%s" % (endline) if endline else "", |
293 | md5 if md5 else md5value)) | 318 | md5 if md5 else md5value)) |
294 | licenses.append((license, licfile, md5value)) | 319 | licenses.append((license, licfile, md5value)) |
295 | return (licenses, chksums) | 320 | return (licenses, chksums, fallback_licenses) |
296 | 321 | ||
297 | (licenses, extravalues["LIC_FILES_CHKSUM"]) = _guess_odd_license(licfiles) | 322 | (licenses, extravalues["LIC_FILES_CHKSUM"], fallback_licenses) = _guess_odd_license(licfiles) |
298 | split_pkg_licenses([*licenses, *guess_license(srctree, d)], packages, lines_after) | 323 | split_pkg_licenses([*licenses, *guess_license(srctree, d)], packages, lines_after, fallback_licenses) |
299 | 324 | ||
300 | classes.append("npm") | 325 | classes.append("npm") |
301 | handled.append("buildsystem") | 326 | handled.append("buildsystem") |