You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							236 lines
						
					
					
						
							5.6 KiB
						
					
					
				
			
		
		
	
	
							236 lines
						
					
					
						
							5.6 KiB
						
					
					
				// pipe in an fstream, and it'll make a tarball. | 
						|
// key-value pair argument is global extended header props. | 
						|
 | 
						|
module.exports = Pack | 
						|
 | 
						|
var EntryWriter = require("./entry-writer.js") | 
						|
  , Stream = require("stream").Stream | 
						|
  , path = require("path") | 
						|
  , inherits = require("inherits") | 
						|
  , GlobalHeaderWriter = require("./global-header-writer.js") | 
						|
  , collect = require("fstream").collect | 
						|
  , eof = new Buffer(512) | 
						|
 | 
						|
for (var i = 0; i < 512; i ++) eof[i] = 0 | 
						|
 | 
						|
inherits(Pack, Stream) | 
						|
 | 
						|
function Pack (props) { | 
						|
  // console.error("-- p ctor") | 
						|
  var me = this | 
						|
  if (!(me instanceof Pack)) return new Pack(props) | 
						|
 | 
						|
  if (props) me._noProprietary = props.noProprietary | 
						|
  else me._noProprietary = false | 
						|
 | 
						|
  me._global = props | 
						|
 | 
						|
  me.readable = true | 
						|
  me.writable = true | 
						|
  me._buffer = [] | 
						|
  // console.error("-- -- set current to null in ctor") | 
						|
  me._currentEntry = null | 
						|
  me._processing = false | 
						|
 | 
						|
  me._pipeRoot = null | 
						|
  me.on("pipe", function (src) { | 
						|
    if (src.root === me._pipeRoot) return | 
						|
    me._pipeRoot = src | 
						|
    src.on("end", function () { | 
						|
      me._pipeRoot = null | 
						|
    }) | 
						|
    me.add(src) | 
						|
  }) | 
						|
} | 
						|
 | 
						|
Pack.prototype.addGlobal = function (props) { | 
						|
  // console.error("-- p addGlobal") | 
						|
  if (this._didGlobal) return | 
						|
  this._didGlobal = true | 
						|
 | 
						|
  var me = this | 
						|
  GlobalHeaderWriter(props) | 
						|
    .on("data", function (c) { | 
						|
      me.emit("data", c) | 
						|
    }) | 
						|
    .end() | 
						|
} | 
						|
 | 
						|
Pack.prototype.add = function (stream) { | 
						|
  if (this._global && !this._didGlobal) this.addGlobal(this._global) | 
						|
 | 
						|
  if (this._ended) return this.emit("error", new Error("add after end")) | 
						|
 | 
						|
  collect(stream) | 
						|
  this._buffer.push(stream) | 
						|
  this._process() | 
						|
  this._needDrain = this._buffer.length > 0 | 
						|
  return !this._needDrain | 
						|
} | 
						|
 | 
						|
Pack.prototype.pause = function () { | 
						|
  this._paused = true | 
						|
  if (this._currentEntry) this._currentEntry.pause() | 
						|
  this.emit("pause") | 
						|
} | 
						|
 | 
						|
Pack.prototype.resume = function () { | 
						|
  this._paused = false | 
						|
  if (this._currentEntry) this._currentEntry.resume() | 
						|
  this.emit("resume") | 
						|
  this._process() | 
						|
} | 
						|
 | 
						|
Pack.prototype.end = function () { | 
						|
  this._ended = true | 
						|
  this._buffer.push(eof) | 
						|
  this._process() | 
						|
} | 
						|
 | 
						|
Pack.prototype._process = function () { | 
						|
  var me = this | 
						|
  if (me._paused || me._processing) { | 
						|
    return | 
						|
  } | 
						|
 | 
						|
  var entry = me._buffer.shift() | 
						|
 | 
						|
  if (!entry) { | 
						|
    if (me._needDrain) { | 
						|
      me.emit("drain") | 
						|
    } | 
						|
    return | 
						|
  } | 
						|
 | 
						|
  if (entry.ready === false) { | 
						|
    // console.error("-- entry is not ready", entry) | 
						|
    me._buffer.unshift(entry) | 
						|
    entry.on("ready", function () { | 
						|
      // console.error("-- -- ready!", entry) | 
						|
      me._process() | 
						|
    }) | 
						|
    return | 
						|
  } | 
						|
 | 
						|
  me._processing = true | 
						|
 | 
						|
  if (entry === eof) { | 
						|
    // need 2 ending null blocks. | 
						|
    me.emit("data", eof) | 
						|
    me.emit("data", eof) | 
						|
    me.emit("end") | 
						|
    me.emit("close") | 
						|
    return | 
						|
  } | 
						|
 | 
						|
  // Change the path to be relative to the root dir that was | 
						|
  // added to the tarball. | 
						|
  // | 
						|
  // XXX This should be more like how -C works, so you can | 
						|
  // explicitly set a root dir, and also explicitly set a pathname | 
						|
  // in the tarball to use.  That way we can skip a lot of extra | 
						|
  // work when resolving symlinks for bundled dependencies in npm. | 
						|
 | 
						|
  var root = path.dirname((entry.root || entry).path); | 
						|
  if (me._global && me._global.fromBase && entry.root && entry.root.path) { | 
						|
    // user set 'fromBase: true' indicating tar root should be directory itself | 
						|
    root = entry.root.path; | 
						|
  } | 
						|
 | 
						|
  var wprops = {} | 
						|
 | 
						|
  Object.keys(entry.props || {}).forEach(function (k) { | 
						|
    wprops[k] = entry.props[k] | 
						|
  }) | 
						|
 | 
						|
  if (me._noProprietary) wprops.noProprietary = true | 
						|
 | 
						|
  wprops.path = path.relative(root, entry.path || '') | 
						|
 | 
						|
  // actually not a matter of opinion or taste. | 
						|
  if (process.platform === "win32") { | 
						|
    wprops.path = wprops.path.replace(/\\/g, "/") | 
						|
  } | 
						|
 | 
						|
  if (!wprops.type) | 
						|
    wprops.type = 'Directory' | 
						|
 | 
						|
  switch (wprops.type) { | 
						|
    // sockets not supported | 
						|
    case "Socket": | 
						|
      return | 
						|
 | 
						|
    case "Directory": | 
						|
      wprops.path += "/" | 
						|
      wprops.size = 0 | 
						|
      break | 
						|
 | 
						|
    case "Link": | 
						|
      var lp = path.resolve(path.dirname(entry.path), entry.linkpath) | 
						|
      wprops.linkpath = path.relative(root, lp) || "." | 
						|
      wprops.size = 0 | 
						|
      break | 
						|
 | 
						|
    case "SymbolicLink": | 
						|
      var lp = path.resolve(path.dirname(entry.path), entry.linkpath) | 
						|
      wprops.linkpath = path.relative(path.dirname(entry.path), lp) || "." | 
						|
      wprops.size = 0 | 
						|
      break | 
						|
  } | 
						|
 | 
						|
  // console.error("-- new writer", wprops) | 
						|
  // if (!wprops.type) { | 
						|
  //   // console.error("-- no type?", entry.constructor.name, entry) | 
						|
  // } | 
						|
 | 
						|
  // console.error("-- -- set current to new writer", wprops.path) | 
						|
  var writer = me._currentEntry = EntryWriter(wprops) | 
						|
 | 
						|
  writer.parent = me | 
						|
 | 
						|
  // writer.on("end", function () { | 
						|
  //   // console.error("-- -- writer end", writer.path) | 
						|
  // }) | 
						|
 | 
						|
  writer.on("data", function (c) { | 
						|
    me.emit("data", c) | 
						|
  }) | 
						|
 | 
						|
  writer.on("header", function () { | 
						|
    Buffer.prototype.toJSON = function () { | 
						|
      return this.toString().split(/\0/).join(".") | 
						|
    } | 
						|
    // console.error("-- -- writer header %j", writer.props) | 
						|
    if (writer.props.size === 0) nextEntry() | 
						|
  }) | 
						|
  writer.on("close", nextEntry) | 
						|
 | 
						|
  var ended = false | 
						|
  function nextEntry () { | 
						|
    if (ended) return | 
						|
    ended = true | 
						|
 | 
						|
    // console.error("-- -- writer close", writer.path) | 
						|
    // console.error("-- -- set current to null", wprops.path) | 
						|
    me._currentEntry = null | 
						|
    me._processing = false | 
						|
    me._process() | 
						|
  } | 
						|
 | 
						|
  writer.on("error", function (er) { | 
						|
    // console.error("-- -- writer error", writer.path) | 
						|
    me.emit("error", er) | 
						|
  }) | 
						|
 | 
						|
  // if it's the root, then there's no need to add its entries, | 
						|
  // or data, since they'll be added directly. | 
						|
  if (entry === me._pipeRoot) { | 
						|
    // console.error("-- is the root, don't auto-add") | 
						|
    writer.add = null | 
						|
  } | 
						|
 | 
						|
  entry.pipe(writer) | 
						|
} | 
						|
 | 
						|
Pack.prototype.destroy = function () {} | 
						|
Pack.prototype.write = function () {}
 | 
						|
 |