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