@xhmikosr/bin-wrapper 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +186 -0
- package/license +9 -0
- package/package.json +60 -0
- package/readme.md +133 -0
package/index.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {promises as fs} from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import binCheck from 'bin-check';
|
|
4
|
+
import binVersionCheck from 'bin-version-check';
|
|
5
|
+
import download from '@xhmikosr/downloader';
|
|
6
|
+
import osFilterObject from 'os-filter-obj';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialize a new `BinWrapper`
|
|
10
|
+
*
|
|
11
|
+
* @param {Object} options
|
|
12
|
+
* @api public
|
|
13
|
+
*/
|
|
14
|
+
export default class BinWrapper {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
|
|
18
|
+
if (this.options.strip <= 0) {
|
|
19
|
+
this.options.strip = 0;
|
|
20
|
+
} else if (!this.options.strip) {
|
|
21
|
+
this.options.strip = 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get or set files to download
|
|
27
|
+
*
|
|
28
|
+
* @param {String} src
|
|
29
|
+
* @param {String} os
|
|
30
|
+
* @param {String} arch
|
|
31
|
+
* @api public
|
|
32
|
+
*/
|
|
33
|
+
src(src, os, arch) {
|
|
34
|
+
if (arguments.length === 0) {
|
|
35
|
+
return this._src;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this._src = this._src || [];
|
|
39
|
+
this._src.push({
|
|
40
|
+
url: src,
|
|
41
|
+
os,
|
|
42
|
+
arch,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get or set the destination
|
|
50
|
+
*
|
|
51
|
+
* @param {String} dest
|
|
52
|
+
* @api public
|
|
53
|
+
*/
|
|
54
|
+
dest(dest) {
|
|
55
|
+
if (arguments.length === 0) {
|
|
56
|
+
return this._dest;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this._dest = dest;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get or set the binary
|
|
65
|
+
*
|
|
66
|
+
* @param {String} bin
|
|
67
|
+
* @api public
|
|
68
|
+
*/
|
|
69
|
+
use(bin) {
|
|
70
|
+
if (arguments.length === 0) {
|
|
71
|
+
return this._use;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this._use = bin;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get or set a semver range to test the binary against
|
|
80
|
+
*
|
|
81
|
+
* @param {String} range
|
|
82
|
+
* @api public
|
|
83
|
+
*/
|
|
84
|
+
version(range) {
|
|
85
|
+
if (arguments.length === 0) {
|
|
86
|
+
return this._version;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this._version = range;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get path to the binary
|
|
95
|
+
*
|
|
96
|
+
* @api public
|
|
97
|
+
*/
|
|
98
|
+
path() {
|
|
99
|
+
return path.join(this.dest(), this.use());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Run
|
|
104
|
+
*
|
|
105
|
+
* @param {Array} cmd
|
|
106
|
+
* @api public
|
|
107
|
+
*/
|
|
108
|
+
run(cmd = ['--version']) {
|
|
109
|
+
return this.findExisting().then(() => {
|
|
110
|
+
if (this.options.skipCheck) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return this.runCheck(cmd);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Run binary check
|
|
120
|
+
*
|
|
121
|
+
* @param {Array} cmd
|
|
122
|
+
* @api private
|
|
123
|
+
*/
|
|
124
|
+
runCheck(cmd) {
|
|
125
|
+
return binCheck(this.path(), cmd).then(works => {
|
|
126
|
+
if (!works) {
|
|
127
|
+
throw new Error(`The \`${this.path()}\` binary doesn't seem to work correctly`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (this.version()) {
|
|
131
|
+
return binVersionCheck(this.path(), this.version());
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Find existing files
|
|
138
|
+
*
|
|
139
|
+
* @api private
|
|
140
|
+
*/
|
|
141
|
+
findExisting() {
|
|
142
|
+
return fs.stat(this.path()).catch(error => {
|
|
143
|
+
if (error && error.code === 'ENOENT') {
|
|
144
|
+
return this.download();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
throw error;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Download files
|
|
153
|
+
*
|
|
154
|
+
* @api private
|
|
155
|
+
*/
|
|
156
|
+
download() {
|
|
157
|
+
const files = osFilterObject(this.src() || []);
|
|
158
|
+
|
|
159
|
+
if (files.length === 0) {
|
|
160
|
+
return Promise.reject(new Error('No binary found matching your system. It\'s probably not supported.'));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const urls = [];
|
|
164
|
+
for (const file of files) {
|
|
165
|
+
urls.push(file.url);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return Promise.all(urls.map(url => download(url, this.dest(), {
|
|
169
|
+
extract: true,
|
|
170
|
+
strip: this.options.strip,
|
|
171
|
+
}))).then(result => {
|
|
172
|
+
const resultingFiles = result.flatMap((item, index) => {
|
|
173
|
+
if (Array.isArray(item)) {
|
|
174
|
+
return item.map(file => file.path);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const parsedUrl = new URL(files[index].url);
|
|
178
|
+
const parsedPath = path.parse(parsedUrl.pathname);
|
|
179
|
+
|
|
180
|
+
return parsedPath.base;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return Promise.all(resultingFiles.map(fileName => fs.chmod(path.join(this.dest(), fileName), 0o755)));
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
package/license
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xhmikosr/bin-wrapper",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "Binary wrapper that makes your programs seamlessly available as local dependencies",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": "XhmikosR/bin-wrapper",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"author": {
|
|
11
|
+
"name": "Kevin Mårtensson",
|
|
12
|
+
"email": "kevinmartensson@gmail.com",
|
|
13
|
+
"url": "https://github.com/kevva"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": "^12.20.0 || ^14.14.0 || >=16.0.0"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"ava": "ava",
|
|
20
|
+
"xo": "xo",
|
|
21
|
+
"test": "npm run xo && npm run ava",
|
|
22
|
+
"test-ci": "npm run xo && c8 ava"
|
|
23
|
+
},
|
|
24
|
+
"main": "index.js",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": "./index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"index.js"
|
|
31
|
+
],
|
|
32
|
+
"keywords": [
|
|
33
|
+
"bin",
|
|
34
|
+
"check",
|
|
35
|
+
"local",
|
|
36
|
+
"wrapper"
|
|
37
|
+
],
|
|
38
|
+
"c8": {
|
|
39
|
+
"reporter": [
|
|
40
|
+
"lcovonly",
|
|
41
|
+
"text"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@xhmikosr/downloader": "^9.0.0",
|
|
46
|
+
"bin-check": "^4.1.0",
|
|
47
|
+
"bin-version-check": "^5.0.0",
|
|
48
|
+
"os-filter-obj": "^2.0.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"ava": "^4.3.0",
|
|
52
|
+
"c8": "^7.11.3",
|
|
53
|
+
"executable": "^4.1.1",
|
|
54
|
+
"nock": "^13.2.6",
|
|
55
|
+
"path-exists": "^5.0.0",
|
|
56
|
+
"rimraf": "^3.0.2",
|
|
57
|
+
"tempy": "^2.0.0",
|
|
58
|
+
"xo": "^0.49.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# bin-wrapper [](https://github.com/XhmikosR/bin-wrapper/actions/workflows/ci.yml)
|
|
2
|
+
|
|
3
|
+
> Binary wrapper that makes your programs seamlessly available as local dependencies
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install bin-wrapper
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
import BinWrapper from 'bin-wrapper';
|
|
18
|
+
|
|
19
|
+
const base = 'https://github.com/imagemin/gifsicle-bin/raw/main/vendor';
|
|
20
|
+
const bin = new BinWrapper()
|
|
21
|
+
.src(`${base}/macos/gifsicle`, 'darwin')
|
|
22
|
+
.src(`${base}/linux/x64/gifsicle`, 'linux', 'x64')
|
|
23
|
+
.src(`${base}/win/x64/gifsicle.exe`, 'win32', 'x64')
|
|
24
|
+
.dest(path.join('vendor'))
|
|
25
|
+
.use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle')
|
|
26
|
+
.version('>=1.71');
|
|
27
|
+
|
|
28
|
+
(async () => {
|
|
29
|
+
await bin.run(['--version']);
|
|
30
|
+
console.log('gifsicle is working');
|
|
31
|
+
})();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Get the path to your binary with `bin.path()`:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
console.log(bin.path());
|
|
38
|
+
//=> 'path/to/vendor/gifsicle'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### `new BinWrapper(options)`
|
|
45
|
+
|
|
46
|
+
Creates a new `BinWrapper` instance.
|
|
47
|
+
|
|
48
|
+
#### options
|
|
49
|
+
|
|
50
|
+
Type: `Object`
|
|
51
|
+
|
|
52
|
+
##### skipCheck
|
|
53
|
+
|
|
54
|
+
* Type: `boolean`
|
|
55
|
+
* Default: `false`
|
|
56
|
+
|
|
57
|
+
Whether to skip the binary check or not.
|
|
58
|
+
|
|
59
|
+
##### strip
|
|
60
|
+
|
|
61
|
+
* Type: `number`
|
|
62
|
+
* Default: `1`
|
|
63
|
+
|
|
64
|
+
Strip a number of leading paths from file names on extraction.
|
|
65
|
+
|
|
66
|
+
### .src(url, [os], [arch])
|
|
67
|
+
|
|
68
|
+
Adds a source to download.
|
|
69
|
+
|
|
70
|
+
#### url
|
|
71
|
+
|
|
72
|
+
Type: `string`
|
|
73
|
+
|
|
74
|
+
Accepts a URL pointing to a file to download.
|
|
75
|
+
|
|
76
|
+
#### os
|
|
77
|
+
|
|
78
|
+
Type: `string`
|
|
79
|
+
|
|
80
|
+
Tie the source to a specific OS.
|
|
81
|
+
|
|
82
|
+
#### arch
|
|
83
|
+
|
|
84
|
+
Type: `string`
|
|
85
|
+
|
|
86
|
+
Tie the source to a specific arch.
|
|
87
|
+
|
|
88
|
+
### .dest(destination)
|
|
89
|
+
|
|
90
|
+
#### destination
|
|
91
|
+
|
|
92
|
+
Type: `string`
|
|
93
|
+
|
|
94
|
+
Accepts a path which the files will be downloaded to.
|
|
95
|
+
|
|
96
|
+
### .use(binary)
|
|
97
|
+
|
|
98
|
+
#### binary
|
|
99
|
+
|
|
100
|
+
Type: `string`
|
|
101
|
+
|
|
102
|
+
Define which file to use as the binary.
|
|
103
|
+
|
|
104
|
+
### .path()
|
|
105
|
+
|
|
106
|
+
Returns the full path to your binary.
|
|
107
|
+
|
|
108
|
+
### .version(range)
|
|
109
|
+
|
|
110
|
+
#### range
|
|
111
|
+
|
|
112
|
+
Type: `string`
|
|
113
|
+
|
|
114
|
+
Define a [semver range](https://github.com/npm/node-semver#ranges) to check
|
|
115
|
+
the binary against.
|
|
116
|
+
|
|
117
|
+
### .run([arguments])
|
|
118
|
+
|
|
119
|
+
Runs the search for the binary. If no binary is found it will download the file
|
|
120
|
+
using the URL provided in `.src()`.
|
|
121
|
+
|
|
122
|
+
#### arguments
|
|
123
|
+
|
|
124
|
+
* Type: `Array`
|
|
125
|
+
* Default: `['--version']`
|
|
126
|
+
|
|
127
|
+
Command to run the binary with. If it exits with code `0` it means that the
|
|
128
|
+
binary is working.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT © [Kevin Mårtensson](http://kevinmartensson.com)
|