| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 | // 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 = DirWritervar Writer = require('./writer.js')var inherits = require('inherits')var mkdir = require('mkdirp')var path = require('path')var collect = require('./collect.js')inherits(DirWriter, Writer)function DirWriter (props) {  var self = this  if (!(self instanceof DirWriter)) {    self.error('DirWriter must be called as constructor.', null, true)  }  // should already be established as a Directory type  if (props.type !== 'Directory' || !props.Directory) {    self.error('Non-directory type ' + props.type + ' ' +      JSON.stringify(props), null, true)  }  Writer.call(this, props)}DirWriter.prototype._create = function () {  var self = this  mkdir(self._path, Writer.dirmode, function (er) {    if (er) return self.error(er)    // ready to start getting entries!    self.ready = true    self.emit('ready')    self._process()  })}// 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 self = this  // console.error('\tadd', entry._path, '->', self._path)  collect(entry)  if (!self.ready || self._currentEntry) {    self._buffer.push(entry)    return false  }  // create a new writer, and pipe the incoming entry into it.  if (self._ended) {    return self.error('add after end')  }  self._buffer.push(entry)  self._process()  return this._buffer.length === 0}DirWriter.prototype._process = function () {  var self = this  // console.error('DW Process p=%j', self._processing, self.basename)  if (self._processing) return  var entry = self._buffer.shift()  if (!entry) {    // console.error("DW Drain")    self.emit('drain')    if (self._ended) self._finish()    return  }  self._processing = true  // console.error("DW Entry", entry._path)  self.emit('entry', entry)  // ok, add this entry  //  // don't allow recursive copying  var p = entry  var pp  do {    pp = p._path || p.path    if (pp === self.root._path || pp === self._path ||      (pp && pp.indexOf(self._path) === 0)) {      // console.error('DW Exit (recursive)', entry.basename, self._path)      self._processing = false      if (entry._collected) entry.pipe()      return self._process()    }    p = p.parent  } while (p)  // console.error("DW not recursive")  // chop off the entry's root dir, replace with ours  var props = {    parent: self,    root: self.root || self,    type: entry.type,    depth: self.depth + 1  }  pp = entry._path || entry.path || entry.props.path  if (entry.parent) {    pp = pp.substr(entry.parent._path.length + 1)  }  // get rid of any ../../ shenanigans  props.path = path.join(self.path, path.join('/', pp))  // if i have a filter, the child should inherit it.  props.filter = self.filter  // all the rest of the stuff, copy over from the source.  Object.keys(entry.props).forEach(function (k) {    if (!props.hasOwnProperty(k)) {      props[k] = entry.props[k]    }  })  // not sure at this point what kind of writer this is.  var child = self._currentChild = new Writer(props)  child.on('ready', function () {    // console.error("DW Child Ready", child.type, child._path)    // console.error("  resuming", entry._path)    entry.pipe(child)    entry.resume()  })  // XXX Make this work in node.  // Long filenames should not break stuff.  child.on('error', function (er) {    if (child._swallowErrors) {      self.warn(er)      child.emit('end')      child.emit('close')    } else {      self.emit('error', er)    }  })  // we fire _end internally *after* end, so that we don't move on  // until any "end" listeners have had their chance to do stuff.  child.on('close', onend)  var ended = false  function onend () {    if (ended) return    ended = true    // console.error("* DW Child end", child.basename)    self._currentChild = null    self._processing = false    self._process()  }}
 |