From f7d2b476c2fb10567d73fb31cf438dbe7b9ce6e2 Mon Sep 17 00:00:00 2001 From: Quentin Rossetti Date: Mon, 25 Aug 2014 09:25:13 +0000 Subject: [PATCH] Extract with full paths tested and working All needed utilities (run and switches) are also tested. --- index.js | 98 ----------------------------------- lib/extractFull.js | 28 ++++++---- test/index.js | 112 ---------------------------------------- test/lib/extractFull.js | 8 +++ util/run.js | 18 ++++--- 5 files changed, 37 insertions(+), 227 deletions(-) delete mode 100644 index.js delete mode 100644 test/index.js diff --git a/index.js b/index.js deleted file mode 100644 index ea178b3..0000000 --- a/index.js +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; -var os = require('os'); -var path = require('path'); -var process = require('child_process'); -var events = require('events'); -var util = require('util'); -var spawn = require('win-spawn'); -var Promise = require('promise'); - -// Create an Api class that extends the EventEmitter. -function Api(name) { - this.name = (name) ? name : '7z'; -} -util.inherits(Api, events.EventEmitter); - -function concatSwitches(switches) { - var r = ''; - var c = ''; - for (var s in switches) { - c = switches[s]; - c = (c === true) ? '' : c; - r += '-' + s + c; - } -} - -// Adds files to archive. -Api.prototype.add = Promise.denodeify(function (archive, files, switches, cb) { - - // When no switches are speciied use the given function as the callback and - // set switches as an empty object. - if (typeof switches === 'function') { - cb = switches; - switches = {}; - } - archive = path.resolve(archive); - - -}); - - -// Test integrity of archive. -Api.prototype.test = Promise.denodeify(function (archive, callback) { - - archive = path.resolve(archive); - var cmd = '7z t ' + archive; - process.exec(cmd, function (err, stdout) { - if (err) return callback(err, null); - // Parse each line of the stdout and build an array of files (and - // directories) tested. The / is used in the result instead of the default - // OS path separator. - var r = []; - stdout.split(os.EOL).forEach(function (_line) { - if (_line.substr(0, 12) === 'Testing ') { - r.push(_line.substr(12, _line.length).replace(path.sep, '/')); - } - }); - return callback(null, r); - }); - -}); - - -// Extract with full paths. -Api.prototype.extract = Promise.denodeify(function (archive, dest, callback) { - - archive = path.resolve(archive); - dest = path.resolve(dest); - var self = this; - var err = null; - var cmd = ('x ' + archive + ' -y -o' + dest).split(' '); - var run = spawn('7z', cmd, { stdio: 'pipe' }); - - run.on('close', function (code) { - if (err) return callback(err); - return callback(null); - }); - - run.stdout.on('data', function (data) { - // When an stdout is emitted, parse it. If an error is detected in the body - // of the stdout create an new error with the 7-Zip error message as the - // error's message. Otherwise emit a `data` event with the processed files - // and directories as an array. - var files = []; - var regex = new RegExp('Error:' + os.EOL + '(.*)', 'g'); - var res = regex.exec(data.toString()); - if (res) err = new Error(res[1]); - data.toString().split(os.EOL).forEach(function (_line) { - if (_line.substr(0, 12) === 'Extracting ') { - files.push(_line.substr(12, _line.length).replace(path.sep, '/')); - } - }); - self.emit('data', files); - }); - -}); - - -module.exports = Api; diff --git a/lib/extractFull.js b/lib/extractFull.js index 0d9e488..bf80c01 100644 --- a/lib/extractFull.js +++ b/lib/extractFull.js @@ -2,17 +2,27 @@ var path = require('path'); var Q = require('q'); var u = { - run: require('../util/run') + run: require('../util/run'), + switches : require('../util/switches') }; +/** + * Extract an archive with full paths. + * @promise ExtractFull + * @progress {array} Extracted files and directories. + * @reject {Error} The error as issued by 7-Zip. + */ module.exports = function (archive, dest, options, cb) { - return Q.Promise(function (resolve, reject, notify) { - - //TODO: parse options, -y always true? - var opts = ''; + return Q.Promise(function (fulfill, reject, progress) { + + if (options === undefined) { + options = {}; + } + + var opts = u.switches(options); var command = '7z x ' + archive + ' -o' + dest + ' ' + opts; u.run(command) - + // When a stdout is emitted, parse each line and search for a pattern. When // the pattern is found, extract the file (or directory) name from it and // pass it to an array. Finally returns this array. @@ -23,16 +33,16 @@ module.exports = function (archive, dest, options, cb) { entries.push(line.substr(12, line.length).replace(path.sep, '/')); } }); - notify(entries); + progress(entries); }) .then(function () { - resolve(); + fulfill(); }) .catch(function (err) { reject(err); }); - + }).nodeify(cb); }; diff --git a/test/index.js b/test/index.js deleted file mode 100644 index 91f7154..0000000 --- a/test/index.js +++ /dev/null @@ -1,112 +0,0 @@ -'use strict'; -var Api = require('../index'); -var expect = require('chai').expect; -var path = require('path'); -var fs = require('fs'); -var rimraf = require('rimraf'); - -describe('The Api object', function () { - - after(function () { - rimraf.sync('.tmp/test'); - }); - - it('should respond to events methods', function () { - var api = new Api(); - expect(api).to.respondTo('emit'); - expect(api).to.respondTo('on'); - }); - - it('should have `7z` as default name', function () { - var api = new Api(); - expect(api.name).to.eql('7z'); - }); - - it('should be nameable', function () { - var api = new Api('testName'); - expect(api.name).to.eql('testName'); - }); - -}); - -describe('`add` function', function() { - - it('should get an error when 7z gets an error', function (done) { - var api = new Api(); - api.add('myArchive.7z', 'files', { i:'az', r: true }, function (s) { - console.log(s); - }); - api.add('myArchive.7z', 'files', function (s) { - console.log(s); - }); - done(); - }); - -}); - -describe('`test` function', function(){ - - it('should get an error when 7z gets an error', function (done) { - var api = new Api(); - api.test('test/nothere.7z', function (err) { - expect(err.message.substr(0, 14)).to.eql('Command failed'); - done(); - }); - }); - - it('should get a list of files and directories', function (done) { - var api = new Api(); - api.test('test/zip.7z', function (err, files) { - expect(files.length).to.be.at.least(6); - done(); - }); - }); - - it('should be compatible with Promise', function (done) { - var api = new Api(); - api.test('test/zip.7z').then(function (files) { - expect(files.length).to.be.at.least(6); - done(); - }); - }); - -}); - -describe('`extract` function', function() { - - it('should get an error when 7z gets an error', function (done) { - var api = new Api(); - api.extract('test/nothere.7z', '.tmp/test', function (err) { - expect(err.message).to.contain('archive'); - done(); - }); - }); - - it('should get a list of files and directories', function (done) { - var api = new Api(); - api.on('data', function (files) { - expect(files).to.be.an('array'); - done(); - }); - api.extract('test/zip.7z', '.tmp/test', function () {}); - }); - - it('should get no error on success', function (done) { - var api = new Api(); - api.extract('test/zip.7z', '.tmp/test', function (err) { - var file = path.resolve('.tmp/test/zip/file1.txt'); - expect(fs.existsSync(file)).to.eql(true); - expect(err).to.eql(null); - done(); - }); - }); - - it('should be compatible with Promise', function (done) { - var api = new Api(); - api.extract('test/nothere.7z', '.tmp/test').then(null, function (err) { - expect(err.message).to.contain('archive'); - done(); - }); - }); - -}); diff --git a/test/lib/extractFull.js b/test/lib/extractFull.js index e16c7c0..6f6d43e 100644 --- a/test/lib/extractFull.js +++ b/test/lib/extractFull.js @@ -15,6 +15,14 @@ describe('Module: `extractFull`', function () { done(); }); }); + + it('should return an error on output duplticate', function (done) { + extractFull('test/zip.7z', '.tmp/test', { o: '.tmp/test/duplicate' }) + .catch(function (err) { + expect(err).to.be.an.instanceof(Error); + done(); + }); + }); it('should return entries on progress', function (done) { extractFull('test/zip.7z', '.tmp/test') diff --git a/util/run.js b/util/run.js index cfc333e..71f76ec 100644 --- a/util/run.js +++ b/util/run.js @@ -4,11 +4,14 @@ var spawn = require('win-spawn'); var Q = require('q'); /** - * @function run - * @param {string} command The command to run + * @promise Run + * @param {string} command The command to run. + * @progress {string} stdout message. + * @reject {Error} The error issued by 7-Zip. + * @reject {number} Exit code issued by 7-Zip. */ module.exports = function (command, cb) { - return Q.Promise(function (resolve, reject, notify) { + return Q.Promise(function (fulfill, reject, progress) { // Parse the command variable. If the command is not a string reject the // Promise. Otherwise transform the command into two variables: the command @@ -22,8 +25,7 @@ module.exports = function (command, cb) { // When an stdout is emitted, parse it. If an error is detected in the body // of the stdout create an new error with the 7-Zip error message as the - // error's message. Otherwise progress with the processed files and - // directories as an array. + // error's message. Otherwise progress with stdout message. var err; var reg = new RegExp('Error:' + os.EOL + '(.*)', 'g'); var run = spawn(cmd, args, { stdio: 'pipe' }); @@ -32,11 +34,11 @@ module.exports = function (command, cb) { if (res) { err = new Error(res[1]); } - notify(data.toString()); + progress(data.toString()); }); run.on('close', function (code) { - if (code === 0) return resolve(); - reject(err); + if (code === 0) return fulfill(); + reject(err, code); }); }).nodeify(cb);