summaryrefslogtreecommitdiffstats
path: root/scripts/lib/recipetool/create_npm.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/recipetool/create_npm.py')
-rw-r--r--scripts/lib/recipetool/create_npm.py139
1 files changed, 70 insertions, 69 deletions
diff --git a/scripts/lib/recipetool/create_npm.py b/scripts/lib/recipetool/create_npm.py
index 3394a89970..8c4cdd5234 100644
--- a/scripts/lib/recipetool/create_npm.py
+++ b/scripts/lib/recipetool/create_npm.py
@@ -13,10 +13,11 @@ import sys
13import tempfile 13import tempfile
14import bb 14import bb
15from bb.fetch2.npm import NpmEnvironment 15from bb.fetch2.npm import NpmEnvironment
16from bb.fetch2.npm import npm_package
16from bb.fetch2.npmsw import foreach_dependencies 17from bb.fetch2.npmsw import foreach_dependencies
18from oe.license_finder import match_licenses, find_license_files
17from recipetool.create import RecipeHandler 19from recipetool.create import RecipeHandler
18from recipetool.create import get_license_md5sums 20from recipetool.create import generate_common_licenses_chksums
19from recipetool.create import guess_license
20from recipetool.create import split_pkg_licenses 21from recipetool.create import split_pkg_licenses
21logger = logging.getLogger('recipetool') 22logger = logging.getLogger('recipetool')
22 23
@@ -31,15 +32,6 @@ class NpmRecipeHandler(RecipeHandler):
31 """Class to handle the npm recipe creation""" 32 """Class to handle the npm recipe creation"""
32 33
33 @staticmethod 34 @staticmethod
34 def _npm_name(name):
35 """Generate a Yocto friendly npm name"""
36 name = re.sub("/", "-", name)
37 name = name.lower()
38 name = re.sub(r"[^\-a-z0-9]", "", name)
39 name = name.strip("-")
40 return name
41
42 @staticmethod
43 def _get_registry(lines): 35 def _get_registry(lines):
44 """Get the registry value from the 'npm://registry' url""" 36 """Get the registry value from the 'npm://registry' url"""
45 registry = None 37 registry = None
@@ -120,41 +112,71 @@ class NpmRecipeHandler(RecipeHandler):
120 """Return the extra license files and the list of packages""" 112 """Return the extra license files and the list of packages"""
121 licfiles = [] 113 licfiles = []
122 packages = {} 114 packages = {}
115 # Licenses from package.json will point to COMMON_LICENSE_DIR so we need
116 # to associate them explicitely to packages for split_pkg_licenses()
117 fallback_licenses = dict()
118
119 def _find_package_licenses(destdir):
120 """Either find license files, or use package.json metadata"""
121 def _get_licenses_from_package_json(package_json):
122 with open(os.path.join(srctree, package_json), "r") as f:
123 data = json.load(f)
124 if "license" in data:
125 licenses = data["license"].split(" ")
126 licenses = [license.strip("()") for license in licenses if license != "OR" and license != "AND"]
127 return [], licenses
128 else:
129 return [package_json], None
123 130
124 # Handle the parent package
125 packages["${PN}"] = ""
126
127 def _licfiles_append_fallback_readme_files(destdir):
128 """Append README files as fallback to license files if a license files is missing"""
129
130 fallback = True
131 readmes = []
132 basedir = os.path.join(srctree, destdir) 131 basedir = os.path.join(srctree, destdir)
133 for fn in os.listdir(basedir): 132 licfiles = find_license_files(basedir)
134 upper = fn.upper() 133 if len(licfiles) > 0:
135 if upper.startswith("README"): 134 return licfiles, None
136 fullpath = os.path.join(basedir, fn) 135 else:
137 readmes.append(fullpath) 136 # A license wasn't found in the package directory, so we'll use the package.json metadata
138 if upper.startswith("COPYING") or "LICENCE" in upper or "LICENSE" in upper: 137 pkg_json = os.path.join(basedir, "package.json")
139 fallback = False 138 return _get_licenses_from_package_json(pkg_json)
140 if fallback: 139
141 for readme in readmes: 140 def _get_package_licenses(destdir, package):
142 licfiles.append(os.path.relpath(readme, srctree)) 141 (package_licfiles, package_licenses) = _find_package_licenses(destdir)
142 if package_licfiles:
143 licfiles.extend(package_licfiles)
144 else:
145 fallback_licenses[package] = package_licenses
143 146
144 # Handle the dependencies 147 # Handle the dependencies
145 def _handle_dependency(name, params, deptree): 148 def _handle_dependency(name, params, destdir):
146 suffix = "-".join([self._npm_name(dep) for dep in deptree]) 149 deptree = destdir.split('node_modules/')
147 destdirs = [os.path.join("node_modules", dep) for dep in deptree] 150 suffix = "-".join([npm_package(dep) for dep in deptree])
148 destdir = os.path.join(*destdirs) 151 packages["${PN}" + suffix] = destdir
149 packages["${PN}-" + suffix] = destdir 152 _get_package_licenses(destdir, "${PN}" + suffix)
150 _licfiles_append_fallback_readme_files(destdir)
151 153
152 with open(shrinkwrap_file, "r") as f: 154 with open(shrinkwrap_file, "r") as f:
153 shrinkwrap = json.load(f) 155 shrinkwrap = json.load(f)
154
155 foreach_dependencies(shrinkwrap, _handle_dependency, dev) 156 foreach_dependencies(shrinkwrap, _handle_dependency, dev)
156 157
157 return licfiles, packages 158 # Handle the parent package
159 packages["${PN}"] = ""
160 _get_package_licenses(srctree, "${PN}")
161
162 return licfiles, packages, fallback_licenses
163
164 # Handle the peer dependencies
165 def _handle_peer_dependency(self, shrinkwrap_file):
166 """Check if package has peer dependencies and show warning if it is the case"""
167 with open(shrinkwrap_file, "r") as f:
168 shrinkwrap = json.load(f)
169
170 packages = shrinkwrap.get("packages", {})
171 peer_deps = packages.get("", {}).get("peerDependencies", {})
172
173 for peer_dep in peer_deps:
174 peer_dep_yocto_name = npm_package(peer_dep)
175 bb.warn(peer_dep + " is a peer dependencie of the actual package. " +
176 "Please add this peer dependencie to the RDEPENDS variable as %s and generate its recipe with devtool"
177 % peer_dep_yocto_name)
178
179
158 180
159 def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): 181 def process(self, srctree, classes, lines_before, lines_after, handled, extravalues):
160 """Handle the npm recipe creation""" 182 """Handle the npm recipe creation"""
@@ -173,7 +195,7 @@ class NpmRecipeHandler(RecipeHandler):
173 if "name" not in data or "version" not in data: 195 if "name" not in data or "version" not in data:
174 return False 196 return False
175 197
176 extravalues["PN"] = self._npm_name(data["name"]) 198 extravalues["PN"] = npm_package(data["name"])
177 extravalues["PV"] = data["version"] 199 extravalues["PV"] = data["version"]
178 200
179 if "description" in data: 201 if "description" in data:
@@ -242,7 +264,7 @@ class NpmRecipeHandler(RecipeHandler):
242 value = origvalue.replace("version=" + data["version"], "version=${PV}") 264 value = origvalue.replace("version=" + data["version"], "version=${PV}")
243 value = value.replace("version=latest", "version=${PV}") 265 value = value.replace("version=latest", "version=${PV}")
244 values = [line.strip() for line in value.strip('\n').splitlines()] 266 values = [line.strip() for line in value.strip('\n').splitlines()]
245 if "dependencies" in shrinkwrap: 267 if "dependencies" in shrinkwrap.get("packages", {}).get("", {}):
246 values.append(url_recipe) 268 values.append(url_recipe)
247 return values, None, 4, False 269 return values, None, 4, False
248 270
@@ -258,40 +280,19 @@ class NpmRecipeHandler(RecipeHandler):
258 fetcher.unpack(srctree) 280 fetcher.unpack(srctree)
259 281
260 bb.note("Handling licences ...") 282 bb.note("Handling licences ...")
261 (licfiles, packages) = self._handle_licenses(srctree, shrinkwrap_file, dev) 283 (licfiles, packages, fallback_licenses) = self._handle_licenses(srctree, shrinkwrap_file, dev)
262 284 licvalues = match_licenses(licfiles, srctree, d)
263 def _guess_odd_license(licfiles): 285 split_pkg_licenses(licvalues, packages, lines_after, fallback_licenses)
264 import bb 286 fallback_licenses_flat = [license for sublist in fallback_licenses.values() for license in sublist]
265 287 extravalues["LIC_FILES_CHKSUM"] = generate_common_licenses_chksums(fallback_licenses_flat, d)
266 md5sums = get_license_md5sums(d, linenumbers=True) 288 extravalues["LICENSE"] = fallback_licenses_flat
267
268 chksums = []
269 licenses = []
270 for licfile in licfiles:
271 f = os.path.join(srctree, licfile)
272 md5value = bb.utils.md5_file(f)
273 (license, beginline, endline, md5) = md5sums.get(md5value,
274 (None, "", "", ""))
275 if not license:
276 license = "Unknown"
277 logger.info("Please add the following line for '%s' to a "
278 "'lib/recipetool/licenses.csv' and replace `Unknown`, "
279 "`X`, `Y` and `MD5` with the license, begin line, "
280 "end line and partial MD5 checksum:\n" \
281 "%s,Unknown,X,Y,MD5" % (licfile, md5value))
282 chksums.append("file://%s%s%s;md5=%s" % (licfile,
283 ";beginline=%s" % (beginline) if beginline else "",
284 ";endline=%s" % (endline) if endline else "",
285 md5 if md5 else md5value))
286 licenses.append((license, licfile, md5value))
287 return (licenses, chksums)
288
289 (licenses, extravalues["LIC_FILES_CHKSUM"]) = _guess_odd_license(licfiles)
290 split_pkg_licenses([*licenses, *guess_license(srctree, d)], packages, lines_after)
291 289
292 classes.append("npm") 290 classes.append("npm")
293 handled.append("buildsystem") 291 handled.append("buildsystem")
294 292
293 # Check if package has peer dependencies and inform the user
294 self._handle_peer_dependency(shrinkwrap_file)
295
295 return True 296 return True
296 297
297def register_recipe_handlers(handlers): 298def register_recipe_handlers(handlers):