summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/fetch2/npm.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/fetch2/npm.py')
-rw-r--r--bitbake/lib/bb/fetch2/npm.py63
1 files changed, 41 insertions, 22 deletions
diff --git a/bitbake/lib/bb/fetch2/npm.py b/bitbake/lib/bb/fetch2/npm.py
index 47898509ff..15f3f19bc8 100644
--- a/bitbake/lib/bb/fetch2/npm.py
+++ b/bitbake/lib/bb/fetch2/npm.py
@@ -44,17 +44,24 @@ def npm_package(package):
44 """Convert the npm package name to remove unsupported character""" 44 """Convert the npm package name to remove unsupported character"""
45 # Scoped package names (with the @) use the same naming convention 45 # Scoped package names (with the @) use the same naming convention
46 # as the 'npm pack' command. 46 # as the 'npm pack' command.
47 if package.startswith("@"): 47 name = re.sub("/", "-", package)
48 return re.sub("/", "-", package[1:]) 48 name = name.lower()
49 return package 49 name = re.sub(r"[^\-a-z0-9]", "", name)
50 name = name.strip("-")
51 return name
52
50 53
51def npm_filename(package, version): 54def npm_filename(package, version):
52 """Get the filename of a npm package""" 55 """Get the filename of a npm package"""
53 return npm_package(package) + "-" + version + ".tgz" 56 return npm_package(package) + "-" + version + ".tgz"
54 57
55def npm_localfile(package, version): 58def npm_localfile(package, version=None):
56 """Get the local filename of a npm package""" 59 """Get the local filename of a npm package"""
57 return os.path.join("npm2", npm_filename(package, version)) 60 if version is not None:
61 filename = npm_filename(package, version)
62 else:
63 filename = package
64 return os.path.join("npm2", filename)
58 65
59def npm_integrity(integrity): 66def npm_integrity(integrity):
60 """ 67 """
@@ -69,41 +76,52 @@ def npm_unpack(tarball, destdir, d):
69 bb.utils.mkdirhier(destdir) 76 bb.utils.mkdirhier(destdir)
70 cmd = "tar --extract --gzip --file=%s" % shlex.quote(tarball) 77 cmd = "tar --extract --gzip --file=%s" % shlex.quote(tarball)
71 cmd += " --no-same-owner" 78 cmd += " --no-same-owner"
79 cmd += " --delay-directory-restore"
72 cmd += " --strip-components=1" 80 cmd += " --strip-components=1"
73 runfetchcmd(cmd, d, workdir=destdir) 81 runfetchcmd(cmd, d, workdir=destdir)
82 runfetchcmd("chmod -R +X '%s'" % (destdir), d, quiet=True, workdir=destdir)
74 83
75class NpmEnvironment(object): 84class NpmEnvironment(object):
76 """ 85 """
77 Using a npm config file seems more reliable than using cli arguments. 86 Using a npm config file seems more reliable than using cli arguments.
78 This class allows to create a controlled environment for npm commands. 87 This class allows to create a controlled environment for npm commands.
79 """ 88 """
80 def __init__(self, d, configs=None): 89 def __init__(self, d, configs=[], npmrc=None):
81 self.d = d 90 self.d = d
82 self.configs = configs 91
92 self.user_config = tempfile.NamedTemporaryFile(mode="w", buffering=1)
93 for key, value in configs:
94 self.user_config.write("%s=%s\n" % (key, value))
95
96 if npmrc:
97 self.global_config_name = npmrc
98 else:
99 self.global_config_name = "/dev/null"
100
101 def __del__(self):
102 if self.user_config:
103 self.user_config.close()
83 104
84 def run(self, cmd, args=None, configs=None, workdir=None): 105 def run(self, cmd, args=None, configs=None, workdir=None):
85 """Run npm command in a controlled environment""" 106 """Run npm command in a controlled environment"""
86 with tempfile.TemporaryDirectory() as tmpdir: 107 with tempfile.TemporaryDirectory() as tmpdir:
87 d = bb.data.createCopy(self.d) 108 d = bb.data.createCopy(self.d)
109 d.setVar("PATH", d.getVar("PATH")) # PATH might contain $HOME - evaluate it before patching
88 d.setVar("HOME", tmpdir) 110 d.setVar("HOME", tmpdir)
89 111
90 cfgfile = os.path.join(tmpdir, "npmrc")
91
92 if not workdir: 112 if not workdir:
93 workdir = tmpdir 113 workdir = tmpdir
94 114
95 def _run(cmd): 115 def _run(cmd):
96 cmd = "NPM_CONFIG_USERCONFIG=%s " % cfgfile + cmd 116 cmd = "NPM_CONFIG_USERCONFIG=%s " % (self.user_config.name) + cmd
97 cmd = "NPM_CONFIG_GLOBALCONFIG=%s " % cfgfile + cmd 117 cmd = "NPM_CONFIG_GLOBALCONFIG=%s " % (self.global_config_name) + cmd
98 return runfetchcmd(cmd, d, workdir=workdir) 118 return runfetchcmd(cmd, d, workdir=workdir)
99 119
100 if self.configs:
101 for key, value in self.configs:
102 _run("npm config set %s %s" % (key, shlex.quote(value)))
103
104 if configs: 120 if configs:
121 bb.warn("Use of configs argument of NpmEnvironment.run() function"
122 " is deprecated. Please use args argument instead.")
105 for key, value in configs: 123 for key, value in configs:
106 _run("npm config set %s %s" % (key, shlex.quote(value))) 124 cmd += " --%s=%s" % (key, shlex.quote(value))
107 125
108 if args: 126 if args:
109 for key, value in args: 127 for key, value in args:
@@ -142,12 +160,12 @@ class Npm(FetchMethod):
142 raise ParameterError("Invalid 'version' parameter", ud.url) 160 raise ParameterError("Invalid 'version' parameter", ud.url)
143 161
144 # Extract the 'registry' part of the url 162 # Extract the 'registry' part of the url
145 ud.registry = re.sub(r"^npm://", "http://", ud.url.split(";")[0]) 163 ud.registry = re.sub(r"^npm://", "https://", ud.url.split(";")[0])
146 164
147 # Using the 'downloadfilename' parameter as local filename 165 # Using the 'downloadfilename' parameter as local filename
148 # or the npm package name. 166 # or the npm package name.
149 if "downloadfilename" in ud.parm: 167 if "downloadfilename" in ud.parm:
150 ud.localfile = d.expand(ud.parm["downloadfilename"]) 168 ud.localfile = npm_localfile(d.expand(ud.parm["downloadfilename"]))
151 else: 169 else:
152 ud.localfile = npm_localfile(ud.package, ud.version) 170 ud.localfile = npm_localfile(ud.package, ud.version)
153 171
@@ -165,14 +183,14 @@ class Npm(FetchMethod):
165 183
166 def _resolve_proxy_url(self, ud, d): 184 def _resolve_proxy_url(self, ud, d):
167 def _npm_view(): 185 def _npm_view():
168 configs = [] 186 args = []
169 configs.append(("json", "true")) 187 args.append(("json", "true"))
170 configs.append(("registry", ud.registry)) 188 args.append(("registry", ud.registry))
171 pkgver = shlex.quote(ud.package + "@" + ud.version) 189 pkgver = shlex.quote(ud.package + "@" + ud.version)
172 cmd = ud.basecmd + " view %s" % pkgver 190 cmd = ud.basecmd + " view %s" % pkgver
173 env = NpmEnvironment(d) 191 env = NpmEnvironment(d)
174 check_network_access(d, cmd, ud.registry) 192 check_network_access(d, cmd, ud.registry)
175 view_string = env.run(cmd, configs=configs) 193 view_string = env.run(cmd, args=args)
176 194
177 if not view_string: 195 if not view_string:
178 raise FetchError("Unavailable package %s" % pkgver, ud.url) 196 raise FetchError("Unavailable package %s" % pkgver, ud.url)
@@ -280,6 +298,7 @@ class Npm(FetchMethod):
280 destsuffix = ud.parm.get("destsuffix", "npm") 298 destsuffix = ud.parm.get("destsuffix", "npm")
281 destdir = os.path.join(rootdir, destsuffix) 299 destdir = os.path.join(rootdir, destsuffix)
282 npm_unpack(ud.localpath, destdir, d) 300 npm_unpack(ud.localpath, destdir, d)
301 ud.unpack_tracer.unpack("npm", destdir)
283 302
284 def clean(self, ud, d): 303 def clean(self, ud, d):
285 """Clean any existing full or partial download""" 304 """Clean any existing full or partial download"""