123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- module.exports = runScript
- var lifecycle = require('./utils/lifecycle.js')
- var npm = require('./npm.js')
- var path = require('path')
- var readJson = require('read-package-json')
- var log = require('npmlog')
- var chain = require('slide').chain
- var usage = require('./utils/usage')
- var output = require('./utils/output.js')
- var didYouMean = require('./utils/did-you-mean')
- var isWindowsShell = require('./utils/is-windows-shell.js')
- runScript.usage = usage(
- 'run-script',
- 'npm run-script <command> [-- <args>...]'
- )
- runScript.completion = function (opts, cb) {
- // see if there's already a package specified.
- var argv = opts.conf.argv.remain
- if (argv.length >= 4) return cb()
- if (argv.length === 3) {
- // either specified a script locally, in which case, done,
- // or a package, in which case, complete against its scripts
- var json = path.join(npm.localPrefix, 'package.json')
- return readJson(json, function (er, d) {
- if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
- if (er) d = {}
- var scripts = Object.keys(d.scripts || {})
- console.error('local scripts', scripts)
- if (scripts.indexOf(argv[2]) !== -1) return cb()
- // ok, try to find out which package it was, then
- var pref = npm.config.get('global') ? npm.config.get('prefix')
- : npm.localPrefix
- var pkgDir = path.resolve(pref, 'node_modules', argv[2], 'package.json')
- readJson(pkgDir, function (er, d) {
- if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
- if (er) d = {}
- var scripts = Object.keys(d.scripts || {})
- return cb(null, scripts)
- })
- })
- }
- readJson(path.join(npm.localPrefix, 'package.json'), function (er, d) {
- if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
- d = d || {}
- cb(null, Object.keys(d.scripts || {}))
- })
- }
- function runScript (args, cb) {
- if (!args.length) return list(cb)
- var pkgdir = npm.localPrefix
- var cmd = args.shift()
- readJson(path.resolve(pkgdir, 'package.json'), function (er, d) {
- if (er) return cb(er)
- run(d, pkgdir, cmd, args, cb)
- })
- }
- function list (cb) {
- var json = path.join(npm.localPrefix, 'package.json')
- var cmdList = [
- 'publish',
- 'install',
- 'uninstall',
- 'test',
- 'stop',
- 'start',
- 'restart',
- 'version'
- ].reduce(function (l, p) {
- return l.concat(['pre' + p, p, 'post' + p])
- }, [])
- return readJson(json, function (er, d) {
- if (er && er.code !== 'ENOENT' && er.code !== 'ENOTDIR') return cb(er)
- if (er) d = {}
- var allScripts = Object.keys(d.scripts || {})
- var scripts = []
- var runScripts = []
- allScripts.forEach(function (script) {
- if (cmdList.indexOf(script) !== -1) scripts.push(script)
- else runScripts.push(script)
- })
- if (log.level === 'silent') {
- return cb(null, allScripts)
- }
- if (npm.config.get('json')) {
- output(JSON.stringify(d.scripts || {}, null, 2))
- return cb(null, allScripts)
- }
- if (npm.config.get('parseable')) {
- allScripts.forEach(function (script) {
- output(script + ':' + d.scripts[script])
- })
- return cb(null, allScripts)
- }
- var s = '\n '
- var prefix = ' '
- if (scripts.length) {
- output('Lifecycle scripts included in %s:', d.name)
- }
- scripts.forEach(function (script) {
- output(prefix + script + s + d.scripts[script])
- })
- if (!scripts.length && runScripts.length) {
- output('Scripts available in %s via `npm run-script`:', d.name)
- } else if (runScripts.length) {
- output('\navailable via `npm run-script`:')
- }
- runScripts.forEach(function (script) {
- output(prefix + script + s + d.scripts[script])
- })
- return cb(null, allScripts)
- })
- }
- function run (pkg, wd, cmd, args, cb) {
- if (!pkg.scripts) pkg.scripts = {}
- var cmds
- if (cmd === 'restart' && !pkg.scripts.restart) {
- cmds = [
- 'prestop', 'stop', 'poststop',
- 'restart',
- 'prestart', 'start', 'poststart'
- ]
- } else {
- if (pkg.scripts[cmd] == null) {
- if (cmd === 'test') {
- pkg.scripts.test = 'echo \'Error: no test specified\''
- } else if (cmd === 'env') {
- if (isWindowsShell) {
- log.verbose('run-script using default platform env: SET (Windows)')
- pkg.scripts[cmd] = 'SET'
- } else {
- log.verbose('run-script using default platform env: env (Unix)')
- pkg.scripts[cmd] = 'env'
- }
- } else if (npm.config.get('if-present')) {
- return cb(null)
- } else {
- let suggestions = didYouMean(cmd, Object.keys(pkg.scripts))
- suggestions = suggestions ? '\n' + suggestions : ''
- return cb(new Error('missing script: ' + cmd + suggestions))
- }
- }
- cmds = [cmd]
- }
- if (!cmd.match(/^(pre|post)/)) {
- cmds = ['pre' + cmd].concat(cmds).concat('post' + cmd)
- }
- log.verbose('run-script', cmds)
- chain(cmds.map(function (c) {
- // pass cli arguments after -- to script.
- if (pkg.scripts[c] && c === cmd) {
- pkg.scripts[c] = pkg.scripts[c] + joinArgs(args)
- }
- // when running scripts explicitly, assume that they're trusted.
- return [lifecycle, pkg, c, wd, { unsafePerm: true }]
- }), cb)
- }
- // join arguments after '--' and pass them to script,
- // handle special characters such as ', ", ' '.
- function joinArgs (args) {
- var joinedArgs = ''
- args.forEach(function (arg) {
- joinedArgs += ' "' + arg.replace(/"/g, '\\"') + '"'
- })
- return joinedArgs
- }
|