Skip to content

Commit a4fce56

Browse files
authored
Log a warning if a bad npm version is detected (#23)
* Log a warning if a bad npm version is detected * Check for any space separator in user agent * Reorder vars
1 parent 5cb090f commit a4fce56

File tree

1 file changed

+72
-24
lines changed

1 file changed

+72
-24
lines changed

index.js

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ function exec (command, options, callback) {
5757
}
5858
procDone(err)
5959
})
60+
61+
return proc
6062
}
6163

6264
// If we call `process.exit` immediately after logging to the console, then
@@ -118,10 +120,11 @@ function postinstallBuild () {
118120
var npm = 'npm'
119121
var execPath = process.env.npm_execpath
120122
var userAgent = process.env.npm_config_user_agent || ''
123+
var npmVersion = (userAgent.match(/^npm\/([^\s]+)/) || [])[1]
121124
// If the user agent doesn't start with `npm/`, just fall back to running
122125
// `npm` since alternative agents (e.g. Yarn) may not support the same
123126
// commands (like `prune`).
124-
if (execPath && userAgent.indexOf('npm/') === 0) {
127+
if (execPath && npmVersion) {
125128
npm = '"' + process.argv[0] + '" "' + execPath + '"'
126129
}
127130

@@ -235,6 +238,18 @@ function postinstallBuild () {
235238
return installArgs
236239
}
237240

241+
var warnUserAgent = function () {
242+
if (npmVersion && !/^(3\.|4\.0\.)/.test(npmVersion)) {
243+
log.warn(
244+
'postinstall-build:\n This version of npm (' + npmVersion + ') may ' +
245+
'not be compatible with postinstall-build! There\n are outstanding ' +
246+
'bugs in certain versions of npm that prevent it from working with\n ' +
247+
'postinstall-build. See https://github.com/exogen/postinstall-build#bugs-in-npm\n ' +
248+
'for more information.\n'
249+
)
250+
}
251+
}
252+
238253
var checkBuildArtifact = function (callback) {
239254
fs.stat(buildArtifact, function (err, stats) {
240255
if (err || !(stats.isFile() || stats.isDirectory())) {
@@ -252,6 +267,30 @@ function postinstallBuild () {
252267
})
253268
}
254269

270+
var checkUserAgent = function (callback) {
271+
// If we know an incompatible version of npm triggered `postinstall-build`,
272+
// print a warning. Note that if the original user agent is NOT npm, then we
273+
// don't know what version `postinstall-build` will actually run, since the
274+
// `$npm_config_user_agent` string didn't tell us, so run `npm --version` to
275+
// find out.
276+
if (npmVersion) {
277+
warnUserAgent()
278+
return callback(null, npmVersion)
279+
}
280+
var output = ''
281+
var command = npm + ' --version'
282+
log.info('postinstall-build:\n ' + command + '\n')
283+
var proc = exec(command, { stdio: 'pipe' }, function (err) {
284+
npmVersion = (output.match(/^(\d[^\s]*)/) || [])[1]
285+
warnUserAgent()
286+
callback(err, npmVersion)
287+
})
288+
proc.stdout.setEncoding('utf8')
289+
proc.stdout.on('data', function (chunk) {
290+
output += chunk
291+
})
292+
}
293+
255294
var installBuildDependencies = function (execOpts, callback) {
256295
// We only need to install dependencies if `shouldPrune` is true. Why?
257296
// Because this flag detects whether `devDependencies` were already
@@ -301,38 +340,47 @@ function postinstallBuild () {
301340
return handleError(err)
302341
}
303342
if (shouldBuild) {
304-
// If `npm install` ends up being run by `installBuildDependencies`, this
305-
// script will be run again. Set an environment variable to tell it to
306-
// skip the check. Really we just want the spawned child's `env` to be
307-
// modified, but it's easier just modify and pass along our entire
308-
// `process.env`.
309-
process.env.POSTINSTALL_BUILD_CWD = CWD
310-
311-
var execOpts = {
312-
env: process.env,
313-
quote: true
314-
}
315-
if (flags.verbosity === 0) {
316-
execOpts.stdio = 'ignore'
317-
}
318-
319-
installBuildDependencies(execOpts, function (err) {
343+
checkUserAgent(function (err) {
344+
// If an error occurred, the only consequence is that we don't know
345+
// which version of npm is going to be run, and can't issue a warning.
346+
// If there's an actual problem running npm we'll find out soon enough.
320347
if (err) {
321-
return handleError(err)
348+
log.warn('postinstall-build:\n ' + err + '\n')
322349
}
323-
// Don't need this flag anymore as `postinstall` was already run.
324-
// Change it back so the environment is minimally changed for the
325-
// remaining commands.
326-
process.env.POSTINSTALL_BUILD_CWD = POSTINSTALL_BUILD_CWD
327350

328-
runBuildCommand(execOpts, function (err) {
351+
// If `npm install` ends up being run by `installBuildDependencies`, this
352+
// script will be run again. Set an environment variable to tell it to
353+
// skip the check. Really we just want the spawned child's `env` to be
354+
// modified, but it's easier just modify and pass along our entire
355+
// `process.env`.
356+
process.env.POSTINSTALL_BUILD_CWD = CWD
357+
358+
var execOpts = {
359+
env: process.env,
360+
quote: true
361+
}
362+
if (flags.verbosity === 0) {
363+
execOpts.stdio = 'ignore'
364+
}
365+
366+
installBuildDependencies(execOpts, function (err) {
329367
if (err) {
330368
return handleError(err)
331369
}
332-
cleanUp(execOpts, function (err) {
370+
// Don't need this flag anymore as `postinstall` was already run.
371+
// Change it back so the environment is minimally changed for the
372+
// remaining commands.
373+
process.env.POSTINSTALL_BUILD_CWD = POSTINSTALL_BUILD_CWD
374+
375+
runBuildCommand(execOpts, function (err) {
333376
if (err) {
334377
return handleError(err)
335378
}
379+
cleanUp(execOpts, function (err) {
380+
if (err) {
381+
return handleError(err)
382+
}
383+
})
336384
})
337385
})
338386
})

0 commit comments

Comments
 (0)