Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ lib-cov
*.out
*.pid
*.gz
*.idea

pids
logs
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
language: node_js
node_js:
- 0.10
- '4.0'
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ been saved to disk.
* `saveTo` A path to save the buffer to.
* `filter` A function that is called for all items to determine whether or not they should be added to the zip buffer. Function is called with the `fullPath` and a `stats` object ([fs.Stats](http://nodejs.org/api/fs.html#fs_class_fs_stats)). Return true to add the item; false otherwise. To include files within directories, directories must also pass this filter.
* `each` A function that is called everytime a file or directory is added to the zip.

## TODO

* Add an option to not add empty directories if there are no valid children inside
* `noEmptyDirectories` disallow empty directories from being zipped. If the root directory is empty an error will be thrown.

## license

Expand Down
25 changes: 23 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ var Zip = require('jszip');
// Limiting the number of files read at the same time
var maxOpenFiles = 500;

//Error Message
var ROOTDIR_CANNOT_BE_EMPTY = 'Cannot have an empty root directory';

module.exports = function zipWrite (rootDir, options, callback) {
if (!callback) {
callback = options;
Expand All @@ -20,7 +23,9 @@ module.exports = function zipWrite (rootDir, options, callback) {
options = options || {};

zipBuffer(rootDir, options, function (err, buffer) {
if (options.saveTo) {
if(err){
callback(err, null);
} else if (options.saveTo) {
fs.writeFile(options.saveTo, buffer, { encoding: 'binary' }, function (err) {
callback(err, buffer);
});
Expand All @@ -36,6 +41,8 @@ function zipBuffer (rootDir, options, callback) {
// Resolve the path so we can remove trailing slash if provided
rootDir = path.resolve(rootDir);

folders['rootDir'] = rootDir;

folders[rootDir] = zip;

dive(rootDir, function (err) {
Expand All @@ -50,7 +57,21 @@ function zipBuffer (rootDir, options, callback) {
function dive (dir, callback) {
fs.readdir(dir, function (err, files) {
if (err) return callback(err);
if (!files.length) return callback();
if(!files.length){
if(folders.rootDir === dir && options.noEmptyDirectories){
return callback(ROOTDIR_CANNOT_BE_EMPTY)
} else if(options.noEmptyDirectories){
var rootDir = dir.substring(0, dir.lastIndexOf('/'));
var baseName = path.basename(dir);
var parentZip = folders[rootDir];
if(parentZip){
parentZip.remove(baseName);
}
return callback();
} else {
return callback();
}
}
var count = files.length;
files.forEach(function (file) {
var fullPath = path.resolve(dir, file);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zip-dir",
"version": "1.0.2",
"version": "1.1.0",
"description": "Zips up directories into buffers or saves zipped files to disk",
"main": "index.js",
"scripts": {
Expand Down
Empty file.
87 changes: 67 additions & 20 deletions test/zip-dir.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var chai = require("chai");
var expect = chai.expect;

var sampleZipPath = path.join(__dirname, "fixtures/sampleZip");
var emptySubFolderSampleZipPath = path.join(__dirname, "fixtures/emptySubFolderSampleZip");
var xpiPath = path.join(__dirname, "my.xpi");
var outputPath = path.join(__dirname, "myxpi/");
var emptyDirPath = path.join(sampleZipPath, "emptyDir");
Expand Down Expand Up @@ -53,7 +54,7 @@ describe("zip-dir", function () {
describe("writes a zip file", function () {
beforeEach(function (done) {
addEmpty(function () {
zipAndUnzip({ saveTo: xpiPath }, done);
zipAndUnzip(sampleZipPath, {saveTo: xpiPath}, done);
});
});
afterEach(cleanUp);
Expand All @@ -66,7 +67,9 @@ describe("zip-dir", function () {
"dir/file3.json",
"dir/deepDir/deeperDir/file4.json"
];
files.forEach(compareFiles);
files.forEach(function(file){
compareFiles(file, sampleZipPath);
});
done();
});

Expand All @@ -83,41 +86,45 @@ describe("zip-dir", function () {
afterEach(cleanUp);

it("filters out by file name, fs.Stat", function (done) {
zipAndUnzip({ saveTo: xpiPath, filter: jsonOnly }, function () {
zipAndUnzip(sampleZipPath, {saveTo: xpiPath, filter: jsonOnly}, function () {
var files = [
"file1.json",
"dir/file2.json",
"dir/file3.json",
"dir/deepDir/deeperDir/file4.json"
];
files.forEach(compareFiles);
files.forEach(function(file){
compareFiles(file, sampleZipPath);
});

fs.stat(path.join(outputPath, "tiny.gif"), function (err, stat) {
expect(err).to.be.ok;
done();
});
});

function jsonOnly (name, stat) {
function jsonOnly(name, stat) {
return /\.json$/.test(name) || stat.isDirectory();
}
});

it("filtering out directories keeps it shallow", function (done) {
zipAndUnzip({ saveTo: xpiPath, filter: noDirs }, function () {
zipAndUnzip(sampleZipPath, {saveTo: xpiPath, filter: noDirs}, function () {
var files = [
"file1.json",
"tiny.gif"
];
files.forEach(compareFiles);
files.forEach(function(file){
compareFiles(file, sampleZipPath);
});

fs.stat(path.join(outputPath, "dir"), function (err, stat) {
expect(err).to.be.ok;
done();
});
});

function noDirs (name, stat) {
function noDirs(name, stat) {
return !stat.isDirectory();
}
});
Expand All @@ -128,10 +135,12 @@ describe("zip-dir", function () {

it("calls `each` with each path added to zip", function (done) {
var paths = [];
function each (p) {

function each(p) {
paths.push(p);
}
zipDir(sampleZipPath, { each: each }, function (err, buffer) {

zipDir(sampleZipPath, {each: each}, function (err, buffer) {
var files = [
"file1.json",
"tiny.gif",
Expand All @@ -141,7 +150,9 @@ describe("zip-dir", function () {
"dir/deepDir",
"dir/deepDir/deeperDir",
"dir/deepDir/deeperDir/file4.json"
].map(function (p) { return path.join.apply(path, [sampleZipPath].concat(p.split("/"))); });
].map(function (p) {
return path.join.apply(path, [sampleZipPath].concat(p.split("/")));
});

files.forEach(function (p) {
expect(paths.indexOf(p)).to.not.equal(-1);
Expand All @@ -152,12 +163,19 @@ describe("zip-dir", function () {
done();
});
});

it("calls `each`, ignoring unadded files", function (done) {
var paths = [];
function each (p) { paths.push(p); }
function filter (p) { return /\.json$/.test(p) || fs.statSync(p).isDirectory(); }
zipDir(sampleZipPath, { each: each, filter: filter }, function (err, buffer) {

function each(p) {
paths.push(p);
}

function filter(p) {
return /\.json$/.test(p) || fs.statSync(p).isDirectory();
}

zipDir(sampleZipPath, {each: each, filter: filter}, function (err, buffer) {
var files = [
"file1.json",
"dir/file2.json",
Expand All @@ -166,7 +184,9 @@ describe("zip-dir", function () {
"dir/deepDir",
"dir/deepDir/deeperDir",
"dir/deepDir/deeperDir/file4.json"
].map(function (p) { return path.join.apply(path, [sampleZipPath].concat(p.split("/"))); });
].map(function (p) {
return path.join.apply(path, [sampleZipPath].concat(p.split("/")));
});

files.forEach(function (p) {
expect(paths.indexOf(p)).to.not.equal(-1);
Expand All @@ -178,16 +198,43 @@ describe("zip-dir", function () {
});
});
});

describe("`noEmptyDirectories` option", function () {
afterEach(cleanUp);
it("calls `noEmptyDirectories` with an empty root directory", function (done) {
var ERROR_MSG = 'Cannot have an empty root directory';
addEmpty(function() {
zipDir(emptyDirPath, {noEmptyDirectories: true}, function (err, buffer) {
expect(err).to.be.equal(ERROR_MSG);
expect(buffer).to.be.a('null');
done();
});
});
});

it("calls `noEmptyDirectories` with an empty sub directory", function (done) {
this.timeout(3000);
var files = [
"file.txt"
];
zipAndUnzip(emptySubFolderSampleZipPath, {saveTo: xpiPath, noEmptyDirectories: true}, function(){
files.forEach(function(file){
compareFiles(file, emptySubFolderSampleZipPath);
done();
});
})
});
});
});

function compareFiles (file) {
var zipBuffer = fs.readFileSync(path.join(sampleZipPath, file));
function compareFiles (file, inputPath) {
var zipBuffer = fs.readFileSync(path.join(inputPath, file));
var fileBuffer = fs.readFileSync(path.join(outputPath, file));
expect(bufferEqual(zipBuffer, fileBuffer)).to.be.ok;
}

function zipAndUnzip (options, done) {
zipDir(sampleZipPath, options, function (err, buffer) {
function zipAndUnzip (inputPath, options, done) {
zipDir(inputPath, options, function (err, buffer) {
if (err) throw err;
fs.createReadStream(xpiPath)
.pipe(unzip.Extract({ path: outputPath }))
Expand Down