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.

265 lines
7.6 KiB

module.exports = errorHandler
var cbCalled = false
, log = require("./log.js")
, npm = require("../npm.js")
, rm = require("rimraf")
, constants = require("constants")
, itWorked = false
, path = require("path")
, ini = require("./ini.js")
, wroteLogFile = false
process.on("exit", function (code) {
// console.error("exit", code)
if (!ini.resolved) return
if (code) itWorked = false
if (itWorked) log("ok")
else {
if (!cbCalled) {
log.error("cb() never called!\n ")
}
if (wroteLogFile) {
log.error([""
,"Additional logging details can be found in:"
," " + path.resolve("npm-debug.log")
].join("\n"))
wroteLogFile = false
}
log.win("not ok")
}
itWorked = false // ready for next exit
})
function errorHandler (er) {
// console.error("errorHandler", er)
if (!ini.resolved) {
// logging won't work unless we pretend that it's ready
er = er || new Error("Exit prior to config file resolving.")
console.error(er.stack || er.message)
}
if (cbCalled) {
er = er || new Error("Callback called more than once.")
}
cbCalled = true
if (!er) return exit(0)
if (!(er instanceof Error)) {
log.error(er)
return exit(1, true)
}
var m = er.code || er.message.match(/^(?:Error: )?(E[A-Z]+)/)
if (m) {
m = m[1]
if (!constants[m] && !npm[m]) constants[m] = {}
er.errno = npm[m] || constants[m]
}
switch (er.errno) {
case "ECONNREFUSED":
case constants.ECONNREFUSED:
log.error(er)
log.error(["If you are using Cygwin, please set up your /etc/resolv.conf"
,"See step 4 in this wiki page:"
," http://github.com/ry/node/wiki/Building-node.js-on-Cygwin-%28Windows%29"
,"If you are not using Cygwin, please report this"
,"at <http://github.com/isaacs/npm/issues>"
,"or email it to <npm-@googlegroups.com>"
].join("\n"))
break
case "EACCES":
case "EPERM":
case constants.EACCES:
case constants.EPERM:
log.error(er)
log.error(["",
"Please use 'sudo' or log in as root to run this command."
,""
," sudo npm "
+npm.config.get("argv").original.map(JSON.stringify).join(" ")
,""
,"or set the 'unsafe-perm' config var to true."
,""
," npm config set unsafe-perm true"
].join("\n"))
break
case npm.ELIFECYCLE:
er.code = "ELIFECYCLE"
log.error(er.message)
log.error(["","Failed at the "+er.pkgid+" "+er.stage+" script."
,"This is most likely a problem with the "+er.pkgname+" package,"
,"not with npm itself."
,"Tell the author that this fails on your system:"
," "+er.script
,"You can get their info via:"
," npm owner ls "+er.pkgname
,"There is likely additional logging output above."
].join("\n"))
break
case npm.EJSONPARSE:
er.code = "EJSONPARSE"
log.error(er.message)
log.error("File: "+er.file)
log.error(["Failed to parse package.json data."
,"package.json must be actual JSON, not just JavaScript."
,"","This is not a bug in npm."
,"Tell the package author to fix their package.json file."
].join("\n"), "JSON.parse")
break
case npm.E404:
er.code = "E404"
if (er.pkgid && er.pkgid !== "-") {
var msg = ["'"+er.pkgid+"' is not in the npm registry."
,"You could maybe bug the author to publish it"]
if (er.pkgid.match(/^node[\.\-]|[\.\-]js$/)) {
var s = er.pkgid.replace(/^node[\.\-]|[\.\-]js$/g, "")
if (s !== er.pkgid) {
s = s.replace(/[^a-z0-9]/g, ' ')
msg.push("Maybe try 'npm search " + s + "'")
}
}
msg.push("Note that you can also install from a tarball or folder.")
log.error(msg.join("\n"), "404")
}
break
case npm.EPUBLISHCONFLICT:
er.code = "EPUBLISHCONFLICT"
log.error(["Cannot publish over existing version."
,"Bump the 'version' field, set the --force flag, or"
," npm unpublish '"+er.pkgid+"'"
,"and try again"
].join("\n"), "publish fail" )
break
case npm.EISGIT:
er.code = "EISGIT"
log.error([er.message
," "+er.path
,"Refusing to remove it. Update manually,"
,"or move it out of the way first."
].join("\n"), "git" )
break
case npm.ECYCLE:
er.code = "ECYCLE"
log.error([er.message
,"While installing: "+er.pkgid
,"Found a pathological dependency case that npm cannot solve."
,"Please report this to the package author."
].join("\n"))
break
case npm.ENOTSUP:
er.code = "ENOTSUP"
log.error([er.message
,"Not compatible with your version of node/npm: "+er.pkgid
,"Required: "+JSON.stringify(er.required)
,"Actual: "
+JSON.stringify({npm:npm.version
,node:npm.config.get("node-version")})
].join("\n"))
break
case "EEXIST":
case constants.EEXIST:
log.error([er.message
,"File exists: "+er.path
,"Move it away, and try again."].join("\n"))
break
default:
log.error(er)
log.error(["Report this *entire* log at:"
," <http://github.com/isaacs/npm/issues>"
,"or email it to:"
," <npm-@googlegroups.com>"
].join("\n"))
break
}
var os = require("os")
log.error("")
log.error(os.type() + " " + os.release(), "System")
log.error(process.argv
.map(JSON.stringify).join(" "), "command")
log.error(process.cwd(), "cwd")
log.error(process.version, "node -v")
log.error(npm.version, "npm -v")
; [ "file"
, "path"
, "type"
, "syscall"
, "fstream_path"
, "fstream_unc_path"
, "fstream_type"
, "fstream_class"
, "fstream_finish_call"
, "fstream_linkpath"
, "arguments"
, "code"
, "message"
].forEach(function (k) {
if (er[k]) log.error(er[k], k)
})
if (er.fstream_stack) {
log.error(er.fstream_stack.join("\n"), "fstream_stack")
}
if (er.errno && typeof er.errno !== "object") log.error(er.errno, "errno")
exit(typeof er.errno === "number" ? er.errno : 1)
}
function exit (code, noLog) {
var doExit = npm.config.get("_exit")
log.verbose([code, doExit], "exit")
if (log.level === log.LEVEL.silent) noLog = true
if (code && !noLog) writeLogFile(reallyExit)
else rm("npm-debug.log", function () { rm(npm.tmp, reallyExit) })
function reallyExit() {
itWorked = !code
//if (!itWorked) {
if (!doExit) process.emit("exit", code)
else process.exit(code)
//}
}
}
var writingLogFile = false
function writeLogFile (cb) {
if (writingLogFile) return cb()
writingLogFile = true
wroteLogFile = true
var fs = require("graceful-fs")
, fstr = fs.createWriteStream("npm-debug.log")
, util = require("util")
log.history.forEach(function (m) {
var lvl = log.LEVEL[m.level]
, pref = m.pref ? " " + m.pref : ""
, b = lvl + pref + " "
, eol = process.platform === "win32" ? "\r\n" : "\n"
, msg = typeof m.msg === "string" ? m.msg
: msg instanceof Error ? msg.stack || msg.message
: util.inspect(m.msg, 0, 4)
fstr.write(new Buffer(b
+(msg.split(/\r?\n+/).join(eol+b))
+ eol))
})
fstr.end()
fstr.on("close", cb)
}