From cd8e8a522eab48639ff4068149cccd3fb27d0e9d Mon Sep 17 00:00:00 2001 From: Adam Lynch Date: Mon, 5 Jun 2017 15:02:35 +0100 Subject: [PATCH 1/4] Switching to native promises (work in progress) --- .gitignore | 1 + lib/downloader.js | 173 +++++++++++++++++++++++----------------------- lib/index.js | 125 ++++++++++++++++----------------- lib/utils.js | 6 +- lib/versions.js | 23 +++--- package.json | 2 +- test/nwBuilder.js | 32 ++++----- test/utils.js | 4 +- 8 files changed, 177 insertions(+), 189 deletions(-) diff --git a/.gitignore b/.gitignore index 403a63909..c0d758416 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,6 @@ cache tmp/ test/temp/ .DS_Store +package-lock.json example/build \ No newline at end of file diff --git a/lib/downloader.js b/lib/downloader.js index 8ec32a054..e914acf41 100644 --- a/lib/downloader.js +++ b/lib/downloader.js @@ -1,4 +1,3 @@ -var Promise = require('bluebird'); var request = require('request'); var progress = require('progress'); var fs = require('fs'); @@ -21,7 +20,7 @@ module.exports = { checkCache: function(cachepath, files) { var missing; - // if the version is >=0.12.3, then we don't know which files we want from the archives, so just check that the + // if the version is >=0.12.3, then we don't know which files we want from the archives, so just check that the // folder exists and has at least 3 files in it. if(files.length === 1 && files[0] === '*'){ return fs.existsSync(cachepath) && fs.readdirSync(cachepath).length >= 2; @@ -44,7 +43,6 @@ module.exports = { }, downloadAndUnpack: function(cachepath, url) { var extention = path.extname(url), - done = Promise.defer(), self = this, rq = request(url), len, @@ -54,85 +52,83 @@ module.exports = { return statusCode + ': ' + require('http').STATUS_CODES[statusCode]; } - rq.proxy = true; - rq.on('error', function(err) { - bar && bar.terminate(); - done.reject(err); - }); - rq.on('response', function (res) { - len = parseInt(res.headers['content-length'], 10); - if (res.statusCode !== 200) { - done.reject({ - statusCode: res.statusCode, - msg: 'Recieved status code ' + format(res.statusCode) - }); - } else if (len) { - if (!bar) { - bar = new progress(' downloading [:bar] :percent :etas', { - complete: '=', - incomplete: '-', - width: 20, - total: len + return new Promise(function(resolve, reject){ + rq.proxy = true; + rq.on('error', function(err) { + bar && bar.terminate(); + reject(err); + }); + rq.on('response', function (res) { + len = parseInt(res.headers['content-length'], 10); + if (res.statusCode !== 200) { + reject({ + statusCode: res.statusCode, + msg: 'Recieved status code ' + format(res.statusCode) }); - } else { - bar.total += len; + } else if (len) { + if (!bar) { + bar = new progress(' downloading [:bar] :percent :etas', { + complete: '=', + incomplete: '-', + width: 20, + total: len + }); + } else { + bar.total += len; + } } - } - }); - rq.on('data', function(chunk) { - len && bar && bar.tick(chunk.length); - }); + }); + rq.on('data', function(chunk) { + len && bar && bar.tick(chunk.length); + }); - if (extention === '.zip') { - stream = temp.createWriteStream(); + if (extention === '.zip') { + stream = temp.createWriteStream(); - stream.on('close', function() { - if(done.promise.isRejected()) return; - self.extractZip(stream.path, cachepath).then(self.stripRootFolder).then(function(files) { - done.resolve(files); + stream.on('finish', function() { + self.extractZip(stream.path, cachepath).then(self.stripRootFolder).then(function(files) { + resolve(files); + }); }); - }); - rq.pipe(stream); - } + rq.pipe(stream); + } - if (extention === '.gz') { - rq.on('response', function(res) { - if(res.statusCode !== 200) return; - self.extractTar(res, cachepath).then(self.stripRootFolder).then(function(files) { - done.resolve(files); + else if (extention === '.gz') { + rq.on('response', function(res) { + if(res.statusCode !== 200) return; + self.extractTar(res, cachepath).then(self.stripRootFolder).then(function(files) { + resolve(files); + }); }); - }); - } - - return done.promise; + } + }); }, extractTar: function(tarstream, destination) { - var done = Promise.defer(), - gunzip = zlib.createGunzip(), + var gunzip = zlib.createGunzip(), files = []; - tarstream - .pipe(gunzip) - .on('error', function(err){ - done.reject(err); - }) - .pipe(tar.extract(destination, { - umask: (isWin ? false : 0), - map: function(header) { - files.push({path: path.basename(header.name)}); - return header; - } - })) - .on('finish', function() { - done.resolve({files:files, destination:destination}); - }); + return new Promise(function(resolve, reject){ + tarstream + .pipe(gunzip) + .on('error', function(err){ + reject(err); + }) + .pipe(tar.extract(destination, { + umask: (isWin ? false : 0), + map: function(header) { + files.push({path: path.basename(header.name)}); + return header; + } + })) + .on('finish', function() { + resolve({files:files, destination:destination}); + }); - return done.promise; + }); }, extractZip: function(zipfile, destination) { - var files = [], - done = Promise.defer(); + var files = []; var onEntry = function(entry){ files.push({ @@ -141,24 +137,24 @@ module.exports = { }); }; - extract(zipfile, { dir: destination, onEntry: onEntry }, function(err){ - if(err){ - return done.reject(err); - } + return new Promise(function(resolve, reject){ + extract(zipfile, { dir: destination, onEntry: onEntry }, function(err){ + if(err){ + return reject(err); + } + + // Setup chmodSync to fix permissions + files.forEach(function(file) { + fs.chmodSync(path.join(destination, file.path), file.mode); + }); - // Setup chmodSync to fix permissions - files.forEach(function(file) { - fs.chmodSync(path.join(destination, file.path), file.mode); + resolve({ files: files, destination: destination }); }); - done.resolve({ files: files, destination: destination }); }); - - return done.promise; }, stripRootFolder: function(extracted){ - var done = Promise.defer(), - files = extracted.files, + var files = extracted.files, destination = extracted.destination, rootFiles = fs.readdirSync(destination), fromDir = path.join(destination, rootFiles.length === 1 ? rootFiles[0] : ''); @@ -174,17 +170,20 @@ module.exports = { i--; } } - // move stripped folder to destination - ncp(fromDir, destination, function (err) { - if (err) done.reject(); - else rimraf(fromDir, function(){ - done.resolve(files); + + return new Promise(function(resolve, reject){ + // move stripped folder to destination + ncp(fromDir, destination, function (err) { + if (err) { + return reject(); + } + else rimraf(fromDir, function(){ + resolve(files); + }); }); }); } else { - done.resolve(files); + return Promise.resolve(files); } - - return done.promise; } }; diff --git a/lib/index.js b/lib/index.js index 0a447f2aa..5ae996761 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,3 @@ -var Promise = require('bluebird'); var _ = require('lodash'); var inherits = require('inherits'); var EventEmitter = require('events').EventEmitter; @@ -6,7 +5,8 @@ var fs = require('graceful-fs-extra'); var recursiveReaddirSync = require('recursive-readdir-sync'); var path = require('path'); var url = require('url'); -var winresourcer = Promise.promisify(require('winresourcer')); +var thenify = require('thenify'); +var winresourcer = thenify(require('winresourcer')); var spawn = require('child_process').spawn; var semver = require('semver'); var platformOverrides = require('platform-overrides'); @@ -34,7 +34,7 @@ if(packageUpdate){ + '\nTo update, run one of the following commands:' + '\n- ' + chalk().cyan('npm i -g ' + pkg.name) + ' (if ' + pkg.name + ' is installed globally)' + '\n- ' + chalk().cyan('npm i -D ' + pkg.name) + ' (if ' + pkg.name + ' is installed locally)'; - + var boxenOptions = { padding: 1, margin: 1, @@ -114,82 +114,70 @@ function NwBuilder(options) { } NwBuilder.prototype.build = function (callback) { - var hasCallback = (typeof callback === 'function'), - done = Promise.defer(); - // Let's create a NWjs app - this.checkFiles().bind(this) + var build = this.checkFiles() .then(this.resolveLatestVersion) .then(this.checkVersion) .then(this.platformFilesForVersion) .then(this.downloadNwjs) - .then(this.preparePlatformSpecificManifests) - .then(this.createReleaseFolder) + .then(this.preparePlatformSpecificManifests.bind(this)) + .then(this.createReleaseFolder.bind(this)) .then(this.copyNwjs) .then(this.handleMacApp) .then(this.handleWinApp) - .then(this.zipAppFiles) - .then(this.mergeAppFiles) - .then(function (info) { + .then(this.zipAppFiles.bind(this)) + .then(this.mergeAppFiles.bind(this)) + .then(function(info){ // the promise(s) resolves to nothing in some cases - var result = info || this; + return info || this; + }); - if(hasCallback) { + if(typeof callback === 'function'){ + build + .then(function(result){ callback(false, result); - } else { - done.resolve(result); - } - }) - .catch(function (error) { - if(hasCallback) { - callback(error); - } else { - done.reject(error); - } - }); + }) + .catch(callback); + return true; + } - return hasCallback ? true : done.promise; + return build; }; NwBuilder.prototype.run = function (callback) { - var hasCallback = (typeof callback === 'function'), - done = Promise.defer(); - // Let's run this NWjs app - this.checkFiles().bind(this) + var run = this.checkFiles() .then(this.resolveLatestVersion) .then(this.checkVersion) .then(this.platformFilesForVersion) .then(this.downloadNwjs) - .then(this.runApp) - .then(function (info) { - if(hasCallback) { - callback(false, info); - } else { - done.resolve(info); - } + .then(this.runApp); + + if(typeof callback === 'function'){ + run.then(function(result){ + callback(false, result); }) - .catch(function (error) { - if(hasCallback) { - callback(true, error); - } else { - done.reject(error); - } + .catch(function(error){ + callback(true, error); }); + return true; + } - return hasCallback ? true : done.promise; + return run; }; NwBuilder.prototype.checkFiles = function () { var self = this; - return Utils.getFileList(this.options.files).then(function (data) { - - self._appPkg = data.json; - self._files = data.files; - - return Utils.getPackageInfo(self._appPkg).then(function (appPkg) { + return Utils.getFileList(this.options.files) + .then(function (data) { + self._appPkg = data.json; + self._files = data.files; + return self._appPkg; + }) + .then(Utils.getPackageInfo) + .then(function (appPkg) { self._appPkg = appPkg; if(!self.options.appName || !self.options.appVersion) { @@ -197,8 +185,6 @@ NwBuilder.prototype.checkFiles = function () { self.options.appVersion = (self.options.appVersion ? self.options.appVersion : appPkg.version); } }); - }); - }; NwBuilder.prototype.resolveLatestVersion = function () { @@ -291,7 +277,7 @@ NwBuilder.prototype.platformFilesForVersion = function () { } }); - return true; + return Promise.resolve(); }; NwBuilder.prototype.downloadNwjs = function () { @@ -346,27 +332,32 @@ NwBuilder.prototype.buildGypModules = function () { NwBuilder.prototype.preparePlatformSpecificManifests = function(){ - if(!(this._appPkg.platformOverrides && Object.keys(this._appPkg.platformOverrides).length)){ - return true; + return Promise.resolve(); } var self = this; - this._forEachPlatform(function (name, platform) { + return new Promise(function(resolve, reject){ + self._forEachPlatform(function (name, platform) { - var overrides = self._appPkg.platformOverrides; - if (overrides[name] || overrides[name.substr(0, name.length-2)]) { + var overrides = self._appPkg.platformOverrides; + if (overrides[name] || overrides[name.substr(0, name.length-2)]) { - platformOverrides({ - options: self._appPkg, - platform: name - }, function(err, result){ - if(err) throw(err); - platform.platformSpecificManifest = result; - }); - } - }); + platformOverrides({ + options: self._appPkg, + platform: name + }, function(err, result){ + if(err){ + return reject(err); + } + + platform.platformSpecificManifest = result; + resolve(); + }); + } + }); + }) }; diff --git a/lib/utils.js b/lib/utils.js index 3feced833..8f6f7842e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,14 +1,14 @@ var fs = require('graceful-fs-extra'); var path = require('path'); var _ = require('lodash'); -var Promise = require('bluebird'); var plist = require('plist'); var Glob = require('simple-glob'); var temp = require('temp'); var archiver = require('archiver'); +var thenify = require('thenify'); -var readFile = Promise.promisify(fs.readFile); -var writeFile = Promise.promisify(fs.writeFile); +var readFile = thenify(fs.readFile); +var writeFile = thenify(fs.writeFile); // Automatically track and cleanup files at exit temp.track(); diff --git a/lib/versions.js b/lib/versions.js index c1e91f573..f4736f273 100644 --- a/lib/versions.js +++ b/lib/versions.js @@ -1,4 +1,3 @@ -var Promise = require('bluebird'); var platforms = require('./platforms'); var semver = require('semver'); var request = require('request'); @@ -11,19 +10,17 @@ var Version = require('./Version'); * @returns {promise} which resolves to response body */ function get(url, options){ - var deferred = Promise.defer(); - - request(url, options, function (err, res, body) { - if (err) { - deferred.reject(err); - } else if (res.statusCode !== 200) { - deferred.reject('Received status code ' + res.statusCode + ': ' + url); - } else { - deferred.resolve(body); - } + return new Promise(function(resolve, reject){ + request(url, options, function (err, res, body) { + if (err) { + reject(err); + } else if (res.statusCode !== 200) { + reject('Received status code ' + res.statusCode + ': ' + url); + } else { + resolve(body); + } + }); }); - - return deferred.promise; } /** diff --git a/package.json b/package.json index ecde55215..d62cdc2c8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ }, "dependencies": { "archiver": "^1.3.0", - "bluebird": "^3.4.0", "boxen": "^1.1.0", "chalk": "^1.1.3", "deprecate": "~1.0.0", @@ -67,6 +66,7 @@ "simple-glob": "~0.1.0", "tar-fs": "^1.13.0", "temp": "github:adam-lynch/node-temp#remove_tmpdir_dep", + "thenify": "^3.3.0", "update-notifier": "^1.0.3", "winresourcer": "^0.9.0" } diff --git a/test/nwBuilder.js b/test/nwBuilder.js index bf64d1f64..732a6eca8 100644 --- a/test/nwBuilder.js +++ b/test/nwBuilder.js @@ -75,8 +75,8 @@ test('Should apply platform-specific overrides correctly', function (t) { platforms: ['osx32', 'osx64', 'win32', 'win64', 'linux32', 'linux64'] }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) .then(function () { _.forEach(x._platforms, function(platform, platformName){ var file = fs.readFileSync(path.join('./test/expected/platformOverrides', platformName + '.json')); @@ -94,9 +94,9 @@ test('Should only create one ZIP if there are no platform-specific overrides', f macZip: true }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.zipAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.zipAppFiles.bind(x)) .then(function () { _.forEach(x._zips, function(zip, platformName){ t.equal(zip.platformSpecific, false, platformName + ' should be marked as platform specific'); @@ -120,9 +120,9 @@ test('Should create a ZIP per platform if every platform has overrides', functio macZip: true }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.zipAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.zipAppFiles.bind(x)) .then(function () { _.forEach(x._zips, function(zip, platformName){ t.equal(zip.platformSpecific, true, platformName + ' should be marked as platform specific'); @@ -144,9 +144,9 @@ test('Should create a ZIP per platform which has overrides and one between the r macZip: true }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.zipAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.zipAppFiles.bind(x)) .then(function () { _.forEach(x._zips, function(zip, platformName){ t.equal(zip.platformSpecific, platformName === 'osx32', platformName + ' should be marked as platform specific'); @@ -198,7 +198,7 @@ test('Should not zip mac apps by default', function (t) { t.plan(1); var x = new NwBuilder({ files: './test/fixtures/nwapp/**/*', platforms: ['osx32', 'osx64'] }); - x.zipAppFiles().then(function () { + x.zipAppFiles.call(x).then(function () { t.notOk(x._needsZip); }); @@ -221,10 +221,10 @@ testSetup({ buildDir: buildDir }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.createReleaseFolder) - .then(x.mergeAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.createReleaseFolder.bind(x)) + .then(x.mergeAppFiles.bind(x)) .then(function () { t.deepEqual( JSON.parse(fs.readFileSync(path.join( diff --git a/test/utils.js b/test/utils.js index 152339af3..a737e6e2e 100644 --- a/test/utils.js +++ b/test/utils.js @@ -8,9 +8,9 @@ var DecompressZip = require('decompress-zip'); var _ = require('lodash'); var EventEmitter = require('events').EventEmitter; var del = require('rimraf'); -var Promise = require('bluebird'); +var thenify = require('thenify'); var isWindows = process.platform === 'win32'; -var tempFile = Promise.promisify(temp.open); +var tempFile = thenify(temp.open); var tempFileCleanup = function(){ return new Promise(function(resolve, reject){ From d71afac9a39a61751134e11f523e277b9c04b97c Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 5 Jun 2017 15:45:29 +0100 Subject: [PATCH 2/4] Using native promises --- lib/index.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5ae996761..2fdf03bb4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -116,15 +116,15 @@ function NwBuilder(options) { NwBuilder.prototype.build = function (callback) { // Let's create a NWjs app var build = this.checkFiles() - .then(this.resolveLatestVersion) - .then(this.checkVersion) - .then(this.platformFilesForVersion) - .then(this.downloadNwjs) + .then(this.resolveLatestVersion.bind(this)) + .then(this.checkVersion.bind(this)) + .then(this.platformFilesForVersion.bind(this)) + .then(this.downloadNwjs.bind(this)) .then(this.preparePlatformSpecificManifests.bind(this)) .then(this.createReleaseFolder.bind(this)) - .then(this.copyNwjs) - .then(this.handleMacApp) - .then(this.handleWinApp) + .then(this.copyNwjs.bind(this)) + .then(this.handleMacApp.bind(this)) + .then(this.handleWinApp.bind(this)) .then(this.zipAppFiles.bind(this)) .then(this.mergeAppFiles.bind(this)) .then(function(info){ @@ -147,11 +147,11 @@ NwBuilder.prototype.build = function (callback) { NwBuilder.prototype.run = function (callback) { // Let's run this NWjs app var run = this.checkFiles() - .then(this.resolveLatestVersion) - .then(this.checkVersion) - .then(this.platformFilesForVersion) - .then(this.downloadNwjs) - .then(this.runApp); + .then(this.resolveLatestVersion.bind(this)) + .then(this.checkVersion.bind(this)) + .then(this.platformFilesForVersion.bind(this)) + .then(this.downloadNwjs.bind(this)) + .then(this.runApp.bind(this)); if(typeof callback === 'function'){ run.then(function(result){ From 9f0af6a5b04e81f696db0557a3eba3dc43af8185 Mon Sep 17 00:00:00 2001 From: Adam Lynch Date: Mon, 5 Jun 2017 15:02:35 +0100 Subject: [PATCH 3/4] Switching to native promises Closes #451 --- .gitignore | 1 + lib/downloader.js | 173 +++++++++++++++++++++++----------------------- lib/index.js | 147 ++++++++++++++++++--------------------- lib/utils.js | 6 +- lib/versions.js | 23 +++--- package.json | 2 +- test/nwBuilder.js | 32 ++++----- test/utils.js | 4 +- 8 files changed, 188 insertions(+), 200 deletions(-) diff --git a/.gitignore b/.gitignore index 403a63909..c0d758416 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,6 @@ cache tmp/ test/temp/ .DS_Store +package-lock.json example/build \ No newline at end of file diff --git a/lib/downloader.js b/lib/downloader.js index 8ec32a054..e914acf41 100644 --- a/lib/downloader.js +++ b/lib/downloader.js @@ -1,4 +1,3 @@ -var Promise = require('bluebird'); var request = require('request'); var progress = require('progress'); var fs = require('fs'); @@ -21,7 +20,7 @@ module.exports = { checkCache: function(cachepath, files) { var missing; - // if the version is >=0.12.3, then we don't know which files we want from the archives, so just check that the + // if the version is >=0.12.3, then we don't know which files we want from the archives, so just check that the // folder exists and has at least 3 files in it. if(files.length === 1 && files[0] === '*'){ return fs.existsSync(cachepath) && fs.readdirSync(cachepath).length >= 2; @@ -44,7 +43,6 @@ module.exports = { }, downloadAndUnpack: function(cachepath, url) { var extention = path.extname(url), - done = Promise.defer(), self = this, rq = request(url), len, @@ -54,85 +52,83 @@ module.exports = { return statusCode + ': ' + require('http').STATUS_CODES[statusCode]; } - rq.proxy = true; - rq.on('error', function(err) { - bar && bar.terminate(); - done.reject(err); - }); - rq.on('response', function (res) { - len = parseInt(res.headers['content-length'], 10); - if (res.statusCode !== 200) { - done.reject({ - statusCode: res.statusCode, - msg: 'Recieved status code ' + format(res.statusCode) - }); - } else if (len) { - if (!bar) { - bar = new progress(' downloading [:bar] :percent :etas', { - complete: '=', - incomplete: '-', - width: 20, - total: len + return new Promise(function(resolve, reject){ + rq.proxy = true; + rq.on('error', function(err) { + bar && bar.terminate(); + reject(err); + }); + rq.on('response', function (res) { + len = parseInt(res.headers['content-length'], 10); + if (res.statusCode !== 200) { + reject({ + statusCode: res.statusCode, + msg: 'Recieved status code ' + format(res.statusCode) }); - } else { - bar.total += len; + } else if (len) { + if (!bar) { + bar = new progress(' downloading [:bar] :percent :etas', { + complete: '=', + incomplete: '-', + width: 20, + total: len + }); + } else { + bar.total += len; + } } - } - }); - rq.on('data', function(chunk) { - len && bar && bar.tick(chunk.length); - }); + }); + rq.on('data', function(chunk) { + len && bar && bar.tick(chunk.length); + }); - if (extention === '.zip') { - stream = temp.createWriteStream(); + if (extention === '.zip') { + stream = temp.createWriteStream(); - stream.on('close', function() { - if(done.promise.isRejected()) return; - self.extractZip(stream.path, cachepath).then(self.stripRootFolder).then(function(files) { - done.resolve(files); + stream.on('finish', function() { + self.extractZip(stream.path, cachepath).then(self.stripRootFolder).then(function(files) { + resolve(files); + }); }); - }); - rq.pipe(stream); - } + rq.pipe(stream); + } - if (extention === '.gz') { - rq.on('response', function(res) { - if(res.statusCode !== 200) return; - self.extractTar(res, cachepath).then(self.stripRootFolder).then(function(files) { - done.resolve(files); + else if (extention === '.gz') { + rq.on('response', function(res) { + if(res.statusCode !== 200) return; + self.extractTar(res, cachepath).then(self.stripRootFolder).then(function(files) { + resolve(files); + }); }); - }); - } - - return done.promise; + } + }); }, extractTar: function(tarstream, destination) { - var done = Promise.defer(), - gunzip = zlib.createGunzip(), + var gunzip = zlib.createGunzip(), files = []; - tarstream - .pipe(gunzip) - .on('error', function(err){ - done.reject(err); - }) - .pipe(tar.extract(destination, { - umask: (isWin ? false : 0), - map: function(header) { - files.push({path: path.basename(header.name)}); - return header; - } - })) - .on('finish', function() { - done.resolve({files:files, destination:destination}); - }); + return new Promise(function(resolve, reject){ + tarstream + .pipe(gunzip) + .on('error', function(err){ + reject(err); + }) + .pipe(tar.extract(destination, { + umask: (isWin ? false : 0), + map: function(header) { + files.push({path: path.basename(header.name)}); + return header; + } + })) + .on('finish', function() { + resolve({files:files, destination:destination}); + }); - return done.promise; + }); }, extractZip: function(zipfile, destination) { - var files = [], - done = Promise.defer(); + var files = []; var onEntry = function(entry){ files.push({ @@ -141,24 +137,24 @@ module.exports = { }); }; - extract(zipfile, { dir: destination, onEntry: onEntry }, function(err){ - if(err){ - return done.reject(err); - } + return new Promise(function(resolve, reject){ + extract(zipfile, { dir: destination, onEntry: onEntry }, function(err){ + if(err){ + return reject(err); + } + + // Setup chmodSync to fix permissions + files.forEach(function(file) { + fs.chmodSync(path.join(destination, file.path), file.mode); + }); - // Setup chmodSync to fix permissions - files.forEach(function(file) { - fs.chmodSync(path.join(destination, file.path), file.mode); + resolve({ files: files, destination: destination }); }); - done.resolve({ files: files, destination: destination }); }); - - return done.promise; }, stripRootFolder: function(extracted){ - var done = Promise.defer(), - files = extracted.files, + var files = extracted.files, destination = extracted.destination, rootFiles = fs.readdirSync(destination), fromDir = path.join(destination, rootFiles.length === 1 ? rootFiles[0] : ''); @@ -174,17 +170,20 @@ module.exports = { i--; } } - // move stripped folder to destination - ncp(fromDir, destination, function (err) { - if (err) done.reject(); - else rimraf(fromDir, function(){ - done.resolve(files); + + return new Promise(function(resolve, reject){ + // move stripped folder to destination + ncp(fromDir, destination, function (err) { + if (err) { + return reject(); + } + else rimraf(fromDir, function(){ + resolve(files); + }); }); }); } else { - done.resolve(files); + return Promise.resolve(files); } - - return done.promise; } }; diff --git a/lib/index.js b/lib/index.js index 0a447f2aa..2fdf03bb4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,3 @@ -var Promise = require('bluebird'); var _ = require('lodash'); var inherits = require('inherits'); var EventEmitter = require('events').EventEmitter; @@ -6,7 +5,8 @@ var fs = require('graceful-fs-extra'); var recursiveReaddirSync = require('recursive-readdir-sync'); var path = require('path'); var url = require('url'); -var winresourcer = Promise.promisify(require('winresourcer')); +var thenify = require('thenify'); +var winresourcer = thenify(require('winresourcer')); var spawn = require('child_process').spawn; var semver = require('semver'); var platformOverrides = require('platform-overrides'); @@ -34,7 +34,7 @@ if(packageUpdate){ + '\nTo update, run one of the following commands:' + '\n- ' + chalk().cyan('npm i -g ' + pkg.name) + ' (if ' + pkg.name + ' is installed globally)' + '\n- ' + chalk().cyan('npm i -D ' + pkg.name) + ' (if ' + pkg.name + ' is installed locally)'; - + var boxenOptions = { padding: 1, margin: 1, @@ -114,82 +114,70 @@ function NwBuilder(options) { } NwBuilder.prototype.build = function (callback) { - var hasCallback = (typeof callback === 'function'), - done = Promise.defer(); - // Let's create a NWjs app - this.checkFiles().bind(this) - .then(this.resolveLatestVersion) - .then(this.checkVersion) - .then(this.platformFilesForVersion) - .then(this.downloadNwjs) - .then(this.preparePlatformSpecificManifests) - .then(this.createReleaseFolder) - .then(this.copyNwjs) - .then(this.handleMacApp) - .then(this.handleWinApp) - .then(this.zipAppFiles) - .then(this.mergeAppFiles) - .then(function (info) { + var build = this.checkFiles() + .then(this.resolveLatestVersion.bind(this)) + .then(this.checkVersion.bind(this)) + .then(this.platformFilesForVersion.bind(this)) + .then(this.downloadNwjs.bind(this)) + .then(this.preparePlatformSpecificManifests.bind(this)) + .then(this.createReleaseFolder.bind(this)) + .then(this.copyNwjs.bind(this)) + .then(this.handleMacApp.bind(this)) + .then(this.handleWinApp.bind(this)) + .then(this.zipAppFiles.bind(this)) + .then(this.mergeAppFiles.bind(this)) + .then(function(info){ // the promise(s) resolves to nothing in some cases - var result = info || this; + return info || this; + }); - if(hasCallback) { + if(typeof callback === 'function'){ + build + .then(function(result){ callback(false, result); - } else { - done.resolve(result); - } - }) - .catch(function (error) { - if(hasCallback) { - callback(error); - } else { - done.reject(error); - } - }); + }) + .catch(callback); + return true; + } - return hasCallback ? true : done.promise; + return build; }; NwBuilder.prototype.run = function (callback) { - var hasCallback = (typeof callback === 'function'), - done = Promise.defer(); - // Let's run this NWjs app - this.checkFiles().bind(this) - .then(this.resolveLatestVersion) - .then(this.checkVersion) - .then(this.platformFilesForVersion) - .then(this.downloadNwjs) - .then(this.runApp) - .then(function (info) { - if(hasCallback) { - callback(false, info); - } else { - done.resolve(info); - } + var run = this.checkFiles() + .then(this.resolveLatestVersion.bind(this)) + .then(this.checkVersion.bind(this)) + .then(this.platformFilesForVersion.bind(this)) + .then(this.downloadNwjs.bind(this)) + .then(this.runApp.bind(this)); + + if(typeof callback === 'function'){ + run.then(function(result){ + callback(false, result); }) - .catch(function (error) { - if(hasCallback) { - callback(true, error); - } else { - done.reject(error); - } + .catch(function(error){ + callback(true, error); }); + return true; + } - return hasCallback ? true : done.promise; + return run; }; NwBuilder.prototype.checkFiles = function () { var self = this; - return Utils.getFileList(this.options.files).then(function (data) { - - self._appPkg = data.json; - self._files = data.files; - - return Utils.getPackageInfo(self._appPkg).then(function (appPkg) { + return Utils.getFileList(this.options.files) + .then(function (data) { + self._appPkg = data.json; + self._files = data.files; + return self._appPkg; + }) + .then(Utils.getPackageInfo) + .then(function (appPkg) { self._appPkg = appPkg; if(!self.options.appName || !self.options.appVersion) { @@ -197,8 +185,6 @@ NwBuilder.prototype.checkFiles = function () { self.options.appVersion = (self.options.appVersion ? self.options.appVersion : appPkg.version); } }); - }); - }; NwBuilder.prototype.resolveLatestVersion = function () { @@ -291,7 +277,7 @@ NwBuilder.prototype.platformFilesForVersion = function () { } }); - return true; + return Promise.resolve(); }; NwBuilder.prototype.downloadNwjs = function () { @@ -346,27 +332,32 @@ NwBuilder.prototype.buildGypModules = function () { NwBuilder.prototype.preparePlatformSpecificManifests = function(){ - if(!(this._appPkg.platformOverrides && Object.keys(this._appPkg.platformOverrides).length)){ - return true; + return Promise.resolve(); } var self = this; - this._forEachPlatform(function (name, platform) { + return new Promise(function(resolve, reject){ + self._forEachPlatform(function (name, platform) { - var overrides = self._appPkg.platformOverrides; - if (overrides[name] || overrides[name.substr(0, name.length-2)]) { + var overrides = self._appPkg.platformOverrides; + if (overrides[name] || overrides[name.substr(0, name.length-2)]) { - platformOverrides({ - options: self._appPkg, - platform: name - }, function(err, result){ - if(err) throw(err); - platform.platformSpecificManifest = result; - }); - } - }); + platformOverrides({ + options: self._appPkg, + platform: name + }, function(err, result){ + if(err){ + return reject(err); + } + + platform.platformSpecificManifest = result; + resolve(); + }); + } + }); + }) }; diff --git a/lib/utils.js b/lib/utils.js index 3feced833..8f6f7842e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,14 +1,14 @@ var fs = require('graceful-fs-extra'); var path = require('path'); var _ = require('lodash'); -var Promise = require('bluebird'); var plist = require('plist'); var Glob = require('simple-glob'); var temp = require('temp'); var archiver = require('archiver'); +var thenify = require('thenify'); -var readFile = Promise.promisify(fs.readFile); -var writeFile = Promise.promisify(fs.writeFile); +var readFile = thenify(fs.readFile); +var writeFile = thenify(fs.writeFile); // Automatically track and cleanup files at exit temp.track(); diff --git a/lib/versions.js b/lib/versions.js index c1e91f573..f4736f273 100644 --- a/lib/versions.js +++ b/lib/versions.js @@ -1,4 +1,3 @@ -var Promise = require('bluebird'); var platforms = require('./platforms'); var semver = require('semver'); var request = require('request'); @@ -11,19 +10,17 @@ var Version = require('./Version'); * @returns {promise} which resolves to response body */ function get(url, options){ - var deferred = Promise.defer(); - - request(url, options, function (err, res, body) { - if (err) { - deferred.reject(err); - } else if (res.statusCode !== 200) { - deferred.reject('Received status code ' + res.statusCode + ': ' + url); - } else { - deferred.resolve(body); - } + return new Promise(function(resolve, reject){ + request(url, options, function (err, res, body) { + if (err) { + reject(err); + } else if (res.statusCode !== 200) { + reject('Received status code ' + res.statusCode + ': ' + url); + } else { + resolve(body); + } + }); }); - - return deferred.promise; } /** diff --git a/package.json b/package.json index ecde55215..d62cdc2c8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ }, "dependencies": { "archiver": "^1.3.0", - "bluebird": "^3.4.0", "boxen": "^1.1.0", "chalk": "^1.1.3", "deprecate": "~1.0.0", @@ -67,6 +66,7 @@ "simple-glob": "~0.1.0", "tar-fs": "^1.13.0", "temp": "github:adam-lynch/node-temp#remove_tmpdir_dep", + "thenify": "^3.3.0", "update-notifier": "^1.0.3", "winresourcer": "^0.9.0" } diff --git a/test/nwBuilder.js b/test/nwBuilder.js index bf64d1f64..732a6eca8 100644 --- a/test/nwBuilder.js +++ b/test/nwBuilder.js @@ -75,8 +75,8 @@ test('Should apply platform-specific overrides correctly', function (t) { platforms: ['osx32', 'osx64', 'win32', 'win64', 'linux32', 'linux64'] }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) .then(function () { _.forEach(x._platforms, function(platform, platformName){ var file = fs.readFileSync(path.join('./test/expected/platformOverrides', platformName + '.json')); @@ -94,9 +94,9 @@ test('Should only create one ZIP if there are no platform-specific overrides', f macZip: true }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.zipAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.zipAppFiles.bind(x)) .then(function () { _.forEach(x._zips, function(zip, platformName){ t.equal(zip.platformSpecific, false, platformName + ' should be marked as platform specific'); @@ -120,9 +120,9 @@ test('Should create a ZIP per platform if every platform has overrides', functio macZip: true }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.zipAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.zipAppFiles.bind(x)) .then(function () { _.forEach(x._zips, function(zip, platformName){ t.equal(zip.platformSpecific, true, platformName + ' should be marked as platform specific'); @@ -144,9 +144,9 @@ test('Should create a ZIP per platform which has overrides and one between the r macZip: true }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.zipAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.zipAppFiles.bind(x)) .then(function () { _.forEach(x._zips, function(zip, platformName){ t.equal(zip.platformSpecific, platformName === 'osx32', platformName + ' should be marked as platform specific'); @@ -198,7 +198,7 @@ test('Should not zip mac apps by default', function (t) { t.plan(1); var x = new NwBuilder({ files: './test/fixtures/nwapp/**/*', platforms: ['osx32', 'osx64'] }); - x.zipAppFiles().then(function () { + x.zipAppFiles.call(x).then(function () { t.notOk(x._needsZip); }); @@ -221,10 +221,10 @@ testSetup({ buildDir: buildDir }); - x.checkFiles().bind(x) - .then(x.preparePlatformSpecificManifests) - .then(x.createReleaseFolder) - .then(x.mergeAppFiles) + x.checkFiles() + .then(x.preparePlatformSpecificManifests.bind(x)) + .then(x.createReleaseFolder.bind(x)) + .then(x.mergeAppFiles.bind(x)) .then(function () { t.deepEqual( JSON.parse(fs.readFileSync(path.join( diff --git a/test/utils.js b/test/utils.js index 152339af3..a737e6e2e 100644 --- a/test/utils.js +++ b/test/utils.js @@ -8,9 +8,9 @@ var DecompressZip = require('decompress-zip'); var _ = require('lodash'); var EventEmitter = require('events').EventEmitter; var del = require('rimraf'); -var Promise = require('bluebird'); +var thenify = require('thenify'); var isWindows = process.platform === 'win32'; -var tempFile = Promise.promisify(temp.open); +var tempFile = thenify(temp.open); var tempFileCleanup = function(){ return new Promise(function(resolve, reject){ From 9fa2016e939a1b1750d3e40ece6296b979bacddd Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 5 Jun 2017 15:56:40 +0100 Subject: [PATCH 4/4] 3.4.1 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30909e6f7..a1514bdcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file and in the [ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [3.4.1] - 2017-06-05 + +### Removed + +- The `bluebird` dependency. We're now using native promises instead. + + ## [3.4.0] - 2017-05-28 ### Added diff --git a/package.json b/package.json index d62cdc2c8..f5b5014a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nw-builder", - "version": "3.4.0", + "version": "3.4.1", "description": "nw-builder", "main": "index.js", "scripts": {