Comparing version
@@ -18,3 +18,4 @@ /** | ||
options = this.options = util.defaults(options, { | ||
highWaterMark: 1024 * 1024 | ||
highWaterMark: 1024 * 1024, | ||
statConcurrency: 4 | ||
}); | ||
@@ -31,4 +32,8 @@ | ||
this._statQueue = async.queue(this._onStatQueueTask.bind(this), options.statConcurrency); | ||
this._state = { | ||
aborted: false, | ||
finalize: false, | ||
finalizing: false, | ||
finalized: false, | ||
@@ -41,5 +46,16 @@ modulePiped: false | ||
Archiver.prototype._abort = function() { | ||
this._queue.kill(); | ||
this._statQueue.kill(); | ||
this._state.aborted = true; | ||
}; | ||
Archiver.prototype._append = function(filepath, data) { | ||
data = data || {}; | ||
var task = { | ||
source: null, | ||
filepath: filepath | ||
}; | ||
if (!data.name) { | ||
@@ -50,9 +66,10 @@ data.name = filepath; | ||
data.sourcePath = filepath; | ||
task.data = data; | ||
this._queue.push({ | ||
data: data, | ||
source: null, | ||
deferredStat: true, | ||
filepath: filepath | ||
}); | ||
if (data.stats && data.stats instanceof fs.Stats) { | ||
task = this._updateQueueTaskWithStats(task, data.stats); | ||
this._queue.push(task); | ||
} else { | ||
this._statQueue.push(task); | ||
} | ||
}; | ||
@@ -65,3 +82,3 @@ | ||
Archiver.prototype._moduleFinalize = function() { | ||
this._state.finalized = true; | ||
this._state.finalizing = true; | ||
@@ -75,2 +92,5 @@ if (typeof this._module.finalize === 'function') { | ||
} | ||
this._state.finalizing = false; | ||
this._state.finalized = true; | ||
}; | ||
@@ -87,3 +107,2 @@ | ||
Archiver.prototype._normalizeEntryData = function(data, stats) { | ||
stats = stats || false; | ||
data = util.defaults(data, { | ||
@@ -94,5 +113,10 @@ type: 'file', | ||
mode: null, | ||
sourcePath: null | ||
sourcePath: null, | ||
stats: false | ||
}); | ||
if (stats && data.stats === false) { | ||
data.stats = stats; | ||
} | ||
var isDir = data.type === 'directory'; | ||
@@ -113,16 +137,14 @@ | ||
data.mode &= 0777; | ||
} else if (stats) { | ||
data.mode = stats.mode & 0777; | ||
} else { | ||
} else if (data.stats && data.mode === null) { | ||
data.mode = data.stats.mode & 0777; | ||
} else if (data.mode === null) { | ||
data.mode = isDir ? 0755 : 0644; | ||
} | ||
if (stats && data.date === null) { | ||
data.date = stats.mtime; | ||
if (data.stats && data.date === null) { | ||
data.date = data.stats.mtime; | ||
} else { | ||
data.date = util.dateify(data.date); | ||
} | ||
data.date = util.dateify(data.date); | ||
data._stats = stats; | ||
return data; | ||
@@ -136,3 +158,7 @@ }; | ||
Archiver.prototype._onQueueDrain = function() { | ||
if (this._state.finalize && !this._state.finalized && this._queue.idle()) { | ||
if (this._state.finalizing || this._state.finalized || this._state.aborted) { | ||
return; | ||
} | ||
if (this._state.finalize && this._queue.idle() && this._statQueue.idle()) { | ||
this._moduleFinalize(); | ||
@@ -143,3 +169,7 @@ } | ||
Archiver.prototype._onQueueTask = function(task, callback) { | ||
var afterAppend = function(err, entry) { | ||
this._task = task; | ||
this._moduleAppend(task.source, task.data, function(err, entry) { | ||
this._task = null; | ||
if (err) { | ||
@@ -157,5 +187,7 @@ this.emit('error', err); | ||
callback(); | ||
}.bind(this); | ||
}.bind(this)); | ||
}; | ||
var afterStat = function(err, stats) { | ||
Archiver.prototype._onStatQueueTask = function(task, callback) { | ||
fs.stat(task.filepath, function(err, stats) { | ||
if (err) { | ||
@@ -170,3 +202,4 @@ this.emit('error', err); | ||
if (task.source !== null) { | ||
this._moduleAppend(task.source, task.data, afterAppend); | ||
this._queue.push(task); | ||
callback(); | ||
} else { | ||
@@ -177,9 +210,3 @@ this.emit('error', new Error('unsupported entry: ' + task.filepath)); | ||
} | ||
}.bind(this); | ||
if (task.deferredStat) { | ||
fs.stat(task.filepath, afterStat); | ||
} else { | ||
this._moduleAppend(task.source, task.data, afterAppend); | ||
} | ||
}.bind(this)); | ||
}; | ||
@@ -225,5 +252,21 @@ | ||
Archiver.prototype.abort = function() { | ||
if (this._state.aborted) { | ||
this.emit('error', new Error('abort: already aborted')); | ||
return this; | ||
} | ||
if (this._state.finalized) { | ||
this.emit('error', new Error('abort: already finalized')); | ||
return this; | ||
} | ||
this._abort(); | ||
return this; | ||
}; | ||
Archiver.prototype.append = function(source, data) { | ||
if (this._state.finalize) { | ||
this.emit('error', new Error('unable to append after calling finalize.')); | ||
if (this._state.finalize || this._state.aborted) { | ||
this.emit('error', new Error('append: queue closed')); | ||
return this; | ||
@@ -235,3 +278,3 @@ } | ||
if (typeof data.name !== 'string' || data.name.length === 0) { | ||
this.emit('error', new Error('entry name must be a non-empty string value')); | ||
this.emit('error', new Error('append: entry name must be a non-empty string value')); | ||
return this; | ||
@@ -241,3 +284,3 @@ } | ||
if (data.type === 'directory' && !this._moduleSupports('directory')) { | ||
this.emit('error', new Error('entries of "directory" type not currently supported by this module')); | ||
this.emit('error', new Error('append: entries of "directory" type not currently supported by this module')); | ||
return this; | ||
@@ -253,3 +296,3 @@ } | ||
} else { | ||
this.emit('error', new Error('input source must be valid Stream or Buffer instance')); | ||
this.emit('error', new Error('append: input source must be valid Stream or Buffer instance')); | ||
return this; | ||
@@ -267,4 +310,4 @@ } | ||
Archiver.prototype.bulk = function(mappings) { | ||
if (this._state.finalize) { | ||
this.emit('error', new Error('unable to append after calling finalize.')); | ||
if (this._state.finalize || this._state.aborted) { | ||
this.emit('error', new Error('bulk: queue closed')); | ||
return this; | ||
@@ -301,4 +344,4 @@ } | ||
Archiver.prototype.file = function(filepath, data) { | ||
if (this._state.finalize) { | ||
this.emit('error', new Error('unable to append after calling finalize.')); | ||
if (this._state.finalize || this._state.aborted) { | ||
this.emit('error', new Error('file: queue closed')); | ||
return this; | ||
@@ -308,3 +351,3 @@ } | ||
if (typeof filepath !== 'string' || filepath.length === 0) { | ||
this.emit('error', new Error('filepath must be a non-empty string value')); | ||
this.emit('error', new Error('file: filepath must be a non-empty string value')); | ||
return this; | ||
@@ -319,5 +362,15 @@ } | ||
Archiver.prototype.finalize = function() { | ||
if (this._state.aborted) { | ||
this.emit('error', new Error('finalize: archive was aborted')); | ||
return this; | ||
} | ||
if (this._state.finalize) { | ||
this.emit('error', new Error('finalize: archive already finalizing')); | ||
return this; | ||
} | ||
this._state.finalize = true; | ||
if (this._queue.idle()) { | ||
if (this._queue.idle() && this._statQueue.idle()) { | ||
this._moduleFinalize(); | ||
@@ -330,4 +383,9 @@ } | ||
Archiver.prototype.setModule = function(module) { | ||
if (this._state.aborted) { | ||
this.emit('error', new Error('module: archive was aborted')); | ||
return this; | ||
} | ||
if (this._state.modulePiped) { | ||
this.emit('error', new Error('format module already set')); | ||
this.emit('error', new Error('module: module already set')); | ||
return; | ||
@@ -334,0 +392,0 @@ } |
{ | ||
"name": "archiver", | ||
"version": "0.11.0", | ||
"version": "0.12.0", | ||
"description": "a streaming interface for archive generation", | ||
@@ -38,7 +38,7 @@ "homepage": "https://github.com/ctalkington/node-archiver", | ||
"buffer-crc32": "~0.2.1", | ||
"glob": "~3.2.6", | ||
"glob": "~4.0.6", | ||
"lazystream": "~0.1.0", | ||
"lodash": "~2.4.1", | ||
"readable-stream": "~1.0.26", | ||
"tar-stream": "~0.4.0", | ||
"tar-stream": "~1.0.0", | ||
"zip-stream": "~0.4.0" | ||
@@ -48,3 +48,3 @@ }, | ||
"chai": "~1.9.1", | ||
"mocha": "~1.20.1", | ||
"mocha": "~2.0.1", | ||
"rimraf": "~2.2.8", | ||
@@ -51,0 +51,0 @@ "mkdirp": "~0.5.0", |
@@ -1,2 +0,2 @@ | ||
# Archiver v0.11.0 [](https://travis-ci.org/ctalkington/node-archiver) | ||
# Archiver v0.12.0 [](https://travis-ci.org/ctalkington/node-archiver) | ||
@@ -29,2 +29,6 @@ a streaming interface for archive generation | ||
#### abort() | ||
Aborts the archiving process by clearing the remaining queue. The instance will remain available in a read-only state. | ||
#### append(input, data) | ||
@@ -94,5 +98,5 @@ | ||
#### forceUTC `boolean` | ||
#### statConcurrency `number` | ||
If true, forces the entry date to UTC. Helps with testing across timezones. | ||
Sets the number of workers used to process the internal fs stat queue. Defaults to 4. | ||
@@ -117,2 +121,4 @@ #### store `boolean` | ||
When using the `bulk` or `file` methods, fs stat data is used as the default value. | ||
#### store `boolean` | ||
@@ -130,2 +136,8 @@ | ||
When using the `bulk` or `file` methods, fs stat data is used as the default value. | ||
#### stats `fs.Stats` | ||
Sets the fs stat data for this entry. This allows for reduction of fs stat calls when stat data is already known. | ||
## Tar | ||
@@ -143,2 +155,6 @@ | ||
#### statConcurrency `number` | ||
Sets the number of workers used to process the internal fs stat queue. Defaults to 4. | ||
### Entry Data | ||
@@ -154,2 +170,4 @@ | ||
When using the `bulk` or `file` methods, fs stat data is used as the default value. | ||
#### mode `number` | ||
@@ -159,2 +177,8 @@ | ||
When using the `bulk` or `file` methods, fs stat data is used as the default value. | ||
#### stats `fs.Stats` | ||
Sets the fs stat data for this entry. This allows for reduction of fs stat calls when stat data is already known. | ||
## Libraries | ||
@@ -161,0 +185,0 @@ |
32933
7.9%746
6.57%190
14.46%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
Updated
Updated