magicbell-cli 1.2.0 → 1.3.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/CHANGELOG.md +6 -0
- package/package.json +2 -6
- package/src/cli.js +50 -0
- package/src/install.js +55 -118
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# magicbell-cli
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#7410](https://github.com/magicbell/magicbell/pull/7410) [`0554378`](https://github.com/magicbell/magicbell/commit/05543786fcbb67db85079f3a5a920bcfdd54aea8) Thanks [@smeijer](https://github.com/smeijer)! - regen
|
|
8
|
+
|
|
3
9
|
## 1.2.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magicbell-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "MagicBell CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -8,13 +8,9 @@
|
|
|
8
8
|
"tar": "^7.5.2"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
|
-
"magicbell": "
|
|
11
|
+
"magicbell": "src/cli.js"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"postinstall": "node src/install.js install",
|
|
15
|
-
"preuninstall": "node src/install.js uninstall",
|
|
16
|
-
"prepack": "npx -y pinst --enable",
|
|
17
|
-
"postpack": "npx -y pinst --disable",
|
|
18
14
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
19
15
|
},
|
|
20
16
|
"author": "MagicBell",
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
import { installBinary } from './install.js';
|
|
8
|
+
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const BIN_DIR = path.resolve(__dirname, '../bin');
|
|
11
|
+
const BINARY_NAME = process.platform === 'win32' ? 'magicbell.exe' : 'magicbell';
|
|
12
|
+
const BINARY_PATH = path.join(BIN_DIR, BINARY_NAME);
|
|
13
|
+
|
|
14
|
+
async function ensureBinary() {
|
|
15
|
+
if (fs.existsSync(BINARY_PATH)) return;
|
|
16
|
+
await installBinary();
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(BINARY_PATH)) {
|
|
19
|
+
throw new Error(`MagicBell binary is missing at ${BINARY_PATH} even after installation.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function run() {
|
|
24
|
+
try {
|
|
25
|
+
await ensureBinary();
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.error(err instanceof Error ? err.message : err);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const child = spawn(BINARY_PATH, process.argv.slice(2), {
|
|
32
|
+
stdio: 'inherit',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
child.on('error', (error) => {
|
|
36
|
+
console.error('Failed to start the MagicBell binary:', error.message);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
child.on('exit', (code, signal) => {
|
|
41
|
+
if (signal) {
|
|
42
|
+
process.kill(process.pid, signal);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
process.exit(code ?? 0);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
run();
|
package/src/install.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// based on https://github.com/Nelwhix/go-npm/blob/main/src/index.js
|
|
2
|
+
// adjustments made so bin is installed to ./bin,
|
|
3
|
+
// and used via a lazy-load mechanism instead of during postinstall
|
|
3
4
|
|
|
4
|
-
/* eslint-disable no-console */
|
|
5
|
-
|
|
6
|
-
// copy from https://github.com/Nelwhix/go-npm/blob/main/src/index.js
|
|
7
|
-
// adjustments made so bin is installed to ./bin instead of node global .bin folder
|
|
8
|
-
|
|
9
|
-
import { exec } from 'child_process';
|
|
10
5
|
import fs from 'fs';
|
|
11
6
|
import fetch from 'node-fetch';
|
|
12
7
|
import path from 'path';
|
|
13
8
|
import * as tar from 'tar';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
14
10
|
import zlib from 'zlib';
|
|
15
11
|
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
15
|
+
|
|
16
16
|
// Mapping from Node's `process.arch` to Golang's `$GOARCH`
|
|
17
17
|
const ARCH_MAPPING = {
|
|
18
18
|
ia32: '386',
|
|
@@ -29,43 +29,7 @@ const PLATFORM_MAPPING = {
|
|
|
29
29
|
freebsd: 'freebsd',
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
function getInstallationPath(callback) {
|
|
34
|
-
exec('npm --v', (err, stdout, _stderr) => {
|
|
35
|
-
const npmVersion = parseFloat(stdout.trim());
|
|
36
|
-
|
|
37
|
-
// npm bin was deprecated after v9 https://github.blog/changelog/2022-10-24-npm-v9-0-0-released/
|
|
38
|
-
if (npmVersion < 9) {
|
|
39
|
-
exec('npm bin -g', (err, stdout, stderr) => {
|
|
40
|
-
let dir = null;
|
|
41
|
-
|
|
42
|
-
if (err || stderr || !stdout || stdout.length === 0) {
|
|
43
|
-
throw new Error('Could not get installation path');
|
|
44
|
-
} else {
|
|
45
|
-
dir = stdout.trim();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
49
|
-
callback(null, dir);
|
|
50
|
-
});
|
|
51
|
-
} else {
|
|
52
|
-
exec('npm prefix -g', (err, stdout, stderr) => {
|
|
53
|
-
let dir = null;
|
|
54
|
-
|
|
55
|
-
if (err || stderr || !stdout || stdout.length === 0) {
|
|
56
|
-
throw new Error('Could not get installation path');
|
|
57
|
-
} else {
|
|
58
|
-
dir = stdout.trim() + '/bin';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
-
callback(null, dir);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function verifyAndPlaceBinary(binName, binPath, callback) {
|
|
32
|
+
function verifyAndPlaceBinary(binName, binPath) {
|
|
69
33
|
const targetPath = path.join(binPath, binName);
|
|
70
34
|
|
|
71
35
|
if (!fs.existsSync(targetPath)) {
|
|
@@ -77,8 +41,6 @@ function verifyAndPlaceBinary(binName, binPath, callback) {
|
|
|
77
41
|
} catch (err) {
|
|
78
42
|
// ignore on Windows
|
|
79
43
|
}
|
|
80
|
-
|
|
81
|
-
callback();
|
|
82
44
|
}
|
|
83
45
|
|
|
84
46
|
function validateConfiguration(packageJson) {
|
|
@@ -103,34 +65,28 @@ function validateConfiguration(packageJson) {
|
|
|
103
65
|
}
|
|
104
66
|
}
|
|
105
67
|
|
|
106
|
-
function
|
|
68
|
+
function loadConfiguration() {
|
|
107
69
|
if (!(process.arch in ARCH_MAPPING)) {
|
|
108
|
-
|
|
109
|
-
return;
|
|
70
|
+
throw new Error('Installation is not supported for this architecture: ' + process.arch);
|
|
110
71
|
}
|
|
111
72
|
|
|
112
73
|
if (!(process.platform in PLATFORM_MAPPING)) {
|
|
113
|
-
|
|
114
|
-
return;
|
|
74
|
+
throw new Error('Installation is not supported for this platform: ' + process.platform);
|
|
115
75
|
}
|
|
116
76
|
|
|
117
|
-
const packageJsonPath = path.join(
|
|
77
|
+
const packageJsonPath = path.join(PACKAGE_ROOT, 'package.json');
|
|
118
78
|
if (!fs.existsSync(packageJsonPath)) {
|
|
119
|
-
|
|
120
|
-
'Unable to find package.json. ' + 'Please run this script at root of the package you want to be installed',
|
|
121
|
-
);
|
|
122
|
-
return;
|
|
79
|
+
throw new Error('Unable to find package.json. Please run this script at the root of the package.');
|
|
123
80
|
}
|
|
124
81
|
|
|
125
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
|
|
82
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
126
83
|
const error = validateConfiguration(packageJson);
|
|
127
84
|
if (error && error.length > 0) {
|
|
128
|
-
|
|
129
|
-
return;
|
|
85
|
+
throw new Error('Invalid package.json: ' + error);
|
|
130
86
|
}
|
|
131
87
|
|
|
132
88
|
let binName = packageJson.goBinary.name;
|
|
133
|
-
const binPath = packageJson.goBinary.path;
|
|
89
|
+
const binPath = path.resolve(PACKAGE_ROOT, packageJson.goBinary.path);
|
|
134
90
|
let url = packageJson.goBinary.url;
|
|
135
91
|
let version = packageJson.goBinary.binaryVersion || packageJson.version;
|
|
136
92
|
if (version[0] === 'v') version = version.substr(1);
|
|
@@ -146,10 +102,10 @@ function parsePackageJson() {
|
|
|
146
102
|
url = url.replace(/{{bin_name}}/g, binName);
|
|
147
103
|
|
|
148
104
|
return {
|
|
149
|
-
binName
|
|
150
|
-
binPath
|
|
151
|
-
url
|
|
152
|
-
version
|
|
105
|
+
binName,
|
|
106
|
+
binPath,
|
|
107
|
+
url,
|
|
108
|
+
version,
|
|
153
109
|
};
|
|
154
110
|
}
|
|
155
111
|
|
|
@@ -161,66 +117,47 @@ function parsePackageJson() {
|
|
|
161
117
|
*
|
|
162
118
|
* See: https://docs.npmjs.com/files/package.json#bin
|
|
163
119
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const options = parsePackageJson();
|
|
167
|
-
if (!options) {
|
|
168
|
-
throw new Error(INVALID_INPUT);
|
|
169
|
-
}
|
|
120
|
+
export function installBinary() {
|
|
121
|
+
const options = loadConfiguration();
|
|
170
122
|
|
|
171
123
|
fs.mkdirSync(options.binPath, { recursive: true });
|
|
172
124
|
const ungz = zlib.createGunzip();
|
|
173
125
|
const untar = tar.x({ cwd: options.binPath });
|
|
174
126
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
let settled = false;
|
|
129
|
+
const finish = (action, value) => {
|
|
130
|
+
if (settled) return;
|
|
131
|
+
settled = true;
|
|
132
|
+
action(value);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleError = (err) => finish(reject, err);
|
|
136
|
+
const handleSuccess = () => finish(resolve);
|
|
137
|
+
|
|
138
|
+
// First we will Un-GZip, then we will untar. So once untar is completed,
|
|
139
|
+
// binary is downloaded into `binPath`. Verify the binary and call it good
|
|
140
|
+
untar.on('end', () => {
|
|
141
|
+
try {
|
|
142
|
+
verifyAndPlaceBinary(options.binName, options.binPath);
|
|
143
|
+
handleSuccess();
|
|
144
|
+
} catch (err) {
|
|
145
|
+
handleError(err);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
191
148
|
|
|
192
|
-
|
|
193
|
-
|
|
149
|
+
ungz.on('error', handleError);
|
|
150
|
+
untar.on('error', handleError);
|
|
194
151
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
152
|
+
fetch(options.url)
|
|
153
|
+
.then((res) => {
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
throw new Error('Error downloading binary. HTTP Status Code: ' + res.status);
|
|
156
|
+
}
|
|
199
157
|
|
|
200
|
-
|
|
201
|
-
|
|
158
|
+
res.body.on('error', handleError);
|
|
159
|
+
res.body.pipe(ungz).pipe(untar);
|
|
160
|
+
})
|
|
161
|
+
.catch(handleError);
|
|
202
162
|
});
|
|
203
163
|
}
|
|
204
|
-
|
|
205
|
-
const actions = {
|
|
206
|
-
install: install,
|
|
207
|
-
uninstall: uninstall,
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const argv = process.argv;
|
|
211
|
-
if (argv && argv.length > 2) {
|
|
212
|
-
const cmd = process.argv[2];
|
|
213
|
-
if (!actions[cmd]) {
|
|
214
|
-
console.log('Invalid command to go-npm. `install` and `uninstall` are the only supported commands');
|
|
215
|
-
process.exit(1);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
actions[cmd](() => {
|
|
220
|
-
process.exit(0);
|
|
221
|
-
});
|
|
222
|
-
} catch (err) {
|
|
223
|
-
console.error(err);
|
|
224
|
-
process.exit(1);
|
|
225
|
-
}
|
|
226
|
-
}
|