@@ -7,6 +7,7 @@ const BB = require('bluebird')
7
7
8
8
const {
9
9
linkBin : binLink ,
10
+ extract,
10
11
getPrefix,
11
12
log : npmlog ,
12
13
logicalTree : buildLogicalTree ,
@@ -28,8 +29,8 @@ const rimraf = BB.promisify(require('rimraf'))
28
29
const { spawn } = require ( 'child_process' )
29
30
30
31
const readFileAsync = BB . promisify ( fs . readFile )
32
+ const readdirAsync = BB . promisify ( fs . readdir )
31
33
const realpathAsync = BB . promisify ( fs . realpath )
32
- const statAsync = BB . promisify ( fs . stat )
33
34
const symlinkAsync = BB . promisify ( fs . symlink )
34
35
const writeFileAsync = BB . promisify ( fs . writeFile )
35
36
@@ -73,6 +74,7 @@ class Installer {
73
74
if ( ! this . validLockHash || this . force ) {
74
75
this . log ( 'info' , 'Generating new package map' )
75
76
await this . timedStage ( 'fetchTree' , this . tree )
77
+ await this . timedStage ( 'updateJson' , this . tree )
76
78
await this . timedStage ( 'buildTree' , this . tree )
77
79
await this . tinkifyBins ( )
78
80
await this . timedStage ( 'runScript' , 'prepublish' , this . pkg , this . prefix )
@@ -250,6 +252,28 @@ class Installer {
250
252
warn : msg => this . opts . log ( 'warn' , msg )
251
253
} )
252
254
)
255
+ const pkg = await readJson ( dep . path ( this . prefix ) , 'package.json' )
256
+ if (
257
+ (
258
+ pkg . scripts && (
259
+ pkg . scripts . preinstall ||
260
+ pkg . scripts . install ||
261
+ pkg . scripts . postinstall
262
+ )
263
+ ) || (
264
+ pkg . bundleDependencies ||
265
+ pkg . bundledDependencies
266
+ )
267
+ ) {
268
+ await extract (
269
+ npa . resolve ( dep . name , dep . version ) ,
270
+ dep . path ( this . prefix ) ,
271
+ this . opts . concat ( {
272
+ integrity : dep . integrity ,
273
+ resolved : dep . resolved
274
+ } )
275
+ )
276
+ }
253
277
// cg.completeWork(1)
254
278
this . pkgCount ++
255
279
await next ( )
@@ -274,6 +298,56 @@ class Installer {
274
298
return ( dep . dev && includeDev ) || ( ! dep . dev && includeProd )
275
299
}
276
300
301
+ async updateJson ( tree ) {
302
+ this . log ( 'verbose' , 'updateJson' , 'checking for native builds' )
303
+ const pkgJsons = new Map ( )
304
+ await tree . forEachAsync ( async ( dep , next ) => {
305
+ if ( ! this . checkDepEnv ( dep ) ) { return }
306
+ const depPath = dep . path ( this . prefix )
307
+ await next ( )
308
+ const pkg = await readJson ( depPath , 'package.json' )
309
+ await this . updateInstallScript ( dep , pkg )
310
+ pkgJsons . set ( dep , pkg )
311
+ } , { concurrency : 100 , Promise : BB } )
312
+ this . pkgJsons = pkgJsons
313
+ return pkgJsons
314
+ }
315
+
316
+ async updateInstallScript ( dep , pkg ) {
317
+ const depPath = dep . path ( this . prefix )
318
+ if ( ! pkg . scripts || ! pkg . scripts . install ) {
319
+ const files = await readdirAsync ( depPath )
320
+ if ( files . find ( f => / \. g y p $ / i. test ( f ) ) ) {
321
+ if ( ! pkg . scripts ) {
322
+ pkg . scripts = { }
323
+ }
324
+ pkg . scripts . install = 'node-gyp rebuild'
325
+ }
326
+ }
327
+ let modified
328
+ if ( pkg . scripts ) {
329
+ if ( pkg . scripts . preinstall ) {
330
+ const old = pkg . scripts . preinstall
331
+ pkg . scripts . preinstall = pkg . scripts . preinstall . replace ( 'node' , 'tish' )
332
+ modified = pkg . scripts . preinstall === old
333
+ }
334
+ if ( pkg . scripts . install ) {
335
+ const old = pkg . scripts . install
336
+ pkg . scripts . install = pkg . scripts . install . replace ( 'node' , 'tish' )
337
+ modified = pkg . scripts . install === old
338
+ }
339
+ if ( pkg . scripts . postinstall ) {
340
+ const old = pkg . scripts . postinstall
341
+ pkg . scripts . postinstall = pkg . scripts . postinstall . replace ( 'node' , 'tish' )
342
+ modified = pkg . scripts . postinstall === old
343
+ }
344
+ if ( modified ) {
345
+ await writeFileAsync ( path . join ( depPath , 'package.json' ) , JSON . stringify ( pkg , null , 2 ) )
346
+ }
347
+ }
348
+ return pkg
349
+ }
350
+
277
351
async buildTree ( tree ) {
278
352
this . log ( 'verbose' , 'buildTree' , 'finalizing tree and running scripts' )
279
353
await tree . forEachAsync ( async ( dep , next ) => {
@@ -282,13 +356,13 @@ class Installer {
282
356
const spec = npa . resolve ( dep . name , dep . version )
283
357
const depPath = dep . path ( this . prefix )
284
358
this . log ( 'silly' , 'buildTree' , `linking ${ spec } ` )
285
- const pkg = await readPkgJson ( path . join ( depPath , 'package.json' ) )
359
+ const pkg = this . pkgJsons . get ( dep )
286
360
await this . runScript ( 'preinstall' , pkg , depPath )
287
361
await next ( ) // build children between preinstall and binLink
288
362
// Don't link root bins
289
363
if (
290
364
dep . isRoot ||
291
- ! ( pkg . bin || pkg . man || ( pkg . directories && pkg . directories . bin ) )
365
+ ! ( pkg . bin || pkg . man || ( pkg . directories && pkg . directories . bin ) || ( pkg . scripts && ( pkg . scripts . install || pkg . scripts . postinstall ) ) )
292
366
) {
293
367
// We skip the relatively expensive readPkgJson if there's no way
294
368
// we'll actually be linking any bins or mans
@@ -329,23 +403,6 @@ class Installer {
329
403
} , { concurrency : 50 , Promise : BB } )
330
404
}
331
405
332
- async updateInstallScript ( dep , pkg ) {
333
- const depPath = dep . path ( this . prefix )
334
- let stat
335
- try {
336
- stat = statAsync ( path . join ( depPath , 'binding.gyp' ) )
337
- } catch ( err ) {
338
- if ( err . code !== 'ENOENT' ) { throw err }
339
- }
340
- if ( stat ) {
341
- if ( ! pkg . scripts ) {
342
- pkg . scripts = { }
343
- }
344
- pkg . scripts . install = 'node-gyp rebuild'
345
- }
346
- return pkg
347
- }
348
-
349
406
// A cute little mark-and-sweep collector!
350
407
async garbageCollect ( tree ) {
351
408
if ( ! this . failedDeps . size ) { return }
@@ -365,7 +422,8 @@ class Installer {
365
422
pkg . _id = pkg . name + '@' + pkg . version
366
423
const ret = await runScript ( pkg , stage , pkgPath , {
367
424
dir : this . prefix ,
368
- log : npmlog
425
+ log : npmlog ,
426
+ config : this . opts
369
427
} )
370
428
this . timings . scripts += Date . now ( ) - start
371
429
return ret
0 commit comments