node/deps/npm/lib/utils/output.js
isaacs 01d146c29f Merge remote-tracking branch 'ry/v0.6' into v0.6-merge
Conflicts:
	ChangeLog
	Makefile
	deps/npm/AUTHORS
	deps/npm/html/api/bin.html
	deps/npm/html/api/bugs.html
	deps/npm/html/api/commands.html
	deps/npm/html/api/config.html
	deps/npm/html/api/deprecate.html
	deps/npm/html/api/docs.html
	deps/npm/html/api/edit.html
	deps/npm/html/api/explore.html
	deps/npm/html/api/help-search.html
	deps/npm/html/api/init.html
	deps/npm/html/api/install.html
	deps/npm/html/api/link.html
	deps/npm/html/api/load.html
	deps/npm/html/api/ls.html
	deps/npm/html/api/npm.html
	deps/npm/html/api/outdated.html
	deps/npm/html/api/owner.html
	deps/npm/html/api/pack.html
	deps/npm/html/api/prefix.html
	deps/npm/html/api/prune.html
	deps/npm/html/api/publish.html
	deps/npm/html/api/rebuild.html
	deps/npm/html/api/restart.html
	deps/npm/html/api/root.html
	deps/npm/html/api/run-script.html
	deps/npm/html/api/search.html
	deps/npm/html/api/shrinkwrap.html
	deps/npm/html/api/start.html
	deps/npm/html/api/stop.html
	deps/npm/html/api/submodule.html
	deps/npm/html/api/tag.html
	deps/npm/html/api/test.html
	deps/npm/html/api/uninstall.html
	deps/npm/html/api/unpublish.html
	deps/npm/html/api/update.html
	deps/npm/html/api/version.html
	deps/npm/html/api/view.html
	deps/npm/html/api/whoami.html
	deps/npm/html/doc/README.html
	deps/npm/html/doc/adduser.html
	deps/npm/html/doc/bin.html
	deps/npm/html/doc/bugs.html
	deps/npm/html/doc/build.html
	deps/npm/html/doc/bundle.html
	deps/npm/html/doc/cache.html
	deps/npm/html/doc/changelog.html
	deps/npm/html/doc/coding-style.html
	deps/npm/html/doc/completion.html
	deps/npm/html/doc/config.html
	deps/npm/html/doc/deprecate.html
	deps/npm/html/doc/developers.html
	deps/npm/html/doc/disputes.html
	deps/npm/html/doc/docs.html
	deps/npm/html/doc/edit.html
	deps/npm/html/doc/explore.html
	deps/npm/html/doc/faq.html
	deps/npm/html/doc/folders.html
	deps/npm/html/doc/help-search.html
	deps/npm/html/doc/help.html
	deps/npm/html/doc/index.html
	deps/npm/html/doc/init.html
	deps/npm/html/doc/install.html
	deps/npm/html/doc/json.html
	deps/npm/html/doc/link.html
	deps/npm/html/doc/list.html
	deps/npm/html/doc/npm.html
	deps/npm/html/doc/outdated.html
	deps/npm/html/doc/owner.html
	deps/npm/html/doc/pack.html
	deps/npm/html/doc/prefix.html
	deps/npm/html/doc/prune.html
	deps/npm/html/doc/publish.html
	deps/npm/html/doc/rebuild.html
	deps/npm/html/doc/registry.html
	deps/npm/html/doc/removing-npm.html
	deps/npm/html/doc/restart.html
	deps/npm/html/doc/root.html
	deps/npm/html/doc/run-script.html
	deps/npm/html/doc/scripts.html
	deps/npm/html/doc/search.html
	deps/npm/html/doc/semver.html
	deps/npm/html/doc/shrinkwrap.html
	deps/npm/html/doc/star.html
	deps/npm/html/doc/start.html
	deps/npm/html/doc/stop.html
	deps/npm/html/doc/submodule.html
	deps/npm/html/doc/tag.html
	deps/npm/html/doc/test.html
	deps/npm/html/doc/uninstall.html
	deps/npm/html/doc/unpublish.html
	deps/npm/html/doc/update.html
	deps/npm/html/doc/version.html
	deps/npm/html/doc/view.html
	deps/npm/html/doc/whoami.html
	deps/npm/man/man1/npm.1
	deps/npm/man/man3/npm.3
	deps/npm/package.json
	doc/api/url.markdown
	lib/http.js
	src/node_version.h
	test/simple/test-fs-sync-fd-leak.js
2012-05-04 15:12:47 -07:00

157 lines
3.9 KiB
JavaScript

// centralized stdout writer.
exports.doColor = doColor
exports.write = write
var npm = require("../npm.js")
, tty = require("tty")
, streams = {}
, ttys = {}
, net = require("net")
, util = require("util")
, deadStreams = {}
function doColor (stream) {
var conf = npm.config.get("color")
return (!conf) ? false
: (conf === "always") ? true
: isatty(stream)
}
function isatty (stream) {
// console.error("isatty?", stream)
if (!tty.isatty) return true
if (!stream) return false
if (stream.isTTY) return true
if (stream && (typeof stream.fd === "number")) {
stream.isTTY = tty.isatty(stream.fd)
}
return stream.isTTY
}
function write (args, stream, lf, cb) {
// console.error("write", [args, stream, lf, cb])
if (typeof cb !== "function" && typeof lf === "function") {
cb = lf
lf = null
}
if (typeof cb !== "function" && typeof stream === "function") {
cb = stream
stream = npm.config.get("outfd")
}
stream = getStream(stream)
// console.error("gotStream", stream)
if (lf == null) lf = isatty(stream)
if (!stream) return cb && cb(), false
if (!Array.isArray(args)) args = [args]
// console.error("write", args)
var msg = ""
, colored = doColor(stream)
msg = args.map(function (arg) {
if (typeof arg !== "string") {
return util.inspect(arg, false, 5, colored) + "\n"
}
if (!colored) arg = arg.replace(/\033\[[0-9;]*m/g, '')
if (!npm.config.get("unicode")) {
arg = arg.replace(/└/g, "`")
.replace(/─/g, "-")
.replace(/├/g, "+")
.replace(/┬/g, "-")
}
return arg
}).join(" ")
// listen to the "output" event to cancel/modify/redirect
npm.output = {stream:stream, message:msg}
npm.emit("output", npm.output)
if (!npm.output) return cb && cb(), false // cancelled
stream = npm.output.stream
msg = npm.output.message
// EPIPE errors just mean that the stream is not listening
// any more. Mark the stream as dead, and return.
if (deadStreams[stream.fd]) {
return cb && cb(), false
}
if (!deadStreams.hasOwnProperty(stream.fd)) {
deadStreams[stream.fd] = false
stream.on("error", function (er) {
if (er.code === "EPIPE") {
deadStreams[stream.fd] = true
return cb && cb()
}
if (stream.listeners("error").length === 1) {
throw er
}
})
}
// use the \r\n in case we're in raw mode.
msg = msg.split(/\r?\n/).concat("").join(lf ? "\r\n" : "\n")
// output to stderr should be synchronous
if (stream === process.stderr || stream.fd === 2) {
process.stderr.write(msg)
if (cb) cb()
return true
}
// console.error("writing ", msg)
var flushed = stream.write(msg)
if (flushed && cb) {
process.nextTick(cb)
} else if (cb) {
stream.once("drain", cb)
}
return flushed
}
var hadError = false
function getStream (fd) {
if (hadError) return
var stream
if (!fd && fd !== 0) return
if (typeof fd === "string") fd = +fd
// console.error("getStream", fd, hadError)
if (fd && typeof fd === "object") {
stream = fd
fd = fd.fd
} else if (streams[fd]) {
stream = streams[fd]
} else {
switch (fd) {
case 1:
stream = process.stdout
stream.fd = fd
stream.writable = true
break
case 2:
stream = process.stderr
stream.fd = fd
stream.writable = true
break
default:
try {
stream = new net.Stream(fd)
if (!stream || !stream.writable) {
throw new Error("Stream not writable")
}
} catch (ex) {
// if this fails, then regular logging is most likely broken.
var er = new Error("cannot output to fd "+fd + ": "+
(ex.stack || ex.message).substr(7) + "\n")
console.error(er.stack)
hadError = true
process.exit(1)
}
}
}
if (!stream || !stream.writable) return
return streams[fd] = stream
}