/lib/utils/error-handler.js
JavaScript | 324 lines | 274 code | 41 blank | 9 comment | 44 complexity | 1c162a55cfe911bee79c818077ccfffd MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, Apache-2.0, WTFPL
- module.exports = errorHandler
- var cbCalled = false
- , log = require("npmlog")
- , npm = require("../npm.js")
- , rm = require("rimraf")
- , itWorked = false
- , path = require("path")
- , wroteLogFile = false
- , exitCode = 0
- process.on("exit", function (code) {
- // console.error("exit", code)
- if (!npm.config.loaded) return
- if (code) itWorked = false
- if (itWorked) log.info("ok")
- else {
- if (!cbCalled) {
- log.error("", "cb() never called!")
- }
- if (wroteLogFile) {
- log.error("", [""
- ,"Additional logging details can be found in:"
- ," " + path.resolve("npm-debug.log")
- ].join("\n"))
- wroteLogFile = false
- }
- log.error("not ok", "code", code)
- }
- var doExit = npm.config.get("_exit")
- if (doExit) {
- // actually exit.
- if (exitCode === 0 && !itWorked) {
- exitCode = 1
- }
- if (exitCode !== 0) process.exit(exitCode)
- } else {
- itWorked = false // ready for next exit
- }
- })
- function exit (code, noLog) {
- exitCode = exitCode || code
- var doExit = npm.config.get("_exit")
- log.verbose("exit", [code, doExit])
- if (log.level === "silent") noLog = true
- if (code && !noLog) writeLogFile(reallyExit)
- else rm("npm-debug.log", function () { rm(npm.tmp, reallyExit) })
- function reallyExit() {
- // truncate once it's been written.
- log.record.length = 0
- itWorked = !code
- // just emit a fake exit event.
- // if we're really exiting, then let it exit on its own, so that
- // in-process stuff can finish or clean up first.
- if (!doExit) process.emit("exit", code)
- }
- }
- function errorHandler (er) {
- var printStack = false
- // console.error("errorHandler", er)
- if (!npm.config.loaded) {
- // 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 (typeof er === "string") {
- log.error("", er)
- return exit(1, true)
- } else if (!(er instanceof Error)) {
- log.error("weird error", er)
- return exit(1, true)
- }
- var m = er.code || er.message.match(/^(?:Error: )?(E[A-Z]+)/)
- if (m && !er.code) er.code = m
- switch (er.code) {
- case "ECONNREFUSED":
- log.error("", er)
- log.error("", ["\nIf you are behind a proxy, please make sure that the"
- ,"'proxy' config is set properly. See: 'npm help config'"
- ].join("\n"))
- printStack = true
- break
- case "EACCES":
- case "EPERM":
- log.error("", er)
- log.error("", ["\nPlease try running this command again as root/Administrator."
- ].join("\n"))
- printStack = true
- break
- case "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 "ENOGIT":
- er.code = "ENOGIT"
- log.error("", er.message)
- log.error("", ["","Failed using git."
- ,"This is most likely not a problem with npm itself."
- ,"Please check if you have git installed and in your PATH."
- ].join("\n"))
- break
- case "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 "E404":
- er.code = "E404"
- if (er.pkgid && er.pkgid !== "-") {
- var msg = ["'"+er.pkgid+"' is not in the npm registry."
- ,"You should 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("\nMaybe try 'npm search " + s + "'")
- }
- }
- msg.push("\nNote that you can also install from a"
- ,"tarball, folder, or http url, or git url.")
- log.error("404", msg.join("\n"))
- }
- break
- case "EPUBLISHCONFLICT":
- er.code = "EPUBLISHCONFLICT"
- log.error("publish fail", ["Cannot publish over existing version."
- ,"Update the 'version' field in package.json and try again."
- ,""
- ,"If the previous version was published in error, see:"
- ," npm help unpublish"
- ,""
- ,"To automatically increment version numbers, see:"
- ," npm help version"
- ].join("\n"))
- break
- case "EISGIT":
- er.code = "EISGIT"
- log.error("git", [er.message
- ," "+er.path
- ,"Refusing to remove it. Update manually,"
- ,"or move it out of the way first."
- ].join("\n"))
- break
- case "ECYCLE":
- er.code = "ECYCLE"
- log.error("cycle", [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 "EBADPLATFORM":
- er.code = "EBADPLATFORM"
- log.error("notsup", [er.message
- ,"Not compatible with your operating system or architecture: "+er.pkgid
- ,"Valid OS: "+er.os.join(",")
- ,"Valid Arch: "+er.cpu.join(",")
- ,"Actual OS: "+process.platform
- ,"Actual Arch: "+process.arch
- ].join("\n"))
- break
- case "EEXIST":
- log.error([er.message
- ,"File exists: "+er.path
- ,"Move it away, and try again."].join("\n"))
- break
- case "ENEEDAUTH":
- log.error("need auth", [er.message
- ,"You need to authorize this machine using `npm adduser`"
- ].join("\n"))
- break
- case "EPEERINVALID":
- var peerErrors = Object.keys(er.peersDepending).map(function (peer) {
- return "Peer " + peer + " wants " + er.packageName + "@"
- + er.peersDepending[peer]
- })
- log.error("peerinvalid", [er.message].concat(peerErrors).join("\n"))
- break
- case "ENOTFOUND":
- log.error("network", [er.message
- ,"This is most likely not a problem with npm itself"
- ,"and is related to network connectivity."
- ,"In most cases you are behind a proxy or have bad network settings."
- ,"\nIf you are behind a proxy, please make sure that the"
- ,"'proxy' config is set properly. See: 'npm help config'"
- ].join("\n"))
- break
- case "ENOTSUP":
- if (er.required) {
- log.error("notsup", [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
- } // else passthrough
- default:
- log.error("", er.stack || er.message || er)
- log.error("", ["If you need help, you may report this log at:"
- ," <http://github.com/isaacs/npm/issues>"
- ,"or email it to:"
- ," <npm-@googlegroups.com>"
- ].join("\n"))
- printStack = false
- break
- }
- var os = require("os")
- // just a line break
- console.error("")
- log.error("System", os.type() + " " + os.release())
- log.error("command", process.argv
- .map(JSON.stringify).join(" "))
- log.error("cwd", process.cwd())
- log.error("node -v", process.version)
- log.error("npm -v", npm.version)
- ; [ "file"
- , "path"
- , "type"
- , "syscall"
- , "fstream_path"
- , "fstream_unc_path"
- , "fstream_type"
- , "fstream_class"
- , "fstream_finish_call"
- , "fstream_linkpath"
- , "code"
- , "errno"
- , "stack"
- , "fstream_stack"
- ].forEach(function (k) {
- var v = er[k]
- if (k === "stack") {
- if (!printStack) return
- if (!v) v = er.message
- }
- if (!v) return
- if (k === "fstream_stack") v = v.join("\n")
- log.error(k, v)
- })
- exit(typeof er.errno === "number" ? er.errno : 1)
- }
- 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")
- , os = require("os")
- , out = ""
- log.record.forEach(function (m) {
- var pref = [m.id, m.level]
- if (m.prefix) pref.push(m.prefix)
- pref = pref.join(' ')
- m.message.trim().split(/\r?\n/).map(function (line) {
- return (pref + ' ' + line).trim()
- }).forEach(function (line) {
- out += line + os.EOL
- })
- })
- fstr.end(out)
- fstr.on("close", cb)
- }