@@ -22,6 +22,10 @@ const streamPipeline = util.promisify(stream.pipeline)
2222
2323async 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
0 commit comments