You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
5.1 KiB

module.exports = runScript
var lifecycle = require("./utils/lifecycle.js")
, npm = require("./npm.js")
, path = require("path")
, readJson = require("read-package-json")
, log = require("npmlog")
, chain = require("slide").chain
runScript.usage = "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
, 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"
].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")) {
console.log(JSON.stringify(d.scripts || {}, null, 2))
return cb(null, allScripts)
}
if (npm.config.get("parseable")) {
allScripts.forEach(function(script) {
console.log(script + ":" + d.scripts[script])
})
return cb(null, allScripts)
}
var s = "\n "
var prefix = " "
if (scripts.length) {
console.log("Lifecycle scripts included in %s:", d.name)
}
scripts.forEach(function(script) {
console.log(prefix + script + s + d.scripts[script])
})
if (!scripts.length && runScripts.length) {
console.log("Scripts available in %s via `npm run-script`:", d.name)
}
else if (runScripts.length) {
console.log("\navailable via `npm run-script`:")
}
runScripts.forEach(function(script) {
console.log(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]) {
if (cmd === "test") {
pkg.scripts.test = "echo \"Error: no test specified\""
} else if (cmd === "env") {
if (process.platform === "win32") {
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 {
return cb(new Error("missing script: " + cmd))
}
}
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, 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
}