diff --git a/index.js b/index.js index 8c193e4..cb63088 100644 --- a/index.js +++ b/index.js @@ -99,10 +99,29 @@ module.exports = function (zipPath, opts, cb) { return setImmediate(done) } + var callback = function (err) { + if (err) { + return done(err) + } + doExtractEntry(entry, done) + } if (opts.onEntry) { - opts.onEntry(entry, zipfile) + if (opts.onEntry.length === 3) { + // Allow the callers onEntry to call methods with callbacks and + // those callbacks can drive failure/doExtractEntry. + opts.onEntry(entry, zipfile, callback) + } else { + // Backwards compatability + opts.onEntry(entry, zipfile) + doExtractEntry(entry, done) + } + } else { + // opts does not contain onEntry, so + doExtractEntry(entry, done) } + } + function doExtractEntry (entry, done) { var dest = path.join(opts.dir, entry.fileName) // convert external file attr int into a fs stat mode int diff --git a/readme.md b/readme.md index af17885..1185476 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,7 @@ extract(source, {dir: target}, function (err) { - `dir` - defaults to `process.cwd()` - `defaultDirMode` - integer - Directory Mode (permissions) will default to `493` (octal `0755` in integer) - `defaultFileMode` - integer - File Mode (permissions) will default to `420` (octal `0644` in integer) -- `onEntry` - function - if present, will be called with `(entry, zipfile)`, entry is every entry from the zip file forwarded from the `entry` event from yauzl. `zipfile` is the `yauzl` instance +- `onEntry` - function - if present, will be called with `(entry, zipfile[, done])`, entry is every entry from the zip file forwarded from the `entry` event from yauzl. `zipfile` is the `yauzl` instance. `done` if specified is a function, to extract the entry call `done()`, if you want to fail extraction then call `done(new Error('my error message'))`. Default modes are only used if no permissions are set in the zip file. diff --git a/test/test.js b/test/test.js index b124527..dd3f2c0 100644 --- a/test/test.js +++ b/test/test.js @@ -193,3 +193,59 @@ test('files in subdirs where the subdir does not have its own entry is extracted }) }) }) + +test('onEntry gets called for each entry', function (t) { + t.plan(3) + + var onEntryCallCount = 0 + var options = { + onEntry: function (entry, zipfile) { + onEntryCallCount++ + } + } + mkdtemp(t, 'files', function (dirPath) { + options.dir = dirPath + extract(catsZip, options, function (err) { + t.notOk(err, 'no error when extracting ' + catsZip) + t.same(onEntryCallCount, 11, 'onEntry was called for each entry') + }) + }) +}) + +test('onEntry can stop extraction', function (t) { + t.plan(3) + + var onEntryCallCount = 0 + var options = { + onEntry: function (entry, zipfile, done) { + onEntryCallCount++ + done('onEntry can stop extraction test') + } + } + mkdtemp(t, 'files', function (dirPath) { + options.dir = dirPath + extract(catsZip, options, function (err) { + t.same(onEntryCallCount, 1, 'onEntry stopped extraction straight away') + t.ok(err, 'onEntry can stop extraction test') + }) + }) +}) + +test('onEntry allows extraction', function (t) { + t.plan(3) + + var onEntryCallCount = 0 + var options = { + onEntry: function (entry, zipfile, done) { + onEntryCallCount++ + done() + } + } + mkdtemp(t, 'files', function (dirPath) { + options.dir = dirPath + extract(catsZip, options, function (err) { + t.notOk(err, 'no error when extracting' + catsZip) + t.same(onEntryCallCount, 11, 'onEntry allowed extraction') + }) + }) +})