Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

Commit

Permalink
Split up Writer into 3 polymorphic classes
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Nov 3, 2011
1 parent 8c740c7 commit c08551b
Show file tree
Hide file tree
Showing 4 changed files with 401 additions and 296 deletions.
133 changes: 133 additions & 0 deletions lib/dir-writer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// It is expected that, when .add() returns false, the consumer
// of the DirWriter will pause until a "drain" event occurs. Note
// that this is *almost always going to be the case*, unless the
// thing being written is some sort of unsupported type, and thus
// skipped over.

module.exports = DirWriter

var fs = require("graceful-fs")
, fstream = require("../fstream.js")
, Writer = fstream.Writer
, inherits = require("inherits")
, mkdir = require("mkdirp")
, path = require("path")
, collect = require("./collect.js")

inherits(DirWriter, Writer)

function DirWriter (props) {
var me = this
if (!(me instanceof DirWriter)) throw new Error(
"DirWriter must be called as constructor.")

// should already be established as a Directory type
if (props.type !== "Directory" || !props.Directory) {
throw new Error("Non-directory type "+ props.type)
}

Writer.call(this, props)
}

DirWriter.prototype._create = function () {
var me = this
mkdir(me.path, Writer.dirmode, function (er) {
if (er) return me.emit("error", er)
// ready to start getting entries!
me._ready = true
me.emit("ready")
})
}

// a DirWriter has an add(entry) method, but its .write() doesn't
// do anything. Why a no-op rather than a throw? Because this
// leaves open the door for writing directory metadata for
// gnu/solaris style dumpdirs.
DirWriter.prototype.write = function () {
return true
}

DirWriter.prototype.end = function () {
this._ended = true
this._process()
}

DirWriter.prototype.add = function (entry) {
var me = this
collect(entry)
if (!me._ready || me._currentEntry) {
me._buffer.push(entry)
return false
}

// create a new writer, and pipe the incoming entry into it.
if (me._ended) {
return me.emit("error", new Error("add after end"))
}

me._buffer.push(entry)
me._process()

return false
}

DirWriter.prototype._process = function () {
var me = this
if (me._processing) return

var entry = me._buffer.shift()
if (!entry) {
me.emit("drain")
if (me._ended) me._finish()
return
}

me._processing = true

// ok, add this entry
//
// don't allow recursive copying
var p = entry
do {
if (p.path === me.path) {
me._processing = false
return me._process()
}
} while (p = p.parent)

// chop off the entry's root dir, replace with ours
var opts = { parent: me
, root: me.root || me
, type: entry.type
, depth: me.depth + 1 }

var p = entry.path || entry.props.path
, root = entry.root || entry.parent
if (root) {
p = p.substr(root.path.length + 1)
}
opts.path = path.join(me.path, path.join("/", p))

// all the rest of the stuff, copy over from the source.
Object.keys(entry.props).forEach(function (k) {
if (!opts.hasOwnProperty(k)) {
opts[k] = entry.props[k]
}
})

// not sure at this point what kind of writer this is.
var child = me._currentChild = new Writer(opts)
child.on("ready", function () {
entry.pipe(child)
})

child.on("end", onend)
child.on("close", onend)
function onend () {
if (me._currentChild !== child) return
console.error(" end", child.path)
me._currentChild = null
me._processing = false
me._process()
}
}
70 changes: 70 additions & 0 deletions lib/file-writer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
module.exports = FileWriter

var fs = require("graceful-fs")
, mkdir = require("mkdirp")
, fstream = require("../fstream.js")
, Writer = fstream.Writer
, inherits = require("inherits")

inherits(FileWriter, Writer)

function FileWriter (props) {
var me = this
if (!(me instanceof FileWriter)) throw new Error(
"FileWriter must be called as constructor.")

// should already be established as a Directory type
if (props.type !== "File" || !props.Directory) {
throw new Error("Non-file type "+ props.type)
}

me._bytesWritten = 0

Writer.call(this, props)
}

FileWriter.prototype._create = function () {
var me = this

// should always chmod explicitly.
me.props.mode = me.props.mode || Writer.filemode

me._stream = fs.createWriteStream(me.path, me.props)

me._stream.on("open", function (fd) {
me._ready = true
me.emit("ready")
})

me._stream.on("drain", function () { me.emit("drain") })

me._stream.on("close", function () {
me._finish()
})
}

FileWriter.prototype.write = function (c) {
me._bytesWritten += c.length

var me = this
, ret = me._stream.write(c)
// allow 2 buffered writes, because otherwise there's just too
// much stop and go bs.
return ret || (me._stream._queue && me._stream._queue.length <= 2)
}

FileWriter.prototype.end = function (c) {
var me = this
me._stream.end()
}

FileWriter.prototype._finish = function () {
var me = this
if (typeof me.size === "number" && me._bytesWritten != me.size) {
me.emit("error", new Error(
"Did not get expected number of bytes.\n" +
"expect: " + me.size + "\n" +
"actual: " + me._bytesWritten))
}
Writer.prototype._finish.call(me)
}
43 changes: 43 additions & 0 deletions lib/link-writer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

module.exports = LinkWriter

var fs = require("graceful-fs")
, fstream = require("../fstream.js")
, Writer = fstream.Writer
, inherits = require("inherits")
, collect = require("./collect.js")

inherits(LinkWriter, Writer)

function LinkWriter (props) {
var me = this
if (!(me instanceof LinkWriter)) throw new Error(
"LinkWriter must be called as constructor.")

// should already be established as a Link type
if (!(props.type === "Link" && props.Link) ||
!(props.type === "SymbolicLink" && props.SymbolicLink)) {
throw new Error("Non-link type "+ props.type)
}

if (!props.linkpath) {
me.emit("error", new Error(
"Need linkpath property to create " + props.type))
}

Writer.call(this, props)
}

LinkWriter.prototype._create = function () {
var me = this
, link = me.type === "Link" ? "link" : "symlink"
fs[link](me.linkpath, me.path, function (er) {
if (er) return me.emit("error", er)
me._ready = true
me.emit("ready")
})
}

LinkWriter.prototype.end = function () {
this._finish()
}
Loading

0 comments on commit c08551b

Please sign in to comment.