bin-wrapper
Advanced tools
Comparing version 0.2.4 to 0.3.0
332
index.js
'use strict'; | ||
var binCheck = require('bin-check'); | ||
var events = require('events'); | ||
var exec = require('child_process').exec; | ||
var executable = require('executable'); | ||
var findFile = require('find-file'); | ||
var merge = require('mout/object/merge'); | ||
var find = require('find-file'); | ||
var path = require('path'); | ||
var rm = require('rimraf'); | ||
var set = require('mout/object/set'); | ||
var tempfile = require('tempfile'); | ||
var util = require('util'); | ||
/** | ||
* Initialize BinWrapper with options | ||
* Initialize a new `BinWrapper` with opts | ||
* | ||
* Options: | ||
* | ||
* - `bin` The name of the binary | ||
* - `dest` Where to download the binary | ||
* - `version` Version of the binary | ||
* - `global` Whether to check for global binaries or not | ||
* | ||
* @param {Object} opts | ||
@@ -30,55 +15,37 @@ * @api public | ||
function BinWrapper(opts) { | ||
events.EventEmitter.call(this); | ||
if (!(this instanceof BinWrapper)) { | ||
return new BinWrapper(); | ||
} | ||
opts = opts || {}; | ||
this.opts = opts; | ||
this.bin = opts.bin; | ||
if (process.platform === 'win32' && path.extname(this.bin) === '') { | ||
this.bin = this.bin + '.exe'; | ||
} | ||
this.files = {}; | ||
this.urls = { name: this.bin }; | ||
this.dest = opts.dest || process.cwd(); | ||
this.global = opts.global !== false; | ||
this.paths = [this.dest]; | ||
this.path = this._find(this.bin) || path.join(this.dest, this.bin); | ||
this._src = []; | ||
} | ||
/** | ||
* Inherit from `events.EventEmitter` | ||
*/ | ||
util.inherits(BinWrapper, events.EventEmitter); | ||
/** | ||
* Check if a binary is present and working | ||
* Define a binary to download | ||
* | ||
* @param {String|Array} cmd | ||
* @param {String} src | ||
* @param {String} os | ||
* @param {String} arch | ||
* @api public | ||
*/ | ||
BinWrapper.prototype.check = function (cmd) { | ||
var file = this._parse(this.files); | ||
var global = this._find(this.bin); | ||
var self = this; | ||
var url = this._parse(this.urls); | ||
BinWrapper.prototype.src = function (src, os, arch) { | ||
if (!arguments.length) { | ||
return this._src; | ||
} | ||
cmd = cmd || ['--help']; | ||
cmd = Array.isArray(cmd) ? cmd : [cmd]; | ||
var obj = { url: src, name: path.basename(src) }; | ||
if (global) { | ||
return this._test(global, cmd); | ||
if (os) { | ||
obj.os = os; | ||
} | ||
var dl = Object.getOwnPropertyNames(file).length !== 0 ? [].concat(url, file) : url; | ||
if (arch) { | ||
obj.arch = arch; | ||
} | ||
this._download(dl, this.dest, { | ||
mode: '0755' | ||
}).once('data', function () { | ||
self.emit('download'); | ||
}).on('close', function () { | ||
return self._test(path.join(self.dest, self.bin), cmd); | ||
}); | ||
this._src = this._src.concat(obj); | ||
return this; | ||
@@ -88,29 +55,14 @@ }; | ||
/** | ||
* Download source and build a binary | ||
* Define where to download the binary to | ||
* | ||
* @param {String|Array} cmd | ||
* @param {String} str | ||
* @api public | ||
*/ | ||
BinWrapper.prototype.build = function (cmd) { | ||
var self = this; | ||
var tmp = tempfile(); | ||
var dl = this._download(this.src, tmp, { | ||
mode: '0777', | ||
extract: true, | ||
strip: 1 | ||
}); | ||
BinWrapper.prototype.dest = function (str) { | ||
if (!arguments.length) { | ||
return this._dest; | ||
} | ||
dl.on('close', function () { | ||
exec(cmd, { cwd: tmp }, function (err) { | ||
if (err) { | ||
self.emit('error', err); | ||
} | ||
rm(tmp, function () { | ||
self.emit('finish'); | ||
}); | ||
}); | ||
}); | ||
this._dest = str; | ||
return this; | ||
@@ -120,38 +72,14 @@ }; | ||
/** | ||
* Add a path to check | ||
* Define which file to use as a binary | ||
* | ||
* @param {String} src | ||
* @param {String} str | ||
* @api public | ||
*/ | ||
BinWrapper.prototype.addPath = function (src) { | ||
this.paths.push(src); | ||
return this; | ||
}; | ||
/** | ||
* Add a URL to download | ||
* | ||
* @param {String} url | ||
* @param {String} platform | ||
* @param {String} arch | ||
* @api public | ||
*/ | ||
BinWrapper.prototype.addUrl = function (url, platform, arch) { | ||
var tmp = {}; | ||
if (platform && arch) { | ||
set(tmp, 'platform.' + [platform] + '.arch.' + [arch] + '.url', url); | ||
this.urls = merge(this.urls, tmp); | ||
return this; | ||
BinWrapper.prototype.use = function (str) { | ||
if (!arguments.length) { | ||
return this._use; | ||
} | ||
if (platform) { | ||
set(tmp, 'platform.' + [platform] + '.url', url); | ||
this.urls = merge(this.urls, tmp); | ||
return this; | ||
} | ||
this.urls.url = url; | ||
this._use = path.join(this.dest(), str); | ||
return this; | ||
@@ -161,105 +89,97 @@ }; | ||
/** | ||
* Add a file URL to download | ||
* Run | ||
* | ||
* @param {String|Object} url | ||
* @param {String} platform | ||
* @param {String} arch | ||
* @param {Array} cmd | ||
* @param {Function} cb | ||
* @api public | ||
*/ | ||
BinWrapper.prototype.addFile = function (url, platform, arch) { | ||
var name = path.basename(url); | ||
var tmp = {}; | ||
BinWrapper.prototype.run = function (cmd, cb) { | ||
var download = require('download'); | ||
var self = this; | ||
if (url.url && url.name) { | ||
name = url.name; | ||
url = url.url; | ||
} | ||
this.parse(this.src()); | ||
this.test(cmd, function (err, bin) { | ||
if (err) { | ||
return download(self.src(), self.dest(), { mode: '0755' }) | ||
.on('error', function (err) { | ||
return cb(err); | ||
}) | ||
.on('close', function () { | ||
self.test(cmd, function (err) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
if (platform && arch) { | ||
set(tmp, 'platform.' + [platform] + '.arch.' + [arch] + '.name', name); | ||
set(tmp, 'platform.' + [platform] + '.arch.' + [arch] + '.url', url); | ||
this.files = merge(this.files, tmp); | ||
return this; | ||
} | ||
cb(); | ||
}); | ||
}); | ||
} | ||
if (platform) { | ||
set(tmp, 'platform.' + [platform] + '.name', name); | ||
set(tmp, 'platform.' + [platform] + '.url', url); | ||
this.files = merge(this.files, tmp); | ||
return this; | ||
} | ||
this.files.name = name; | ||
this.files.url = url; | ||
return this; | ||
self.dest(bin); | ||
cb(); | ||
}); | ||
}; | ||
/** | ||
* Add a URL to source code | ||
* Test | ||
* | ||
* @param {String} url | ||
* @param {Array} cmd | ||
* @param {Function} cb | ||
* @api public | ||
*/ | ||
BinWrapper.prototype.addSource = function (url) { | ||
this.src = url; | ||
return this; | ||
}; | ||
BinWrapper.prototype.test = function (cmd, cb) { | ||
var opts = { path: this.dest(), global: this.global, exclude: 'node_modules/.bin' }; | ||
var bin = find(path.basename(this.use()), opts) || []; | ||
var self = this; | ||
/** | ||
* Find binary and check if it's executable | ||
* | ||
* @param {String} bin | ||
* @api private | ||
*/ | ||
if (bin.length > 0) { | ||
return binCheck(bin[0], cmd, function (err, works) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
BinWrapper.prototype._find = function (bin) { | ||
var opts = { path: this.paths, exclude: 'node_modules/.bin' }; | ||
if (!works) { | ||
return cb('command failed'); | ||
} | ||
if (!this.global) { | ||
opts.global = false; | ||
} | ||
if (self.opts.version) { | ||
return binCheck(bin[0], ['--version'], function (err, works, msg) { | ||
if (msg.indexOf(self.opts.version) !== -1) { | ||
return cb(null, bin[0]); | ||
} | ||
var file = findFile(bin, opts); | ||
cb('wrong version'); | ||
}); | ||
} | ||
if (file) { | ||
if (executable.sync(file[0])) { | ||
return file[0]; | ||
} | ||
cb(null, bin[0]); | ||
}); | ||
} | ||
return false; | ||
cb('no binary found'); | ||
}; | ||
/** | ||
* Check if a binary is working by checking its exit code | ||
* Parse | ||
* | ||
* @param {String} bin | ||
* @param {Array} cmd | ||
* @api private | ||
* @param {Object} obj | ||
* @api public | ||
*/ | ||
BinWrapper.prototype._test = function (bin, cmd) { | ||
var self = this; | ||
BinWrapper.prototype.parse = function (obj) { | ||
var ret = []; | ||
binCheck(bin, cmd, function (err, works) { | ||
if (err) { | ||
self.emit('error', err); | ||
obj.filter(function (o) { | ||
if (o.os && o.os === process.platform && o.arch && o.arch === process.arch) { | ||
return ret.push(o); | ||
} else if (o.os && o.os === process.platform && !o.arch) { | ||
return ret.push(o); | ||
} else if (!o.os && !o.arch) { | ||
return ret.push(o); | ||
} | ||
if (self.opts.version && works) { | ||
binCheck(bin, '--version', function (err, works, msg) { | ||
if (msg) { | ||
self.emit(msg.indexOf(self.opts.version) !== -1 ? 'success' : 'fail'); | ||
} else { | ||
self.emit('success'); | ||
} | ||
}); | ||
} else { | ||
self.emit(works ? 'success' : 'fail'); | ||
} | ||
}); | ||
this._src = ret; | ||
return this; | ||
@@ -269,56 +189,2 @@ }; | ||
/** | ||
* Download | ||
* | ||
* @param {String|Object} url | ||
* @param {String} dest | ||
* @param {Object} opts | ||
* @api private | ||
*/ | ||
BinWrapper.prototype._download = function (url, dest, opts) { | ||
var proxy = process.env.http_proxy || | ||
process.env.HTTP_PROXY || | ||
process.env.https_proxy || | ||
process.env.HTTPS_PROXY || | ||
null; | ||
opts.proxy = proxy; | ||
var download = require('download'); | ||
var dl = download(url, dest, opts); | ||
var self = this; | ||
dl.on('error', function (err) { | ||
self.emit('error', err); | ||
}); | ||
return dl; | ||
}; | ||
/** | ||
* Parse object | ||
* | ||
* @param {Object} opts | ||
* @api private | ||
*/ | ||
BinWrapper.prototype._parse = function (opts) { | ||
var platform = process.platform; | ||
var arch = process.arch === 'x64' ? 'x64' : process.arch === 'arm' ? 'arm' : 'x86'; | ||
if (opts.platform && opts.platform.hasOwnProperty([platform])) { | ||
opts = merge(opts, opts.platform[platform]); | ||
} | ||
if (opts.arch && opts.arch.hasOwnProperty([arch])) { | ||
opts = merge(opts, opts.arch[arch]); | ||
} | ||
delete opts.platform; | ||
delete opts.arch; | ||
return opts; | ||
}; | ||
/** | ||
* Module exports | ||
@@ -325,0 +191,0 @@ */ |
{ | ||
"name": "bin-wrapper", | ||
"version": "0.2.4", | ||
"version": "0.3.0", | ||
"description": "Binary wrapper that makes your programs seamlessly available as local dependencies", | ||
@@ -30,11 +30,8 @@ "license": "MIT", | ||
"download": "^0.1.2", | ||
"executable": "^0.1.0", | ||
"find-file": "^0.1.2", | ||
"mout": "^0.9.1", | ||
"rimraf": "^2.2.6", | ||
"tempfile": "^0.1.2" | ||
"find-file": "^0.1.2" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^1.18.2" | ||
"mocha": "^1.18.2", | ||
"rimraf": "^2.2.6" | ||
} | ||
} |
@@ -15,27 +15,22 @@ # bin-wrapper [![Build Status](https://travis-ci.org/kevva/bin-wrapper.svg?branch=master)](https://travis-ci.org/kevva/bin-wrapper) | ||
var BinWrapper = require('bin-wrapper'); | ||
var bin = new BinWrapper({ bin: 'gifsicle', version: '1.71', dest: 'vendor' }); | ||
var bin = new BinWrapper({ version: 1.80, global: true }); | ||
bin | ||
.addUrl('https://raw.github.com/yeoman/node-gifsicle/0.1.4/vendor/osx/gifsicle', 'darwin') | ||
.addUrl('https://raw.github.com/yeoman/node-gifsicle/0.1.4/vendor/linux/x64/gifsicle', 'linux', 'x64') | ||
.addSource('http://www.lcdf.org/gifsicle/gifsicle-1.71.tar.gz') | ||
.check() | ||
.on('error', function (err) { | ||
console.log(err); | ||
.src('https://raw.github.com/yeoman/node-jpegtran-bin/0.2.4/vendor/win/x64/jpegtran.exe', 'win32', 'x64') | ||
.src('https://raw.github.com/yeoman/node-jpegtran-bin/0.2.4/vendor/win/x64/libjpeg-62.dll', 'win32', 'x64') | ||
.dest('vendor') | ||
.use('jpegtran.exe') | ||
.run(['--version'], function (err) { | ||
if (err) { | ||
throw err; | ||
} | ||
console.log('jpegtran is working'); | ||
}); | ||
.on('fail', function () { | ||
this.build('./configure && make && make install') | ||
}) | ||
.on('success', function () { | ||
console.log('gifsicle is working'); | ||
}) | ||
.on('finish', function () { | ||
console.log('gifsicle rebuilt successfully!') | ||
}) | ||
``` | ||
Get the path to your binary with `bin.path`: | ||
Get the path to your binary with `bin.use`: | ||
```js | ||
console.log(bin.path); // => path/to/vendor/gifsicle | ||
console.log(bin.use); // => path/to/vendor/jpegtran.exe | ||
``` | ||
@@ -47,47 +42,24 @@ | ||
Creates a new `BinWrapper`. Available options are `bin` which is the name of the | ||
binary and `dest` which is where to download/build the binary to. | ||
Creates a new `BinWrapper` instance. Use the `version` option to define a specific | ||
version and the `global` option to enable or disable global checking. | ||
### .check(cmd) | ||
### .src(str) | ||
Check if a binary is present and working. If it isn't, download and test it by | ||
running the binary with `cmd` and see if it exits correctly. | ||
Accepts a URL pointing to a file to download. | ||
Emits `success` if the binary is working and `fail` if the binary failed to exit with | ||
status code `0`. | ||
### .dest(str) | ||
### .build(cmd) | ||
Accepts a path which the files will be downloaded to. | ||
Download the source archive defined in the `src` property and build it using the | ||
build script defined in the `cmd` argument. | ||
### .use(str) | ||
Emits `finish` when build is finished successfully. | ||
Define which file to use as the binary. | ||
### .addPath(src) | ||
### .run(cb) | ||
Add a path where to check for the binary. By default `dest` is added to paths. | ||
Runs the search for the binary. If no binary is found it will download the file using the URL | ||
provided in `.src()`. It will also check that the binary is working by checking it's exit code. | ||
### .addUrl(url, platform, arch) | ||
Add a URL to download the binary from. Use `platform` and `arch` to target a | ||
specific system. | ||
### .addFile(url, platform, arch) | ||
Add a file to download alongside with the binary. Use `platform` and `arch` to | ||
target a specific system. | ||
### .addSource(url) | ||
Add a URL where to download the source code from. | ||
## Options | ||
### bin | ||
Type: `String` | ||
Default: `undefined` | ||
Set the name of the binary. | ||
### version | ||
@@ -107,11 +79,4 @@ | ||
### dest | ||
Type: `String` | ||
Default: `process.cwd()` | ||
Destination to download/build binary. | ||
## License | ||
[MIT License](http://en.wikipedia.org/wiki/MIT_License) © [Kevin Mårtensson](http://kevinmartensson.com) | ||
MIT © [Kevin Mårtensson](http://kevinmartensson.com) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
3
1
6193
2
153
80
- Removedexecutable@^0.1.0
- Removedmout@^0.9.1
- Removedrimraf@^2.2.6
- Removedtempfile@^0.1.2
- Removedmout@0.9.1(transitive)