@@ -4,60 +4,42 @@ const fs = require('graceful-fs')
44const os = require ( 'os' )
55const tar = require ( 'tar' )
66const path = require ( 'path' )
7+ const util = require ( 'util' )
78const stream = require ( 'stream' )
89const crypto = require ( 'crypto' )
910const log = require ( 'npmlog' )
1011const semver = require ( 'semver' )
1112const fetch = require ( 'make-fetch-happen' )
1213const processRelease = require ( './process-release' )
1314const win = process . platform === 'win32'
14- const streamPipeline = require ( ' util' ) . promisify ( stream . pipeline )
15+ const streamPipeline = util . promisify ( stream . pipeline )
1516
1617/**
1718 * @param {typeof import('graceful-fs') } fs
1819 */
1920
20- function install ( fs , gyp , argv , callback ) {
21+ async function install ( fs , gyp , argv ) {
2122 const release = processRelease ( argv , gyp , process . version , process . release )
2223
23- // ensure no double-callbacks happen
24- function cb ( err ) {
25- if ( cb . done ) {
26- return
27- }
28- cb . done = true
29- if ( err ) {
30- log . warn ( 'install' , 'got an error, rolling back install' )
31- // roll-back the install if anything went wrong
32- gyp . commands . remove ( [ release . versionDir ] , function ( ) {
33- callback ( err )
34- } )
35- } else {
36- callback ( null , release . version )
37- }
38- }
39-
4024 // Determine which node dev files version we are installing
4125 log . verbose ( 'install' , 'input version string %j' , release . version )
4226
4327 if ( ! release . semver ) {
4428 // could not parse the version string with semver
45- return callback ( new Error ( 'Invalid version number: ' + release . version ) )
29+ throw new Error ( 'Invalid version number: ' + release . version )
4630 }
4731
4832 if ( semver . lt ( release . version , '0.8.0' ) ) {
49- return callback ( new Error ( 'Minimum target version is `0.8.0` or greater. Got: ' + release . version ) )
33+ throw new Error ( 'Minimum target version is `0.8.0` or greater. Got: ' + release . version )
5034 }
5135
5236 // 0.x.y-pre versions are not published yet and cannot be installed. Bail.
5337 if ( release . semver . prerelease [ 0 ] === 'pre' ) {
5438 log . verbose ( 'detected "pre" node version' , release . version )
55- if ( gyp . opts . nodedir ) {
56- log . verbose ( '--nodedir flag was passed; skipping install' , gyp . opts . nodedir )
57- callback ( )
58- } else {
59- callback ( new Error ( '"pre" versions of node cannot be installed, use the --nodedir flag instead' ) )
39+ if ( ! gyp . opts . nodedir ) {
40+ throw new Error ( '"pre" versions of node cannot be installed, use the --nodedir flag instead' )
6041 }
42+ log . verbose ( '--nodedir flag was passed; skipping install' , gyp . opts . nodedir )
6143 return
6244 }
6345
@@ -71,55 +53,48 @@ function install (fs, gyp, argv, callback) {
7153 // check if it is already installed, and only install when needed
7254 if ( gyp . opts . ensure ) {
7355 log . verbose ( 'install' , '--ensure was passed, so won\'t reinstall if already installed' )
74- fs . stat ( devDir , function ( err ) {
75- if ( err ) {
76- if ( err . code === 'ENOENT' ) {
77- log . verbose ( 'install' , 'version not already installed, continuing with install' , release . version )
78- go ( ) . then ( cb , cb )
79- } else if ( err . code === 'EACCES' ) {
80- eaccesFallback ( err )
81- } else {
82- cb ( err )
56+ try {
57+ await fs . promises . stat ( devDir )
58+ } catch ( err ) {
59+ if ( err . code === 'ENOENT' ) {
60+ log . verbose ( 'install' , 'version not already installed, continuing with install' , release . version )
61+ try {
62+ return await go ( )
63+ } catch ( err ) {
64+ return rollback ( err )
8365 }
84- return
66+ } else if ( err . code === 'EACCES' ) {
67+ return eaccesFallback ( err )
8568 }
86- log . verbose ( 'install' , 'version is already installed, need to check "installVersion"' )
87- const installVersionFile = path . resolve ( devDir , 'installVersion' )
88- fs . readFile ( installVersionFile , 'ascii' , ( err , ver ) => {
89- if ( err && err . code !== 'ENOENT' ) {
90- return cb ( err )
91- }
92- const installVersion = parseInt ( ver , 10 ) || 0
93- log . verbose ( 'got "installVersion"' , installVersion )
94- log . verbose ( 'needs "installVersion"' , gyp . package . installVersion )
95- if ( installVersion < gyp . package . installVersion ) {
96- log . verbose ( 'install' , 'version is no good; reinstalling' )
97- go ( ) . then ( cb , cb )
98- } else {
99- log . verbose ( 'install' , 'version is good' )
100- cb ( )
101- }
102- } )
103- } )
104- } else {
105- go ( ) . then ( cb , cb )
106- }
107-
108- class ShaSum extends stream . Transform {
109- constructor ( callback ) {
110- super ( )
111- this . _callback = callback
112- this . _digester = crypto . createHash ( 'sha256' )
69+ throw err
11370 }
114-
115- _transform ( chunk , _ , callback ) {
116- this . _digester . update ( chunk )
117- callback ( null , chunk )
71+ log . verbose ( 'install' , 'version is already installed, need to check "installVersion"' )
72+ const installVersionFile = path . resolve ( devDir , 'installVersion' )
73+ let installVersion = 0
74+ try {
75+ const ver = await fs . promises . readFile ( installVersionFile , 'ascii' )
76+ installVersion = parseInt ( ver , 10 ) || 0
77+ } catch ( err ) {
78+ if ( err . code !== 'ENOENT' ) {
79+ throw err
80+ }
11881 }
119-
120- _flush ( callback ) {
121- this . _callback ( null , this . _digester . digest ( 'hex' ) )
122- callback ( )
82+ log . verbose ( 'got "installVersion"' , installVersion )
83+ log . verbose ( 'needs "installVersion"' , gyp . package . installVersion )
84+ if ( installVersion < gyp . package . installVersion ) {
85+ log . verbose ( 'install' , 'version is no good; reinstalling' )
86+ try {
87+ return await go ( )
88+ } catch ( err ) {
89+ return rollback ( err )
90+ }
91+ }
92+ log . verbose ( 'install' , 'version is good' )
93+ } else {
94+ try {
95+ return await go ( )
96+ } catch ( err ) {
97+ return rollback ( err )
12398 }
12499 }
125100
@@ -135,8 +110,7 @@ function install (fs, gyp, argv, callback) {
135110 }
136111 } catch ( err ) {
137112 if ( err . code === 'EACCES' ) {
138- eaccesFallback ( err )
139- return
113+ return eaccesFallback ( err )
140114 }
141115
142116 throw err
@@ -173,7 +147,7 @@ function install (fs, gyp, argv, callback) {
173147 } )
174148 } else {
175149 try {
176- const res = await download ( gyp , process . env , release . tarballUrl )
150+ const res = await download ( gyp , release . tarballUrl )
177151
178152 if ( res . status !== 200 ) {
179153 throw new Error ( `${ res . status } response downloading ${ release . tarballUrl } ` )
@@ -234,7 +208,7 @@ function install (fs, gyp, argv, callback) {
234208 log . verbose ( 'check download content checksum, need to download `SHASUMS256.txt`...' )
235209 log . verbose ( 'checksum url' , release . shasumsUrl )
236210
237- const res = await download ( gyp , process . env , release . shasumsUrl )
211+ const res = await download ( gyp , release . shasumsUrl )
238212
239213 if ( res . status !== 200 ) {
240214 throw new Error ( `${ res . status } status code downloading checksum` )
@@ -268,7 +242,7 @@ function install (fs, gyp, argv, callback) {
268242 await fs . promises . mkdir ( dir , { recursive : true } )
269243 log . verbose ( 'streaming' , name , 'to:' , targetLibPath )
270244
271- const res = await download ( gyp , process . env , libUrl )
245+ const res = await download ( gyp , libUrl )
272246
273247 if ( res . status === 403 || res . status === 404 ) {
274248 if ( arch === 'arm64' ) {
@@ -304,6 +278,13 @@ function install (fs, gyp, argv, callback) {
304278 return extname === '.h' || extname === '.gypi'
305279 }
306280
281+ async function rollback ( err ) {
282+ log . warn ( 'install' , 'got an error, rolling back install' )
283+ // roll-back the install if anything went wrong
284+ await util . promisify ( gyp . commands . remove ) ( [ release . versionDir ] )
285+ throw err
286+ }
287+
307288 /**
308289 * The EACCES fallback is a workaround for npm's `sudo` behavior, where
309290 * it drops the permissions before invoking any child processes (like
@@ -313,10 +294,10 @@ function install (fs, gyp, argv, callback) {
313294 * the compilation will succeed...
314295 */
315296
316- function eaccesFallback ( err ) {
297+ async function eaccesFallback ( err ) {
317298 const noretry = '--node_gyp_internal_noretry'
318299 if ( argv . indexOf ( noretry ) !== - 1 ) {
319- return cb ( err )
300+ throw err
320301 }
321302 const tmpdir = os . tmpdir ( )
322303 gyp . devDir = path . resolve ( tmpdir , '.node-gyp' )
@@ -331,11 +312,29 @@ function install (fs, gyp, argv, callback) {
331312 log . verbose ( 'tmpdir == cwd' , 'automatically will remove dev files after to save disk space' )
332313 gyp . todo . push ( { name : 'remove' , args : argv } )
333314 }
334- gyp . commands . install ( [ noretry ] . concat ( argv ) , cb )
315+ return util . promisify ( gyp . commands . install ) ( [ noretry ] . concat ( argv ) )
316+ }
317+ }
318+
319+ class ShaSum extends stream . Transform {
320+ constructor ( callback ) {
321+ super ( )
322+ this . _callback = callback
323+ this . _digester = crypto . createHash ( 'sha256' )
324+ }
325+
326+ _transform ( chunk , _ , callback ) {
327+ this . _digester . update ( chunk )
328+ callback ( null , chunk )
329+ }
330+
331+ _flush ( callback ) {
332+ this . _callback ( null , this . _digester . digest ( 'hex' ) )
333+ callback ( )
335334 }
336335}
337336
338- async function download ( gyp , env , url ) {
337+ async function download ( gyp , url ) {
339338 log . http ( 'GET' , url )
340339
341340 const requestOpts = {
@@ -367,11 +366,11 @@ async function readCAFile (filename) {
367366}
368367
369368module . exports = function ( gyp , argv , callback ) {
370- return install ( fs , gyp , argv , callback )
369+ install ( fs , gyp , argv ) . then ( callback , callback )
371370}
372371module . exports . test = {
373- download : download ,
374- install : install ,
375- readCAFile : readCAFile
372+ download,
373+ install,
374+ readCAFile
376375}
377376module . exports . usage = 'Install node development files for the specified node version.'
0 commit comments