Skip to content

Commit 7a3fe1c

Browse files
win,install: only download target_arch node.lib (#2857)
Instead of downloading node.lib for all architectures, just download the one that will be needed. Install.js changed to enable downloading just node.lib for node versions that already have tarball downloaded and extracted. Not fetching lib now fails the installation. Increased installVersion because of the changes. Refs: #2847
1 parent 55048f8 commit 7a3fe1c

File tree

3 files changed

+95
-78
lines changed

3 files changed

+95
-78
lines changed

lib/install.js

Lines changed: 93 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const streamPipeline = util.promisify(stream.pipeline)
2222

2323
async function install (fs, gyp, argv) {
2424
const release = processRelease(argv, gyp, process.version, process.release)
25+
// Detecting target_arch based on logic from create-cnfig-gyp.js. Used on Windows only.
26+
const arch = win ? (gyp.opts.target_arch || gyp.opts.arch || process.arch || 'ia32') : ''
27+
// Used to prevent downloading tarball if only new node.lib is required on Windows.
28+
let shouldDownloadTarball = true
2529

2630
// Determine which node dev files version we are installing
2731
log.verbose('install', 'input version string %j', release.version)
@@ -92,6 +96,26 @@ async function install (fs, gyp, argv) {
9296
}
9397
}
9498
log.verbose('install', 'version is good')
99+
if (win) {
100+
log.verbose('on Windows; need to check node.lib')
101+
const nodeLibPath = path.resolve(devDir, arch, 'node.lib')
102+
try {
103+
await fs.promises.stat(nodeLibPath)
104+
} catch (err) {
105+
if (err.code === 'ENOENT') {
106+
log.verbose('install', `version not already installed for ${arch}, continuing with install`, release.version)
107+
try {
108+
shouldDownloadTarball = false
109+
return await go()
110+
} catch (err) {
111+
return rollback(err)
112+
}
113+
} else if (err.code === 'EACCES') {
114+
return eaccesFallback(err)
115+
}
116+
throw err
117+
}
118+
}
95119
} else {
96120
try {
97121
return await go()
@@ -179,66 +203,69 @@ async function install (fs, gyp, argv) {
179203
}
180204

181205
// download the tarball and extract!
206+
// Ommited on Windows if only new node.lib is required
182207

183208
// on Windows there can be file errors from tar if parallel installs
184209
// are happening (not uncommon with multiple native modules) so
185210
// extract the tarball to a temp directory first and then copy over
186211
const tarExtractDir = win ? await fs.promises.mkdtemp(path.join(os.tmpdir(), 'node-gyp-tmp-')) : devDir
187212

188213
try {
189-
if (tarPath) {
190-
await tar.extract({
191-
file: tarPath,
192-
strip: 1,
193-
filter: isValid,
194-
onwarn,
195-
cwd: tarExtractDir
196-
})
197-
} else {
198-
try {
199-
const res = await download(gyp, release.tarballUrl)
214+
if (shouldDownloadTarball) {
215+
if (tarPath) {
216+
await tar.extract({
217+
file: tarPath,
218+
strip: 1,
219+
filter: isValid,
220+
onwarn,
221+
cwd: tarExtractDir
222+
})
223+
} else {
224+
try {
225+
const res = await download(gyp, release.tarballUrl)
200226

201-
if (res.status !== 200) {
202-
throw new Error(`${res.status} response downloading ${release.tarballUrl}`)
203-
}
227+
if (res.status !== 200) {
228+
throw new Error(`${res.status} response downloading ${release.tarballUrl}`)
229+
}
204230

205-
await streamPipeline(
206-
res.body,
207-
// content checksum
208-
new ShaSum((_, checksum) => {
209-
const filename = path.basename(release.tarballUrl).trim()
210-
contentShasums[filename] = checksum
211-
log.verbose('content checksum', filename, checksum)
212-
}),
213-
tar.extract({
214-
strip: 1,
215-
cwd: tarExtractDir,
216-
filter: isValid,
217-
onwarn
218-
})
219-
)
220-
} catch (err) {
231+
await streamPipeline(
232+
res.body,
233+
// content checksum
234+
new ShaSum((_, checksum) => {
235+
const filename = path.basename(release.tarballUrl).trim()
236+
contentShasums[filename] = checksum
237+
log.verbose('content checksum', filename, checksum)
238+
}),
239+
tar.extract({
240+
strip: 1,
241+
cwd: tarExtractDir,
242+
filter: isValid,
243+
onwarn
244+
})
245+
)
246+
} catch (err) {
221247
// something went wrong downloading the tarball?
222-
if (err.code === 'ENOTFOUND') {
223-
throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' +
248+
if (err.code === 'ENOTFOUND') {
249+
throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' +
224250
'is related to network connectivity. In most cases you are behind a proxy or have bad \n' +
225251
'network settings.')
252+
}
253+
throw err
226254
}
227-
throw err
228255
}
229-
}
230256

231-
// invoked after the tarball has finished being extracted
232-
if (extractErrors || extractCount === 0) {
233-
throw new Error('There was a fatal problem while downloading/extracting the tarball')
234-
}
257+
// invoked after the tarball has finished being extracted
258+
if (extractErrors || extractCount === 0) {
259+
throw new Error('There was a fatal problem while downloading/extracting the tarball')
260+
}
235261

236-
log.verbose('tarball', 'done parsing tarball')
262+
log.verbose('tarball', 'done parsing tarball')
263+
}
237264

238265
const installVersionPath = path.resolve(tarExtractDir, 'installVersion')
239266
await Promise.all([
240-
// need to download node.lib
241-
...(win ? downloadNodeLib() : []),
267+
// need to download node.lib
268+
...(win ? [downloadNodeLib()] : []),
242269
// write the "installVersion" file
243270
fs.promises.writeFile(installVersionPath, gyp.package.installVersion + '\n'),
244271
// Only download SHASUMS.txt if we downloaded something in need of SHA verification
@@ -293,43 +320,33 @@ async function install (fs, gyp, argv) {
293320
log.verbose('checksum data', JSON.stringify(expectShasums))
294321
}
295322

296-
function downloadNodeLib () {
323+
async function downloadNodeLib () {
297324
log.verbose('on Windows; need to download `' + release.name + '.lib`...')
298-
const archs = ['ia32', 'x64', 'arm64']
299-
return archs.map(async (arch) => {
300-
const dir = path.resolve(tarExtractDir, arch)
301-
const targetLibPath = path.resolve(dir, release.name + '.lib')
302-
const { libUrl, libPath } = release[arch]
303-
const name = `${arch} ${release.name}.lib`
304-
log.verbose(name, 'dir', dir)
305-
log.verbose(name, 'url', libUrl)
306-
307-
await fs.promises.mkdir(dir, { recursive: true })
308-
log.verbose('streaming', name, 'to:', targetLibPath)
309-
310-
const res = await download(gyp, libUrl)
311-
312-
if (res.status === 403 || res.status === 404) {
313-
if (arch === 'arm64') {
314-
// Arm64 is a newer platform on Windows and not all node distributions provide it.
315-
log.verbose(`${name} was not found in ${libUrl}`)
316-
} else {
317-
log.warn(`${name} was not found in ${libUrl}`)
318-
}
319-
return
320-
} else if (res.status !== 200) {
321-
throw new Error(`${res.status} status code downloading ${name}`)
322-
}
325+
const dir = path.resolve(tarExtractDir, arch)
326+
const targetLibPath = path.resolve(dir, release.name + '.lib')
327+
const { libUrl, libPath } = release[arch]
328+
const name = `${arch} ${release.name}.lib`
329+
log.verbose(name, 'dir', dir)
330+
log.verbose(name, 'url', libUrl)
331+
332+
await fs.promises.mkdir(dir, { recursive: true })
333+
log.verbose('streaming', name, 'to:', targetLibPath)
334+
335+
const res = await download(gyp, libUrl)
336+
337+
// Since only required node.lib is downloaded throw error if it is not fetched
338+
if (res.status !== 200) {
339+
throw new Error(`${res.status} status code downloading ${name}`)
340+
}
323341

324-
return streamPipeline(
325-
res.body,
326-
new ShaSum((_, checksum) => {
327-
contentShasums[libPath] = checksum
328-
log.verbose('content checksum', libPath, checksum)
329-
}),
330-
fs.createWriteStream(targetLibPath)
331-
)
332-
})
342+
return streamPipeline(
343+
res.body,
344+
new ShaSum((_, checksum) => {
345+
contentShasums[libPath] = checksum
346+
log.verbose('content checksum', libPath, checksum)
347+
}),
348+
fs.createWriteStream(targetLibPath)
349+
)
333350
} // downloadNodeLib()
334351
} // go()
335352

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"gyp"
1313
],
1414
"version": "9.3.1",
15-
"installVersion": 10,
15+
"installVersion": 11,
1616
"author": "Nathan Rajlich <[email protected]> (http://tootallnate.net)",
1717
"repository": {
1818
"type": "git",

test/test-download.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ describe('download', function () {
180180
await util.promisify(install)(prog, [])
181181

182182
const data = await fs.promises.readFile(path.join(expectedDir, 'installVersion'), 'utf8')
183-
assert.strictEqual(data, '10\n', 'correct installVersion')
183+
assert.strictEqual(data, '11\n', 'correct installVersion')
184184

185185
const list = await fs.promises.readdir(path.join(expectedDir, 'include/node'))
186186
assert.ok(list.includes('common.gypi'))

0 commit comments

Comments
 (0)