-
Notifications
You must be signed in to change notification settings - Fork 66
/
cli.js
executable file
·157 lines (133 loc) · 5.94 KB
/
cli.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env node
/**
* Builds a complete Mbed OS project
*/
const fs = require('fs');
const Path = require('path');
const helpers = require('./build-tools/helpers');
const application = require('./build-tools/build-application');
const opn = require('opn');
const commandExistsSync = require('command-exists').sync;
const launchServer = require('./server/launch-server');
const version = JSON.parse(fs.readFileSync(Path.join(__dirname, 'package.json'), 'utf-8')).version;
const puppeteer = require('puppeteer');
const promisify = require('es6-promisify').promisify;
let program = require('commander');
program
.version(version)
.option('-i --input-dir <dir>', 'Input directory')
.option('-f --input-file <file>', 'Input file')
.option('-o --output-file <file>', 'Output file (or directory)')
.option('-v --verbose', 'Verbose logging')
.option('-c --compiler-opts <opts>', 'Compiler options (e.g. -std=c++11)')
.option('-l --launch', 'Launch the simulator for this project after building (opens a browser)')
.option('--launch-headless', 'Launch the simulator for this project after building in headless mode (pipes output to console)')
.option('--skip-build', 'Skip the build step (launch only)')
.option('--disable-runtime-logs', 'Disable runtime logs (e.g. from the LoRa server or networking proxy)')
.option('--emterpretify', 'Enable emterpretify mode (required if projects take a long time to compile)')
.allowUnknownOption(true)
.parse(process.argv);
// shorthand so you can run `mbed simulator .`
if (fs.existsSync(process.argv[2]) && fs.statSync(process.argv[2]).isDirectory()) {
program.inputDir = Path.resolve(process.argv[2]);
if (!program.launchHeadless) {
program.launch = true;
}
}
if (program.inputDir && program.inputFile) {
console.log('Cannot specify both --input-dir and --input-file');
process.exit(1);
}
if (!program.inputDir && !program.inputFile) {
console.log(`Argument '--input-dir' or '--input-file' is required`);
process.exit(1);
}
if (program.inputDir && !fs.existsSync(program.inputDir)) {
console.log('Input directory', program.inputDir, 'does not exist');
process.exit(1);
}
if (program.inputDir && !fs.statSync(program.inputDir).isDirectory()) {
console.log('Input directory', program.inputDir, 'is not a directory');
process.exit(1);
}
if (program.inputFile && !fs.existsSync(program.inputFile)) {
console.log('Input file', program.inputFile, 'does not exist');
process.exit(1);
}
if (program.inputFile && !fs.statSync(program.inputFile).isFile()) {
console.log('Input file', program.inputFile, 'is not a file');
process.exit(1);
}
if (!program.outputFile) {
if (program.inputDir) {
program.inputDir = Path.resolve(program.inputDir);
program.outputFile = Path.join(program.inputDir, 'BUILD', 'SIMULATOR', Path.basename(program.inputDir) + '.js');
}
else {
console.log(`Argument '--output-file' is required`);
process.exit(1);
}
}
if (!commandExistsSync('emcc')) {
console.log('Cannot find emcc');
console.log('\tEmscripten is not installed (or not in your PATH)');
console.log('\tFollow: https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html');
process.exit(1);
}
let inputDir = program.inputDir ? Path.resolve(program.inputDir) : Path.resolve(Path.dirname(program.inputFile));
program.inputFile = program.inputFile ? Path.resolve(program.inputFile) : null;
program.outputFile = Path.resolve(program.outputFile);
if (fs.existsSync(program.outputFile) && fs.statSync(program.outputFile).isDirectory()) {
program.outputFile = Path.join(program.outputFile, Path.basename(inputDir) + '.js');
}
const outputDir = Path.dirname(program.outputFile);
helpers.mkdirpSync(outputDir);
// extra arguments that are passed in, but need to remove ones already covered in program...
let extraArgs = (program.compilerOpts || '').split(' ');
let fn = program.inputDir ? application.buildDirectory : application.buildFile;
if (program.skipBuild) {
console.log('Skipping build...');
fn = () => Promise.resolve();
}
fn(program.inputDir || program.inputFile, program.outputFile, extraArgs, program.emterpretify, program.verbose)
.then(async function() {
console.log('Building application succeeded, output file is', program.outputFile);
if (program.launch || program.launchHeadless) {
let browser;
try {
let port = process.env.PORT || 7900;
let logsEnabled = !program.disableRuntimeLogs;
await promisify(launchServer)(outputDir, port, 0, logsEnabled);
let name = Path.basename(program.outputFile, '.js');
if (program.launch) {
opn(`http://localhost:${port}/view/${name}`);
}
else if (program.launchHeadless) {
browser = await puppeteer.launch();
const page = await browser.newPage();
await page.exposeFunction('onPrintEvent', e => {
console.log(e);
});
await page.exposeFunction('onStartExecution', () => {
console.log('Application started in headless mode');
});
await page.exposeFunction('onFailedExecution', async function (e) {
console.error('Error while running in headless mode', e);
await browser.close();
process.exit(1);
});
await page.goto(`http://localhost:${port}/view/${name}`);
}
}
catch (ex) {
console.error('Failed to launch server', ex);
if (browser) {
await browser.close();
}
}
}
})
.catch(err => {
console.error(err);
console.error('Building application failed');
});