PageRenderTime 55ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/utils/error-handler.js

https://github.com/samseen/npm
JavaScript | 345 lines | 293 code | 43 blank | 9 comment | 49 complexity | 21f4e421662f3f7c4ba96a5eaadf6018 MD5 | raw file
Possible License(s): 0BSD, MIT, BSD-3-Clause, WTFPL, Apache-2.0, MPL-2.0-no-copyleft-exception, GPL-2.0, AGPL-3.0
  1. module.exports = errorHandler
  2. var cbCalled = false
  3. , log = require("npmlog")
  4. , npm = require("../npm.js")
  5. , rm = require("rimraf")
  6. , itWorked = false
  7. , path = require("path")
  8. , wroteLogFile = false
  9. , exitCode = 0
  10. process.on("exit", function (code) {
  11. // console.error("exit", code)
  12. if (!npm.config || !npm.config.loaded) return
  13. if (code) itWorked = false
  14. if (itWorked) log.info("ok")
  15. else {
  16. if (!cbCalled) {
  17. log.error("", "cb() never called!")
  18. }
  19. if (wroteLogFile) {
  20. log.error("", [""
  21. ,"Additional logging details can be found in:"
  22. ," " + path.resolve("npm-debug.log")
  23. ].join("\n"))
  24. wroteLogFile = false
  25. }
  26. log.error("not ok", "code", code)
  27. }
  28. var doExit = npm.config.get("_exit")
  29. if (doExit) {
  30. // actually exit.
  31. if (exitCode === 0 && !itWorked) {
  32. exitCode = 1
  33. }
  34. if (exitCode !== 0) process.exit(exitCode)
  35. } else {
  36. itWorked = false // ready for next exit
  37. }
  38. })
  39. function exit (code, noLog) {
  40. exitCode = exitCode || process.exitCode || code
  41. var doExit = npm.config ? npm.config.get("_exit") : true
  42. log.verbose("exit", [code, doExit])
  43. if (log.level === "silent") noLog = true
  44. if (code && !noLog) writeLogFile(reallyExit)
  45. else rm("npm-debug.log", function () { rm(npm.tmp, reallyExit) })
  46. function reallyExit() {
  47. // truncate once it's been written.
  48. log.record.length = 0
  49. itWorked = !code
  50. // just emit a fake exit event.
  51. // if we're really exiting, then let it exit on its own, so that
  52. // in-process stuff can finish or clean up first.
  53. if (!doExit) process.emit("exit", code)
  54. npm.spinner.stop()
  55. }
  56. }
  57. function errorHandler (er) {
  58. var printStack = false
  59. // console.error("errorHandler", er)
  60. if (!npm.config || !npm.config.loaded) {
  61. // logging won't work unless we pretend that it's ready
  62. er = er || new Error("Exit prior to config file resolving.")
  63. console.error(er.stack || er.message)
  64. }
  65. if (cbCalled) {
  66. er = er || new Error("Callback called more than once.")
  67. }
  68. cbCalled = true
  69. if (!er) return exit(0)
  70. if (typeof er === "string") {
  71. log.error("", er)
  72. return exit(1, true)
  73. } else if (!(er instanceof Error)) {
  74. log.error("weird error", er)
  75. return exit(1, true)
  76. }
  77. var m = er.code || er.message.match(/^(?:Error: )?(E[A-Z]+)/)
  78. if (m && !er.code) er.code = m
  79. switch (er.code) {
  80. case "ECONNREFUSED":
  81. log.error("", er)
  82. log.error("", ["\nIf you are behind a proxy, please make sure that the"
  83. ,"'proxy' config is set properly. See: 'npm help config'"
  84. ].join("\n"))
  85. printStack = true
  86. break
  87. case "EACCES":
  88. case "EPERM":
  89. log.error("", er)
  90. log.error("", ["\nPlease try running this command again as root/Administrator."
  91. ].join("\n"))
  92. printStack = true
  93. break
  94. case "ELIFECYCLE":
  95. er.code = "ELIFECYCLE"
  96. log.error("", er.message)
  97. log.error("", ["","Failed at the "+er.pkgid+" "+er.stage+" script."
  98. ,"This is most likely a problem with the "+er.pkgname+" package,"
  99. ,"not with npm itself."
  100. ,"Tell the author that this fails on your system:"
  101. ," "+er.script
  102. ,"You can get their info via:"
  103. ," npm owner ls "+er.pkgname
  104. ,"There is likely additional logging output above."
  105. ].join("\n"))
  106. break
  107. case "ENOGIT":
  108. er.code = "ENOGIT"
  109. log.error("", er.message)
  110. log.error("", ["","Failed using git."
  111. ,"This is most likely not a problem with npm itself."
  112. ,"Please check if you have git installed and in your PATH."
  113. ].join("\n"))
  114. break
  115. case "EJSONPARSE":
  116. er.code = "EJSONPARSE"
  117. log.error("", er.message)
  118. log.error("", "File: "+er.file)
  119. log.error("", ["Failed to parse package.json data."
  120. ,"package.json must be actual JSON, not just JavaScript."
  121. ,"","This is not a bug in npm."
  122. ,"Tell the package author to fix their package.json file."
  123. ].join("\n"), "JSON.parse")
  124. break
  125. case "E404":
  126. er.code = "E404"
  127. var msg = [er.message]
  128. if (er.pkgid && er.pkgid !== "-") {
  129. msg.push("", "'"+er.pkgid+"' is not in the npm registry."
  130. ,"You should bug the author to publish it")
  131. if (er.parent) {
  132. msg.push("It was specified as a dependency of '"+er.parent+"'")
  133. }
  134. if (er.pkgid.match(/^node[\.\-]|[\.\-]js$/)) {
  135. var s = er.pkgid.replace(/^node[\.\-]|[\.\-]js$/g, "")
  136. if (s !== er.pkgid) {
  137. s = s.replace(/[^a-z0-9]/g, ' ')
  138. msg.push("\nMaybe try 'npm search " + s + "'")
  139. }
  140. }
  141. msg.push("\nNote that you can also install from a"
  142. ,"tarball, folder, or http url, or git url.")
  143. }
  144. log.error("404", msg.join("\n"))
  145. break
  146. case "EPUBLISHCONFLICT":
  147. er.code = "EPUBLISHCONFLICT"
  148. log.error("publish fail", ["Cannot publish over existing version."
  149. ,"Update the 'version' field in package.json and try again."
  150. ,""
  151. ,"If the previous version was published in error, see:"
  152. ," npm help unpublish"
  153. ,""
  154. ,"To automatically increment version numbers, see:"
  155. ," npm help version"
  156. ].join("\n"))
  157. break
  158. case "EISGIT":
  159. er.code = "EISGIT"
  160. log.error("git", [er.message
  161. ," "+er.path
  162. ,"Refusing to remove it. Update manually,"
  163. ,"or move it out of the way first."
  164. ].join("\n"))
  165. break
  166. case "ECYCLE":
  167. er.code = "ECYCLE"
  168. log.error("cycle", [er.message
  169. ,"While installing: "+er.pkgid
  170. ,"Found a pathological dependency case that npm cannot solve."
  171. ,"Please report this to the package author."
  172. ].join("\n"))
  173. break
  174. case "EBADPLATFORM":
  175. er.code = "EBADPLATFORM"
  176. log.error("notsup", [er.message
  177. ,"Not compatible with your operating system or architecture: "+er.pkgid
  178. ,"Valid OS: "+er.os.join(",")
  179. ,"Valid Arch: "+er.cpu.join(",")
  180. ,"Actual OS: "+process.platform
  181. ,"Actual Arch: "+process.arch
  182. ].join("\n"))
  183. break
  184. case "EEXIST":
  185. log.error([er.message
  186. ,"File exists: "+er.path
  187. ,"Move it away, and try again."].join("\n"))
  188. break
  189. case "ENEEDAUTH":
  190. log.error("need auth", [er.message
  191. ,"You need to authorize this machine using `npm adduser`"
  192. ].join("\n"))
  193. break
  194. case "EPEERINVALID":
  195. var peerErrors = Object.keys(er.peersDepending).map(function (peer) {
  196. return "Peer " + peer + " wants " + er.packageName + "@"
  197. + er.peersDepending[peer]
  198. })
  199. log.error("peerinvalid", [er.message].concat(peerErrors).join("\n"))
  200. break
  201. case "ECONNRESET":
  202. case "ENOTFOUND":
  203. case "ETIMEDOUT":
  204. log.error("network", [er.message
  205. ,"This is most likely not a problem with npm itself"
  206. ,"and is related to network connectivity."
  207. ,"In most cases you are behind a proxy or have bad network settings."
  208. ,"\nIf you are behind a proxy, please make sure that the"
  209. ,"'proxy' config is set properly. See: 'npm help config'"
  210. ].join("\n"))
  211. break
  212. case "ENOPACKAGEJSON":
  213. log.error("package.json", [er.message
  214. ,"This is most likely not a problem with npm itself."
  215. ,"npm can't find a package.json file in your current directory."
  216. ].join("\n"))
  217. break
  218. case "ETARGET":
  219. log.error("notarget", [er.message
  220. ,"This is most likely not a problem with npm itself."
  221. ,"In most cases you or one of your dependencies are requesting"
  222. ,"a package version that doesn't exist."
  223. ].join("\n"))
  224. break
  225. case "ENOTSUP":
  226. if (er.required) {
  227. log.error("notsup", [er.message
  228. ,"Not compatible with your version of node/npm: "+er.pkgid
  229. ,"Required: "+JSON.stringify(er.required)
  230. ,"Actual: "
  231. +JSON.stringify({npm:npm.version
  232. ,node:npm.config.get("node-version")})
  233. ].join("\n"))
  234. break
  235. } // else passthrough
  236. default:
  237. log.error("", er.stack || er.message || er)
  238. log.error("", ["If you need help, you may report this *entire* log,"
  239. ,"including the npm and node versions, at:"
  240. ," <http://github.com/npm/npm/issues>"
  241. ].join("\n"))
  242. printStack = false
  243. break
  244. }
  245. var os = require("os")
  246. // just a line break
  247. if (log.levels[log.level] <= log.levels.error) console.error("")
  248. log.error("System", os.type() + " " + os.release())
  249. log.error("command", process.argv
  250. .map(JSON.stringify).join(" "))
  251. log.error("cwd", process.cwd())
  252. log.error("node -v", process.version)
  253. log.error("npm -v", npm.version)
  254. ; [ "file"
  255. , "path"
  256. , "type"
  257. , "syscall"
  258. , "fstream_path"
  259. , "fstream_unc_path"
  260. , "fstream_type"
  261. , "fstream_class"
  262. , "fstream_finish_call"
  263. , "fstream_linkpath"
  264. , "code"
  265. , "errno"
  266. , "stack"
  267. , "fstream_stack"
  268. ].forEach(function (k) {
  269. var v = er[k]
  270. if (k === "stack") {
  271. if (!printStack) return
  272. if (!v) v = er.message
  273. }
  274. if (!v) return
  275. if (k === "fstream_stack") v = v.join("\n")
  276. log.error(k, v)
  277. })
  278. exit(typeof er.errno === "number" ? er.errno : 1)
  279. }
  280. var writingLogFile = false
  281. function writeLogFile (cb) {
  282. if (writingLogFile) return cb()
  283. writingLogFile = true
  284. wroteLogFile = true
  285. var fs = require("graceful-fs")
  286. , fstr = fs.createWriteStream("npm-debug.log")
  287. , util = require("util")
  288. , os = require("os")
  289. , out = ""
  290. log.record.forEach(function (m) {
  291. var pref = [m.id, m.level]
  292. if (m.prefix) pref.push(m.prefix)
  293. pref = pref.join(' ')
  294. m.message.trim().split(/\r?\n/).map(function (line) {
  295. return (pref + ' ' + line).trim()
  296. }).forEach(function (line) {
  297. out += line + os.EOL
  298. })
  299. })
  300. fstr.end(out)
  301. fstr.on("close", cb)
  302. }