@@ -7,6 +7,7 @@ const BB = require('bluebird')
77
88const {
99 linkBin : binLink ,
10+ extract,
1011 getPrefix,
1112 log : npmlog ,
1213 logicalTree : buildLogicalTree ,
@@ -28,8 +29,8 @@ const rimraf = BB.promisify(require('rimraf'))
2829const { spawn } = require ( 'child_process' )
2930
3031const readFileAsync = BB . promisify ( fs . readFile )
32+ const readdirAsync = BB . promisify ( fs . readdir )
3133const realpathAsync = BB . promisify ( fs . realpath )
32- const statAsync = BB . promisify ( fs . stat )
3334const symlinkAsync = BB . promisify ( fs . symlink )
3435const writeFileAsync = BB . promisify ( fs . writeFile )
3536
@@ -73,6 +74,7 @@ class Installer {
7374 if ( ! this . validLockHash || this . force ) {
7475 this . log ( 'info' , 'Generating new package map' )
7576 await this . timedStage ( 'fetchTree' , this . tree )
77+ await this . timedStage ( 'updateJson' , this . tree )
7678 await this . timedStage ( 'buildTree' , this . tree )
7779 await this . tinkifyBins ( )
7880 await this . timedStage ( 'runScript' , 'prepublish' , this . pkg , this . prefix )
@@ -250,6 +252,28 @@ class Installer {
250252 warn : msg => this . opts . log ( 'warn' , msg )
251253 } )
252254 )
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+ }
253277 // cg.completeWork(1)
254278 this . pkgCount ++
255279 await next ( )
@@ -274,6 +298,56 @@ class Installer {
274298 return ( dep . dev && includeDev ) || ( ! dep . dev && includeProd )
275299 }
276300
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+
277351 async buildTree ( tree ) {
278352 this . log ( 'verbose' , 'buildTree' , 'finalizing tree and running scripts' )
279353 await tree . forEachAsync ( async ( dep , next ) => {
@@ -282,13 +356,13 @@ class Installer {
282356 const spec = npa . resolve ( dep . name , dep . version )
283357 const depPath = dep . path ( this . prefix )
284358 this . log ( 'silly' , 'buildTree' , `linking ${ spec } ` )
285- const pkg = await readPkgJson ( path . join ( depPath , 'package.json' ) )
359+ const pkg = this . pkgJsons . get ( dep )
286360 await this . runScript ( 'preinstall' , pkg , depPath )
287361 await next ( ) // build children between preinstall and binLink
288362 // Don't link root bins
289363 if (
290364 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 ) ) )
292366 ) {
293367 // We skip the relatively expensive readPkgJson if there's no way
294368 // we'll actually be linking any bins or mans
@@ -329,23 +403,6 @@ class Installer {
329403 } , { concurrency : 50 , Promise : BB } )
330404 }
331405
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-
349406 // A cute little mark-and-sweep collector!
350407 async garbageCollect ( tree ) {
351408 if ( ! this . failedDeps . size ) { return }
@@ -365,7 +422,8 @@ class Installer {
365422 pkg . _id = pkg . name + '@' + pkg . version
366423 const ret = await runScript ( pkg , stage , pkgPath , {
367424 dir : this . prefix ,
368- log : npmlog
425+ log : npmlog ,
426+ config : this . opts
369427 } )
370428 this . timings . scripts += Date . now ( ) - start
371429 return ret
0 commit comments