Skip to content

Commit 674004c

Browse files
committedMay 26, 2017
lifecycle: added prepack and postpack (#16725)
1 parent db76632 commit 674004c

File tree

9 files changed

+155
-128
lines changed

9 files changed

+155
-128
lines changed
 

‎doc/misc/npm-scripts.md

+11-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ npm supports the "scripts" property of the package.json script, for the
77
following scripts:
88

99
* prepublish:
10-
Run BEFORE the package is published. (Also run on local `npm
11-
install` without any arguments. See below.)
10+
Run BEFORE the package is packed and published, as well as on local `npm
11+
install` without any arguments. (See below)
1212
* prepare:
13-
Run both BEFORE the package is published, and on local `npm
14-
install` without any arguments. (See below.) This is run
13+
Run both BEFORE the package is packed and published, and on local `npm
14+
install` without any arguments (See below). This is run
1515
AFTER `prepublish`, but BEFORE `prepublishOnly`.
1616
* prepublishOnly:
17-
Run BEFORE the package is published. (See below.)
17+
Run BEFORE the package is prepared and packed, ONLY on `npm publish`. (See
18+
below.)
19+
* prepack:
20+
run BEFORE a tarball is packed (on `npm pack`, `npm publish`, and when
21+
installing git dependencies)
22+
* postpack:
23+
Run AFTER the tarball has been generated and moved to its final destination.
1824
* publish, postpublish:
1925
Run AFTER the package is published.
2026
* preinstall:

‎lib/config/pacote.js

+5-90
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
'use strict'
22

3-
const BB = require('bluebird')
43
const Buffer = require('safe-buffer').Buffer
54

6-
const cp = require('child_process')
75
const npm = require('../npm')
86
const log = require('npmlog')
9-
const packToStream = require('../utils/tar').packToStream
7+
let pack
108
const path = require('path')
11-
const pipe = BB.promisify(require('mississippi').pipe)
12-
const readJson = BB.promisify(require('read-package-json'))
13-
const PassThrough = require('stream').PassThrough
149

1510
let effectiveOwner
1611

1712
module.exports = pacoteOpts
1813
function pacoteOpts (moreOpts) {
14+
if (!pack) {
15+
pack = require('../pack.js')
16+
}
1917
const ownerStats = calculateOwner()
2018
const opts = {
2119
cache: path.join(npm.config.get('cache'), '_cacache'),
2220
defaultTag: npm.config.get('tag'),
23-
dirPacker: prepareAndPack,
21+
dirPacker: pack.packGitDep,
2422
hashAlgorithm: 'sha1',
2523
localAddress: npm.config.get('local-address'),
2624
log: log,
@@ -108,86 +106,3 @@ function calculateOwner () {
108106

109107
return effectiveOwner
110108
}
111-
112-
const PASSTHROUGH_OPTS = [
113-
'always-auth',
114-
'auth-type',
115-
'ca',
116-
'cafile',
117-
'cert',
118-
'git',
119-
'local-address',
120-
'maxsockets',
121-
'offline',
122-
'prefer-offline',
123-
'prefer-online',
124-
'proxy',
125-
'https-proxy',
126-
'registry',
127-
'send-metrics',
128-
'sso-poll-frequency',
129-
'sso-type',
130-
'strict-ssl'
131-
]
132-
133-
function prepareAndPack (manifest, dir) {
134-
const stream = new PassThrough()
135-
readJson(path.join(dir, 'package.json')).then((pkg) => {
136-
if (pkg.scripts && pkg.scripts.prepare) {
137-
log.verbose('prepareGitDep', `${manifest._spec}: installing devDeps and running prepare script.`)
138-
const cliArgs = PASSTHROUGH_OPTS.reduce((acc, opt) => {
139-
if (npm.config.get(opt, 'cli') != null) {
140-
acc.push(`--${opt}=${npm.config.get(opt)}`)
141-
}
142-
return acc
143-
}, [])
144-
const child = cp.spawn(process.env.NODE || process.execPath, [
145-
require.main.filename,
146-
'install',
147-
'--ignore-prepublish',
148-
'--no-progress',
149-
'--no-save'
150-
].concat(cliArgs), {
151-
cwd: dir,
152-
env: process.env
153-
})
154-
let errData = []
155-
let errDataLen = 0
156-
let outData = []
157-
let outDataLen = 0
158-
child.stdout.on('data', (data) => {
159-
outData.push(data)
160-
outDataLen += data.length
161-
log.gauge.pulse('preparing git package')
162-
})
163-
child.stderr.on('data', (data) => {
164-
errData.push(data)
165-
errDataLen += data.length
166-
log.gauge.pulse('preparing git package')
167-
})
168-
return BB.fromNode((cb) => {
169-
child.on('error', cb)
170-
child.on('exit', (code, signal) => {
171-
if (code > 0) {
172-
const err = new Error(`${signal}: npm exited with code ${code} while attempting to build ${manifest._requested}. Clone the repository manually and run 'npm install' in it for more information.`)
173-
err.code = code
174-
err.signal = signal
175-
cb(err)
176-
} else {
177-
cb()
178-
}
179-
})
180-
}).then(() => {
181-
if (outDataLen > 0) log.silly('prepareGitDep', '1>', Buffer.concat(outData, outDataLen).toString())
182-
if (errDataLen > 0) log.silly('prepareGitDep', '2>', Buffer.concat(errData, errDataLen).toString())
183-
}, (err) => {
184-
if (outDataLen > 0) log.error('prepareGitDep', '1>', Buffer.concat(outData, outDataLen).toString())
185-
if (errDataLen > 0) log.error('prepareGitDep', '2>', Buffer.concat(errData, errDataLen).toString())
186-
throw err
187-
})
188-
}
189-
}).then(() => {
190-
return pipe(packToStream(manifest, dir), stream)
191-
}).catch((err) => stream.emit('error', err))
192-
return stream
193-
}

‎lib/fetch-package-metadata.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const npmlog = require('npmlog')
1212
const limit = require('call-limit')
1313
const tempFilename = require('./utils/temp-filename')
1414
const pacote = require('pacote')
15-
const pacoteOpts = require('./config/pacote')
15+
let pacoteOpts
1616
const isWindows = require('./utils/is-windows.js')
1717

1818
function andLogAndFinish (spec, tracker, done) {
@@ -52,7 +52,9 @@ function fetchPackageMetadata (spec, where, opts, done) {
5252
err.code = 'EWINDOWSPATH'
5353
return logAndFinish(err)
5454
}
55-
55+
if (!pacoteOpts) {
56+
pacoteOpts = require('./config/pacote')
57+
}
5658
pacote.manifest(dep, pacoteOpts({
5759
annotate: true,
5860
fullMetadata: opts.fullMetadata,
@@ -83,6 +85,9 @@ function fetchPackageMetadata (spec, where, opts, done) {
8385
module.exports.addBundled = addBundled
8486
function addBundled (pkg, next) {
8587
validate('OF', arguments)
88+
if (!pacoteOpts) {
89+
pacoteOpts = require('./config/pacote')
90+
}
8691
if (pkg._bundled !== undefined) return next(null, pkg)
8792

8893
if (!pkg.bundleDependencies && pkg._requested.type !== 'directory') return next(null, pkg)

‎lib/install/action/extract.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ const move = BB.promisify(require('../../utils/move.js'))
1212
const npa = require('npm-package-arg')
1313
const packageId = require('../../utils/package-id.js')
1414
const pacote = require('pacote')
15-
const pacoteOpts = require('../../config/pacote')
15+
let pacoteOpts
1616
const path = require('path')
1717

1818
module.exports = extract
1919
function extract (staging, pkg, log) {
2020
log.silly('extract', packageId(pkg))
2121
const extractTo = moduleStagingPath(staging, pkg)
22+
if (!pacoteOpts) {
23+
pacoteOpts = require('../../config/pacote')
24+
}
2225
const opts = pacoteOpts({
2326
integrity: pkg.package._integrity
2427
})

‎lib/install/inflate-shrinkwrap.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
const BB = require('bluebird')
44

5-
const addBundled = BB.promisify(require('../fetch-package-metadata.js').addBundled)
5+
let addBundled
66
const childPath = require('../utils/child-path.js')
77
const createChild = require('./node.js').create
8-
const fetchPackageMetadata = BB.promisify(require('../fetch-package-metadata.js'))
8+
let fetchPackageMetadata
99
const inflateBundled = require('./inflate-bundled.js')
1010
const moduleName = require('../utils/module-name.js')
1111
const normalizePackageData = require('normalize-package-data')
@@ -15,6 +15,10 @@ const validate = require('aproba')
1515
const path = require('path')
1616

1717
module.exports = function (tree, swdeps, opts, finishInflating) {
18+
if (!fetchPackageMetadata) {
19+
fetchPackageMetadata = BB.promisify(require('../fetch-package-metadata.js'))
20+
addBundled = BB.promisify(fetchPackageMetadata.addBundled)
21+
}
1822
if (!npm.config.get('shrinkwrap') || !npm.config.get('package-lock')) {
1923
return finishInflating()
2024
}

‎lib/pack.js

+111-7
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ const BB = require('bluebird')
88

99
const cache = require('./cache')
1010
const cacache = require('cacache')
11+
const cp = require('child_process')
1112
const deprCheck = require('./utils/depr-check')
12-
const fpm = BB.promisify(require('./fetch-package-metadata'))
13+
const fpm = require('./fetch-package-metadata')
1314
const fs = require('graceful-fs')
1415
const install = require('./install')
1516
const lifecycle = BB.promisify(require('./utils/lifecycle'))
17+
const log = require('npmlog')
1618
const move = require('move-concurrently')
1719
const npm = require('./npm')
1820
const output = require('./utils/output')
1921
const pacoteOpts = require('./config/pacote')
2022
const path = require('path')
23+
const PassThrough = require('stream').PassThrough
2124
const pathIsInside = require('path-is-inside')
2225
const pipe = BB.promisify(require('mississippi').pipe)
2326
const prepublishWarning = require('./utils/warn-deprecated')('prepublish-on-install')
@@ -53,7 +56,7 @@ function pack (args, silent, cb) {
5356

5457
// add to cache, then cp to the cwd
5558
function pack_ (pkg, dir) {
56-
return fpm(pkg, dir).then((mani) => {
59+
return BB.fromNode((cb) => fpm(pkg, dir, cb)).then((mani) => {
5760
let name = mani.name[0] === '@'
5861
// scoped packages get special treatment
5962
? mani.name.substr(1).replace(/\//g, '-')
@@ -108,10 +111,111 @@ function prepareDirectory (dir) {
108111
module.exports.packDirectory = packDirectory
109112
function packDirectory (mani, dir, target) {
110113
deprCheck(mani)
111-
return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'packing'}, (tmp) => {
112-
const tmpTarget = path.join(tmp, path.basename(target))
113-
return tarPack(tmpTarget, dir, mani).then(() => {
114-
return move(tmpTarget, target, {Promise: BB, fs})
115-
}).then(() => target)
114+
return readJson(path.join(dir, 'package.json')).then((pkg) => {
115+
return lifecycle(pkg, 'prepack', dir)
116+
}).then(() => {
117+
return readJson(path.join(dir, 'package.json'))
118+
}).then((pkg) => {
119+
return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'packing'}, (tmp) => {
120+
const tmpTarget = path.join(tmp, path.basename(target))
121+
return tarPack(tmpTarget, dir, pkg).then(() => {
122+
return move(tmpTarget, target, {Promise: BB, fs})
123+
}).then(() => {
124+
return lifecycle(pkg, 'postpack', dir)
125+
}).then(() => target)
126+
})
116127
})
117128
}
129+
130+
const PASSTHROUGH_OPTS = [
131+
'always-auth',
132+
'auth-type',
133+
'ca',
134+
'cafile',
135+
'cert',
136+
'git',
137+
'local-address',
138+
'maxsockets',
139+
'offline',
140+
'prefer-offline',
141+
'prefer-online',
142+
'proxy',
143+
'https-proxy',
144+
'registry',
145+
'send-metrics',
146+
'sso-poll-frequency',
147+
'sso-type',
148+
'strict-ssl'
149+
]
150+
151+
module.exports.packGitDep = packGitDep
152+
function packGitDep (manifest, dir) {
153+
const stream = new PassThrough()
154+
readJson(path.join(dir, 'package.json')).then((pkg) => {
155+
if (pkg.scripts && pkg.scripts.prepare) {
156+
log.verbose('prepareGitDep', `${manifest._spec}: installing devDeps and running prepare script.`)
157+
const cliArgs = PASSTHROUGH_OPTS.reduce((acc, opt) => {
158+
if (npm.config.get(opt, 'cli') != null) {
159+
acc.push(`--${opt}=${npm.config.get(opt)}`)
160+
}
161+
return acc
162+
}, [])
163+
const child = cp.spawn(process.env.NODE || process.execPath, [
164+
require.main.filename,
165+
'install',
166+
'--ignore-prepublish',
167+
'--no-progress',
168+
'--no-save'
169+
].concat(cliArgs), {
170+
cwd: dir,
171+
env: process.env
172+
})
173+
let errData = []
174+
let errDataLen = 0
175+
let outData = []
176+
let outDataLen = 0
177+
child.stdout.on('data', (data) => {
178+
outData.push(data)
179+
outDataLen += data.length
180+
log.gauge.pulse('preparing git package')
181+
})
182+
child.stderr.on('data', (data) => {
183+
errData.push(data)
184+
errDataLen += data.length
185+
log.gauge.pulse('preparing git package')
186+
})
187+
return BB.fromNode((cb) => {
188+
child.on('error', cb)
189+
child.on('exit', (code, signal) => {
190+
if (code > 0) {
191+
const err = new Error(`${signal}: npm exited with code ${code} while attempting to build ${manifest._requested}. Clone the repository manually and run 'npm install' in it for more information.`)
192+
err.code = code
193+
err.signal = signal
194+
cb(err)
195+
} else {
196+
cb()
197+
}
198+
})
199+
}).then(() => {
200+
if (outDataLen > 0) log.silly('prepareGitDep', '1>', Buffer.concat(outData, outDataLen).toString())
201+
if (errDataLen > 0) log.silly('prepareGitDep', '2>', Buffer.concat(errData, errDataLen).toString())
202+
}, (err) => {
203+
if (outDataLen > 0) log.error('prepareGitDep', '1>', Buffer.concat(outData, outDataLen).toString())
204+
if (errDataLen > 0) log.error('prepareGitDep', '2>', Buffer.concat(errData, errDataLen).toString())
205+
throw err
206+
})
207+
}
208+
}).then(() => {
209+
return readJson(path.join(dir, 'package.json'))
210+
}).then((pkg) => {
211+
return cacache.tmp.withTmp(npm.tmp, {
212+
tmpPrefix: 'pacote-packing'
213+
}, (tmp) => {
214+
const tmpTar = path.join(tmp, 'package.tgz')
215+
return packDirectory(manifest, dir, tmpTar).then(() => {
216+
return pipe(fs.createReadStream(tmpTar), stream)
217+
})
218+
})
219+
}).catch((err) => stream.emit('error', err))
220+
return stream
221+
}

‎lib/publish.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,23 @@ function publish_ (arg) {
7676
}
7777

7878
function publishFromDirectory (arg) {
79-
return pack.prepareDirectory(arg).tap((pkg) => {
79+
// All this readJson is because any of the given scripts might modify the
80+
// package.json in question, so we need to refresh after every step.
81+
return pack.prepareDirectory(arg).then(() => {
82+
return readJson(path.join(arg, 'package.json'))
83+
}).then((pkg) => {
8084
return lifecycle(pkg, 'prepublishOnly', arg)
81-
}).tap((pkg) => {
85+
}).then(() => {
86+
return readJson(path.join(arg, 'package.json'))
87+
}).then((pkg) => {
8288
return cacache.tmp.withTmp(npm.tmp, {tmpPrefix: 'fromDir'}, (tmpDir) => {
8389
const target = path.join(tmpDir, 'package.tgz')
8490
return pack.packDirectory(pkg, arg, target).then(() => {
8591
return upload(arg, pkg, false, target)
8692
})
8793
})
94+
}).then(() => {
95+
return readJson(path.join(arg, 'package.json'))
8896
}).tap((pkg) => {
8997
return lifecycle(pkg, 'publish', arg)
9098
}).tap((pkg) => {

‎lib/utils/tar.js

-19
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// commands for packing and unpacking tarballs
44
// this file is used by lib/cache.js
55

6-
const BB = require('bluebird')
7-
86
var fs = require('graceful-fs')
97
var path = require('path')
108
var writeFileAtomic = require('write-file-atomic')
@@ -28,11 +26,6 @@ var moduleName = require('./module-name.js')
2826
var packageId = require('./package-id.js')
2927
var pulseTillDone = require('../utils/pulse-till-done.js')
3028

31-
const cacache = require('cacache')
32-
const packAsync = BB.promisify(pack)
33-
const PassThrough = require('stream').PassThrough
34-
const pipe = BB.promisify(require('mississippi').pipe)
35-
3629
if (process.env.SUDO_UID && myUid === 0) {
3730
if (!isNaN(process.env.SUDO_UID)) myUid = +process.env.SUDO_UID
3831
if (!isNaN(process.env.SUDO_GID)) myGid = +process.env.SUDO_GID
@@ -41,18 +34,6 @@ if (process.env.SUDO_UID && myUid === 0) {
4134
exports.pack = pack
4235
exports.unpack = unpack
4336

44-
module.exports.packToStream = packToStream
45-
function packToStream (mani, dir) {
46-
const stream = new PassThrough()
47-
cacache.tmp.withTmp(npm.tmp, (tmp) => {
48-
const tmpTarget = path.join(tmp, 'package.tgz')
49-
return packAsync(tmpTarget, dir, mani).then(() => {
50-
return pipe(fs.createReadStream(tmpTarget), stream)
51-
})
52-
}).catch((err) => stream.emit('error', err))
53-
return stream
54-
}
55-
5637
function pack (tarball, folder, pkg, cb) {
5738
log.verbose('tar pack', [tarball, folder])
5839

‎test/tap/config-meta.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var exceptions = [
1919
path.resolve(lib, 'adduser.js'),
2020
path.resolve(lib, 'config.js'),
2121
path.resolve(lib, 'config', 'pacote.js'),
22+
path.resolve(lib, 'pack.js'),
2223
path.resolve(lib, 'publish.js'),
2324
path.resolve(lib, 'install', 'inflate-shrinkwrap.js'),
2425
path.resolve(lib, 'utils', 'lifecycle.js'),

0 commit comments

Comments
 (0)
Please sign in to comment.