bvm-core 1.1.13 → 1.1.15
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/README.md +9 -3
- package/README.zh-CN.md +9 -3
- package/dist/index.js +33 -32
- package/install.ps1 +103 -218
- package/install.sh +105 -282
- package/package.json +5 -5
- package/scripts/postinstall.js +238 -143
package/scripts/postinstall.js
CHANGED
|
@@ -2,79 +2,83 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* BVM Post-install Script
|
|
5
|
-
*
|
|
5
|
+
* Standardized Installation Workflow:
|
|
6
|
+
* 1. Init & Deploy Assets
|
|
7
|
+
* 2. Detect System Bun
|
|
8
|
+
* 3. Smoke Test System Bun
|
|
9
|
+
* 4. Configure Runtime (Reuse or Download)
|
|
10
|
+
* 5. Setup Shell Environment
|
|
6
11
|
*/
|
|
7
12
|
|
|
8
13
|
const fs = require('fs');
|
|
9
14
|
const path = require('path');
|
|
10
15
|
const { spawnSync } = require('child_process');
|
|
16
|
+
const os = require('os');
|
|
11
17
|
|
|
18
|
+
// --- Constants & Config ---
|
|
19
|
+
const ASCII_LOGO = `
|
|
20
|
+
\x1b[36m
|
|
21
|
+
__________
|
|
22
|
+
\______ \__ _______
|
|
23
|
+
| | _| \/ / \
|
|
24
|
+
| | \\ / Y Y \
|
|
25
|
+
|______ / \_/|__|_| /
|
|
26
|
+
\/ \/
|
|
27
|
+
\x1b[0m`;
|
|
28
|
+
|
|
29
|
+
const HOME = process.env.HOME || os.homedir();
|
|
30
|
+
const BVM_DIR = process.env.BVM_DIR || path.join(HOME, '.bvm');
|
|
31
|
+
const BVM_SRC_DIR = path.join(BVM_DIR, 'src');
|
|
32
|
+
const BVM_BIN_DIR = path.join(BVM_DIR, 'bin');
|
|
33
|
+
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
34
|
+
const DIST_DIR = path.join(PKG_ROOT, 'dist');
|
|
35
|
+
const LOG_FILE = path.join(os.tmpdir(), 'bvm-install.log');
|
|
36
|
+
|
|
37
|
+
// --- Helpers ---
|
|
12
38
|
function log(msg) {
|
|
13
|
-
|
|
39
|
+
const line = `[bvm] ${msg}`;
|
|
40
|
+
process.stdout.write(line + '\n');
|
|
41
|
+
try { fs.appendFileSync(LOG_FILE, line + '\n'); } catch(e) {}
|
|
14
42
|
}
|
|
15
43
|
|
|
16
44
|
function error(msg) {
|
|
17
|
-
|
|
45
|
+
const line = `[bvm] ERROR: ${msg}`;
|
|
46
|
+
process.stderr.write(`\x1b[31m${line}\x1b[0m\n`);
|
|
47
|
+
try { fs.appendFileSync(LOG_FILE, line + '\n'); } catch(e) {}
|
|
18
48
|
}
|
|
19
49
|
|
|
20
|
-
|
|
21
|
-
|
|
50
|
+
function ensureDir(dir) {
|
|
51
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
52
|
+
}
|
|
22
53
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const isBun = (process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes('bun/')) ||
|
|
28
|
-
(process.versions && process.versions.bun) ||
|
|
29
|
-
process.isBun;
|
|
30
|
-
|
|
31
|
-
log(`Environment: TTY=${!!isTTY}, CI=${isCI}, isBun=${!!isBun}`);
|
|
32
|
-
if (isBun) {
|
|
33
|
-
log('Detected Bun installation. Optimizing setup...');
|
|
34
|
-
}
|
|
54
|
+
function ensureVersionPrefix(version) {
|
|
55
|
+
if (!version) return 'v0.0.0';
|
|
56
|
+
return version.startsWith('v') ? version : `v${version}`;
|
|
57
|
+
}
|
|
35
58
|
|
|
36
|
-
|
|
37
|
-
const HOME = process.env.HOME || require('os').homedir();
|
|
38
|
-
const BVM_DIR = process.env.BVM_DIR || path.join(HOME, '.bvm');
|
|
39
|
-
const BVM_SRC_DIR = path.join(BVM_DIR, 'src');
|
|
40
|
-
const BVM_BIN_DIR = path.join(BVM_DIR, 'bin');
|
|
41
|
-
|
|
42
|
-
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
43
|
-
const DIST_DIR = path.join(PKG_ROOT, 'dist');
|
|
44
|
-
const BVM_EXEC = path.join(BVM_BIN_DIR, 'bvm');
|
|
59
|
+
// --- Core Logic ---
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
function main() {
|
|
62
|
+
// Force a leading newline to break from npm's output
|
|
63
|
+
process.stdout.write('\n' + ASCII_LOGO + '\n');
|
|
64
|
+
log('Starting BVM post-install setup...');
|
|
48
65
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
// 1. Conflict Detection
|
|
67
|
+
const BVM_EXEC = path.join(BVM_BIN_DIR, 'bvm');
|
|
68
|
+
if (fs.existsSync(BVM_EXEC) && !process.env.BVM_FORCE_INSTALL) {
|
|
52
69
|
try {
|
|
53
70
|
const content = fs.readFileSync(BVM_EXEC, 'utf-8');
|
|
54
|
-
if (content.includes('
|
|
55
|
-
|
|
71
|
+
if (!content.includes('BVM_INSTALL_SOURCE="npm"')) {
|
|
72
|
+
log('Native BVM installation detected. Proceeding to update assets...');
|
|
56
73
|
}
|
|
57
74
|
} catch (e) {}
|
|
58
|
-
|
|
59
|
-
if (isNpmInstall) {
|
|
60
|
-
log('Detected existing npm installation. Proceeding with update...');
|
|
61
|
-
forceInstall = true;
|
|
62
|
-
} else if (!forceInstall) {
|
|
63
|
-
error(`Conflict detected: ${BVM_EXEC} already exists (Native installation).`);
|
|
64
|
-
error('Please run "bvm upgrade" to update your native BVM installation.');
|
|
65
|
-
error('To force overwrite, run with BVM_FORCE_INSTALL=true');
|
|
66
|
-
process.exit(1);
|
|
67
|
-
} else {
|
|
68
|
-
log('BVM_FORCE_INSTALL set. Overwriting existing installation.');
|
|
69
|
-
}
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
//
|
|
77
|
+
// 2. Deploy Assets
|
|
73
78
|
log(`Deploying to ${BVM_DIR}...`);
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
ensureDir(BVM_SRC_DIR);
|
|
80
|
+
ensureDir(BVM_BIN_DIR);
|
|
76
81
|
|
|
77
|
-
// --- 3. Copy Files ---
|
|
78
82
|
const filesToCopy = [
|
|
79
83
|
{ src: 'index.js', destDir: BVM_SRC_DIR, name: 'index.js' },
|
|
80
84
|
{ src: 'bvm-shim.sh', destDir: BVM_BIN_DIR, name: 'bvm-shim.sh', mode: 0o755 },
|
|
@@ -86,119 +90,210 @@ async function main() {
|
|
|
86
90
|
const destPath = path.join(file.destDir, file.name);
|
|
87
91
|
|
|
88
92
|
if (fs.existsSync(srcPath)) {
|
|
89
|
-
log(`Copying ${file.src} -> ${destPath}`);
|
|
90
93
|
fs.copyFileSync(srcPath, destPath);
|
|
91
|
-
if (file.mode)
|
|
92
|
-
fs.chmodSync(destPath, file.mode);
|
|
93
|
-
}
|
|
94
|
+
if (file.mode) fs.chmodSync(destPath, file.mode);
|
|
94
95
|
} else {
|
|
95
96
|
error(`Source file not found: ${srcPath}`);
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
-
// --- 4. Runtime Bootstrapping (Scenario 2) ---
|
|
100
|
-
const currentRuntime = path.join(BVM_DIR, 'current');
|
|
101
|
-
|
|
102
|
-
const wrapperContent = `#!/bin/bash
|
|
103
|
-
export BVM_DIR="${BVM_DIR}"
|
|
104
|
-
export BVM_INSTALL_SOURCE="npm"
|
|
105
|
-
# 1. Try internal runtime
|
|
106
|
-
if [ -x "\${BVM_DIR}/current/bin/bun" ]; then
|
|
107
|
-
exec "\${BVM_DIR}/current/bin/bun" "\${BVM_DIR}/src/index.js" "$@"
|
|
108
|
-
# 2. Try global/system bun
|
|
109
|
-
elif command -v bun >/dev/null 2>&1; then
|
|
110
|
-
exec bun "\${BVM_DIR}/src/index.js" "$@"
|
|
111
|
-
else
|
|
112
|
-
echo "Error: BVM requires Bun. Please install Bun or ensure it is in your PATH."
|
|
113
|
-
exit 1
|
|
114
|
-
fi
|
|
115
|
-
`;
|
|
116
99
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Check if current process is Bun
|
|
125
|
-
if (process.versions && process.versions.bun) {
|
|
126
|
-
sysBun = process.execPath;
|
|
127
|
-
hostVer = process.versions.bun;
|
|
128
|
-
} else {
|
|
129
|
-
// Try PATH
|
|
130
|
-
const whichBun = spawnSync('which', ['bun'], { encoding: 'utf-8' });
|
|
131
|
-
if (whichBun.status === 0 && whichBun.stdout) {
|
|
132
|
-
sysBun = whichBun.stdout.trim();
|
|
133
|
-
const verOut = spawnSync(sysBun, ['--version'], { encoding: 'utf-8' });
|
|
134
|
-
if (verOut.status === 0) {
|
|
135
|
-
hostVer = verOut.stdout.trim().replace(/^v/, '');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
100
|
+
// 3. Detect & Configure Runtime
|
|
101
|
+
let activeRuntimePath = null;
|
|
102
|
+
let activeVersion = null;
|
|
103
|
+
|
|
104
|
+
const systemBun = detectSystemBun();
|
|
105
|
+
let systemBunCompatible = false;
|
|
139
106
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
if (useCmd.status === 0) {
|
|
168
|
-
const target = fs.readlinkSync(currentRuntime);
|
|
169
|
-
const usedVersion = path.basename(target);
|
|
170
|
-
log(`Setup complete. Using Bun v${usedVersion} as default.`);
|
|
171
|
-
}
|
|
172
|
-
} else {
|
|
173
|
-
log(`Warning: Failed to install latest. Stayed with Bun v${hostVer}.`);
|
|
174
|
-
}
|
|
107
|
+
if (systemBun) {
|
|
108
|
+
log(`Found system Bun at ${systemBun.path} (v${systemBun.version})`);
|
|
109
|
+
if (runSmokeTest(systemBun.path)) {
|
|
110
|
+
log('Smoke Test passed: System Bun is compatible.');
|
|
111
|
+
systemBunCompatible = true;
|
|
112
|
+
activeVersion = ensureVersionPrefix(systemBun.version);
|
|
113
|
+
const versionDir = path.join(BVM_DIR, 'versions', activeVersion);
|
|
114
|
+
registerBunVersion(systemBun.path, versionDir);
|
|
115
|
+
activeRuntimePath = versionDir;
|
|
116
|
+
} else {
|
|
117
|
+
log('Smoke Test failed: System Bun cannot run BVM core.');
|
|
118
|
+
const versionDir = path.join(BVM_DIR, 'versions', ensureVersionPrefix(systemBun.version));
|
|
119
|
+
registerBunVersion(systemBun.path, versionDir);
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
log('No system Bun detected.');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!systemBunCompatible) {
|
|
126
|
+
log('Downloading compatible Bun runtime...');
|
|
127
|
+
try {
|
|
128
|
+
const installedVersion = downloadAndInstallRuntime(BVM_DIR);
|
|
129
|
+
if (installedVersion) {
|
|
130
|
+
activeVersion = installedVersion;
|
|
131
|
+
activeRuntimePath = path.join(BVM_DIR, 'versions', activeVersion);
|
|
175
132
|
} else {
|
|
176
|
-
|
|
133
|
+
throw new Error('Download failed');
|
|
177
134
|
}
|
|
178
135
|
} catch (e) {
|
|
179
|
-
|
|
136
|
+
error(`Failed to download runtime: ${e.message}`);
|
|
180
137
|
}
|
|
181
138
|
}
|
|
182
139
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
140
|
+
// 4. Link Runtime & Default Alias
|
|
141
|
+
if (activeRuntimePath && activeVersion) {
|
|
142
|
+
const legacyCurrentLink = path.join(BVM_DIR, 'current');
|
|
143
|
+
const privateRuntimeLink = path.join(BVM_DIR, 'runtime', 'current');
|
|
144
|
+
ensureDir(path.join(BVM_DIR, 'runtime'));
|
|
145
|
+
|
|
146
|
+
try { if (fs.existsSync(privateRuntimeLink)) fs.unlinkSync(privateRuntimeLink); } catch(e) {}
|
|
147
|
+
try { fs.symlinkSync(activeRuntimePath, privateRuntimeLink, 'dir'); } catch(e) {}
|
|
186
148
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
149
|
+
try { if (fs.existsSync(legacyCurrentLink)) fs.unlinkSync(legacyCurrentLink); } catch(e) {}
|
|
150
|
+
try { fs.symlinkSync(activeRuntimePath, legacyCurrentLink, 'dir'); } catch(e) {}
|
|
151
|
+
|
|
152
|
+
const aliasDir = path.join(BVM_DIR, 'aliases');
|
|
153
|
+
ensureDir(aliasDir);
|
|
154
|
+
fs.writeFileSync(path.join(aliasDir, 'default'), activeVersion);
|
|
155
|
+
log(`Active runtime set to ${activeVersion}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 5. Create BVM Wrapper
|
|
159
|
+
createBvmWrapper();
|
|
160
|
+
|
|
161
|
+
// 6. Configure Shell (bvm setup)
|
|
162
|
+
log('Configuring shell environment...');
|
|
163
|
+
spawnSync(path.join(BVM_BIN_DIR, 'bvm'), ['setup', '--silent'], {
|
|
190
164
|
stdio: 'inherit',
|
|
191
165
|
env: Object.assign({}, process.env, { BVM_DIR })
|
|
192
166
|
});
|
|
193
167
|
|
|
194
|
-
|
|
195
|
-
|
|
168
|
+
// 7. Final Success Message
|
|
169
|
+
printSuccessMessage(!!systemBun);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// --- Implementation Details ---
|
|
173
|
+
|
|
174
|
+
function detectSystemBun() {
|
|
175
|
+
const which = spawnSync('which', ['bun'], { encoding: 'utf-8' });
|
|
176
|
+
if (which.status === 0 && which.stdout) {
|
|
177
|
+
const binPath = which.stdout.trim();
|
|
178
|
+
const ver = getBunVersion(binPath);
|
|
179
|
+
if (ver) return { path: binPath, version: ver };
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getBunVersion(binPath) {
|
|
185
|
+
try {
|
|
186
|
+
const proc = spawnSync(binPath, ['--version'], { encoding: 'utf-8' });
|
|
187
|
+
if (proc.status === 0) return proc.stdout.trim().replace(/^v/, '');
|
|
188
|
+
} catch (e) {}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function runSmokeTest(binPath) {
|
|
193
|
+
try {
|
|
194
|
+
const indexJs = path.join(BVM_SRC_DIR, 'index.js');
|
|
195
|
+
const proc = spawnSync(binPath, [indexJs, '--version'], {
|
|
196
|
+
encoding: 'utf-8',
|
|
197
|
+
env: Object.assign({}, process.env, { BVM_DIR })
|
|
198
|
+
});
|
|
199
|
+
return proc.status === 0;
|
|
200
|
+
} catch (e) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function registerBunVersion(sourceBin, targetDir) {
|
|
206
|
+
const targetBinDir = path.join(targetDir, 'bin');
|
|
207
|
+
ensureDir(targetBinDir);
|
|
208
|
+
const targetBin = path.join(targetBinDir, 'bun');
|
|
209
|
+
if (!fs.existsSync(targetBin)) {
|
|
210
|
+
fs.copyFileSync(sourceBin, targetBin);
|
|
211
|
+
fs.chmodSync(targetBin, 0o755);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function downloadAndInstallRuntime(bvmDir) {
|
|
216
|
+
const platform = process.platform;
|
|
217
|
+
const arch = process.arch;
|
|
218
|
+
|
|
219
|
+
let pkgPlatform = '';
|
|
220
|
+
if (platform === 'darwin') pkgPlatform = 'darwin';
|
|
221
|
+
else if (platform === 'linux') pkgPlatform = 'linux';
|
|
222
|
+
else if (platform === 'win32') pkgPlatform = 'windows';
|
|
223
|
+
else return null;
|
|
224
|
+
|
|
225
|
+
const pkgArch = arch === 'arm64' ? 'aarch64' : 'x64';
|
|
226
|
+
const bunVer = '1.1.13';
|
|
227
|
+
const vBunVer = ensureVersionPrefix(bunVer);
|
|
228
|
+
const registry = 'https://registry.npmmirror.com';
|
|
229
|
+
const pkgName = `@oven/bun-${pkgPlatform}-${pkgArch}`;
|
|
230
|
+
const url = `${registry}/${pkgName}/-/${pkgName.split('/').pop()}-${bunVer}.tgz`;
|
|
231
|
+
|
|
232
|
+
const tempTgz = path.join(os.tmpdir(), `bun-${Date.now()}.tgz`);
|
|
233
|
+
const extractDir = path.join(os.tmpdir(), `bun-ext-${Date.now()}`);
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
log(`Downloading Bun ${bunVer}...`);
|
|
237
|
+
spawnSync('curl', ['-L', '-s', '-o', tempTgz, url]);
|
|
238
|
+
ensureDir(extractDir);
|
|
239
|
+
spawnSync('tar', ['-xzf', tempTgz, '-C', extractDir]);
|
|
240
|
+
const exeName = platform === 'win32' ? 'bun.exe' : 'bun';
|
|
241
|
+
const foundBinProc = spawnSync('find', [extractDir, '-name', exeName], { encoding: 'utf-8' });
|
|
242
|
+
const binPath = foundBinProc.stdout ? foundBinProc.stdout.trim().split('\n')[0] : null;
|
|
243
|
+
if (binPath && fs.existsSync(binPath)) {
|
|
244
|
+
const versionDir = path.join(bvmDir, 'versions', vBunVer);
|
|
245
|
+
registerBunVersion(binPath, versionDir);
|
|
246
|
+
return vBunVer;
|
|
247
|
+
}
|
|
248
|
+
} catch (e) {
|
|
249
|
+
error(`Download failed: ${e.message}`);
|
|
250
|
+
} finally {
|
|
251
|
+
try {
|
|
252
|
+
if (fs.existsSync(tempTgz)) fs.unlinkSync(tempTgz);
|
|
253
|
+
if (fs.existsSync(extractDir)) fs.rmSync(extractDir, { recursive: true });
|
|
254
|
+
} catch(e) {}
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function createBvmWrapper() {
|
|
260
|
+
const wrapperContent = `#!/bin/bash
|
|
261
|
+
export BVM_DIR="${BVM_DIR}"
|
|
262
|
+
export BVM_INSTALL_SOURCE="npm"
|
|
263
|
+
if [ -x "\${BVM_DIR}/runtime/current/bin/bun" ]; then
|
|
264
|
+
exec "\${BVM_DIR}/runtime/current/bin/bun" "\${BVM_DIR}/src/index.js" "$@"
|
|
265
|
+
elif command -v bun >/dev/null 2>&1; then
|
|
266
|
+
exec bun "\${BVM_DIR}/src/index.js" "$@"
|
|
267
|
+
else
|
|
268
|
+
echo "Error: BVM requires Bun. Please ensure setup completed correctly."
|
|
269
|
+
exit 1
|
|
270
|
+
fi
|
|
271
|
+
`;
|
|
272
|
+
const bvmExec = path.join(BVM_BIN_DIR, 'bvm');
|
|
273
|
+
fs.writeFileSync(bvmExec, wrapperContent);
|
|
274
|
+
fs.chmodSync(bvmExec, 0o755);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function printSuccessMessage(hasSystemBun) {
|
|
278
|
+
const shell = process.env.SHELL || '';
|
|
279
|
+
let configFile = '~/.zshrc';
|
|
280
|
+
if (shell.includes('bash')) configFile = '~/.bashrc';
|
|
281
|
+
else if (shell.includes('fish')) configFile = '~/.config/fish/config.fish';
|
|
282
|
+
|
|
283
|
+
process.stdout.write('\n\x1b[32m\x1b[1m🎉 BVM (Bun Version Manager) installed successfully!\x1b[0m\n');
|
|
284
|
+
if (hasSystemBun) {
|
|
285
|
+
process.stdout.write('\x1b[33mBVM has been added to the END of your PATH configuration to ensure priority.\x1b[0m\n');
|
|
286
|
+
process.stdout.write('\x1b[33mYour existing Bun installations were NOT deleted and will coexist.\x1b[0m\n');
|
|
196
287
|
} else {
|
|
197
|
-
|
|
288
|
+
process.stdout.write('\x1b[33mBVM has installed a compatible Bun runtime for you.\x1b[0m\n');
|
|
198
289
|
}
|
|
290
|
+
process.stdout.write('\n\x1b[1mTo finalize the setup, please restart your terminal or run:\x1b[0m\n');
|
|
291
|
+
process.stdout.write(` source ${configFile}\n\n`);
|
|
199
292
|
}
|
|
200
293
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
})
|
|
294
|
+
// Execute
|
|
295
|
+
try {
|
|
296
|
+
main();
|
|
297
|
+
} catch (e) {
|
|
298
|
+
error(e.message);
|
|
299
|
+
}
|