Skip to content
This repository was archived by the owner on Jul 28, 2021. It is now read-only.

Commit 11fc0d6

Browse files
committed
feat(prepare): support install scripts and native builds
1 parent 57e13c2 commit 11fc0d6

File tree

3 files changed

+81
-23
lines changed

3 files changed

+81
-23
lines changed

lib/ensure-package.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ class CacacheUnpacker extends tar.Parse {
225225
}
226226

227227
const EnsurePkgOpts = figgyPudding({
228-
restore: { default: true }
228+
restore: { default: false }
229229
})
230230

231231
module.exports = ensurePackage

lib/installer.js

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const BB = require('bluebird')
77

88
const {
99
linkBin: binLink,
10+
extract,
1011
getPrefix,
1112
log: npmlog,
1213
logicalTree: buildLogicalTree,
@@ -28,8 +29,8 @@ const rimraf = BB.promisify(require('rimraf'))
2829
const { spawn } = require('child_process')
2930

3031
const readFileAsync = BB.promisify(fs.readFile)
32+
const readdirAsync = BB.promisify(fs.readdir)
3133
const realpathAsync = BB.promisify(fs.realpath)
32-
const statAsync = BB.promisify(fs.stat)
3334
const symlinkAsync = BB.promisify(fs.symlink)
3435
const 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 => /\.gyp$/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

lib/lock-worker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ async function main (cache, integrity, pkg, opts) {
3737
if (res && !res.pkgCount) { throw new Error('no packages installed') }
3838
} catch (err) {
3939
if (!ensurePkg) { ensurePkg = require('./ensure-package.js') }
40-
await ensurePkg(cache, pkg.name, pkg, opts)
40+
await ensurePkg(cache, pkg.name, pkg, opts.concat({restore: true}))
4141
}
4242
}

0 commit comments

Comments
 (0)