flightdeck 0.0.1 → 0.0.3
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/dist/flightdeck.$configPath.schema.json +27 -15
- package/dist/flightdeck.bin.js +350 -0
- package/dist/flightdeck.main.schema.json +27 -15
- package/dist/klaxon.bin.js +87 -0
- package/dist/lib.d.ts +96 -23
- package/dist/lib.js +180 -66
- package/package.json +12 -10
- package/src/{bin.ts → flightdeck.bin.ts} +24 -28
- package/src/flightdeck.lib.ts +343 -0
- package/src/klaxon.bin.ts +58 -0
- package/src/klaxon.lib.ts +78 -0
- package/src/lib.ts +4 -1
- package/dist/bin.js +0 -102
- package/src/flightdeck.ts +0 -235
package/dist/lib.js
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/flightdeck.lib.ts
|
|
2
13
|
import {execSync, spawn} from "node:child_process";
|
|
3
14
|
import {existsSync, mkdirSync, renameSync, rmSync} from "node:fs";
|
|
4
|
-
import {createServer} from "node:
|
|
15
|
+
import {createServer} from "node:http";
|
|
5
16
|
import {homedir} from "node:os";
|
|
6
17
|
import {resolve} from "node:path";
|
|
7
18
|
import {Future} from "atom.io/internal";
|
|
19
|
+
import {fromEntries, toEntries} from "atom.io/json";
|
|
8
20
|
import {ChildSocket} from "atom.io/realtime-server";
|
|
9
|
-
var safety = 0;
|
|
10
21
|
var PORT = process.env.PORT ?? 8080;
|
|
11
22
|
var ORIGIN = `http://localhost:${PORT}`;
|
|
12
23
|
|
|
13
24
|
class FlightDeck {
|
|
14
25
|
options;
|
|
15
|
-
|
|
16
|
-
return `${this.options.repo}/${this.options.app}`;
|
|
17
|
-
}
|
|
26
|
+
safety = 0;
|
|
18
27
|
webhookServer;
|
|
19
|
-
|
|
28
|
+
services;
|
|
29
|
+
serviceIdx;
|
|
30
|
+
defaultServicesReadyToUpdate;
|
|
31
|
+
servicesReadyToUpdate;
|
|
32
|
+
servicesShouldRestart;
|
|
20
33
|
restartTimes = [];
|
|
21
|
-
|
|
34
|
+
servicesLive;
|
|
35
|
+
servicesDead;
|
|
36
|
+
live = new Future(() => {
|
|
22
37
|
});
|
|
23
38
|
dead = new Future(() => {
|
|
24
39
|
});
|
|
@@ -27,13 +42,25 @@ class FlightDeck {
|
|
|
27
42
|
backupServiceDir;
|
|
28
43
|
constructor(options) {
|
|
29
44
|
this.options = options;
|
|
30
|
-
const {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
const { secret, flightdeckRootDir = resolve(homedir(), `services`) } = options;
|
|
46
|
+
const servicesEntries = toEntries(options.services);
|
|
47
|
+
this.services = fromEntries(servicesEntries.map(([serviceName]) => [serviceName, null]));
|
|
48
|
+
this.serviceIdx = fromEntries(servicesEntries.map(([serviceName], idx) => [serviceName, idx]));
|
|
49
|
+
this.defaultServicesReadyToUpdate = fromEntries(servicesEntries.map(([serviceName, { waitFor }]) => [
|
|
50
|
+
serviceName,
|
|
51
|
+
!waitFor
|
|
52
|
+
]));
|
|
53
|
+
this.servicesReadyToUpdate = { ...this.defaultServicesReadyToUpdate };
|
|
54
|
+
this.servicesShouldRestart = true;
|
|
55
|
+
this.servicesLive = servicesEntries.map(() => new Future(() => {
|
|
56
|
+
}));
|
|
57
|
+
this.servicesDead = servicesEntries.map(() => new Future(() => {
|
|
58
|
+
}));
|
|
59
|
+
this.live.use(Promise.all(this.servicesLive));
|
|
60
|
+
this.dead.use(Promise.all(this.servicesDead));
|
|
61
|
+
this.currentServiceDir = resolve(flightdeckRootDir, options.packageName, `current`);
|
|
62
|
+
this.backupServiceDir = resolve(flightdeckRootDir, options.packageName, `backup`);
|
|
63
|
+
this.updateServiceDir = resolve(flightdeckRootDir, options.packageName, `update`);
|
|
37
64
|
createServer((req, res) => {
|
|
38
65
|
let data = [];
|
|
39
66
|
req.on(`data`, (chunk) => {
|
|
@@ -42,6 +69,8 @@ class FlightDeck {
|
|
|
42
69
|
console.log(req.headers);
|
|
43
70
|
const authHeader = req.headers.authorization;
|
|
44
71
|
try {
|
|
72
|
+
if (typeof req.url === `undefined`)
|
|
73
|
+
throw 400;
|
|
45
74
|
if (authHeader !== `Bearer ${secret}`)
|
|
46
75
|
throw 401;
|
|
47
76
|
const url = new URL(req.url, ORIGIN);
|
|
@@ -56,11 +85,20 @@ class FlightDeck {
|
|
|
56
85
|
res.writeHead(200);
|
|
57
86
|
res.end();
|
|
58
87
|
this.fetchLatestRelease();
|
|
59
|
-
if (this.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
88
|
+
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
89
|
+
console.log(`All services are ready to update!`);
|
|
90
|
+
this.stopAllServices();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
for (const entry of toEntries(this.services)) {
|
|
94
|
+
const [serviceName, service] = entry;
|
|
95
|
+
if (service) {
|
|
96
|
+
if (this.options.services[serviceName].waitFor) {
|
|
97
|
+
service.emit(`updatesReady`);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
this.startService(serviceName);
|
|
101
|
+
}
|
|
64
102
|
}
|
|
65
103
|
}
|
|
66
104
|
break;
|
|
@@ -85,68 +123,89 @@ class FlightDeck {
|
|
|
85
123
|
}).listen(PORT, () => {
|
|
86
124
|
console.log(`Server started on port ${PORT}`);
|
|
87
125
|
});
|
|
88
|
-
this.
|
|
126
|
+
this.startAllServices();
|
|
127
|
+
}
|
|
128
|
+
startAllServices() {
|
|
129
|
+
console.log(`Starting all services...`);
|
|
130
|
+
for (const [serviceName] of toEntries(this.services)) {
|
|
131
|
+
this.startService(serviceName);
|
|
132
|
+
}
|
|
89
133
|
}
|
|
90
|
-
startService() {
|
|
91
|
-
safety
|
|
92
|
-
if (safety >
|
|
93
|
-
throw new Error(`
|
|
134
|
+
startService(serviceName) {
|
|
135
|
+
console.log(`Starting service ${this.options.packageName}::${serviceName}, try ${this.safety}/2...`);
|
|
136
|
+
if (this.safety > 2) {
|
|
137
|
+
throw new Error(`Out of tries...`);
|
|
94
138
|
}
|
|
139
|
+
this.safety++;
|
|
95
140
|
if (!existsSync(this.currentServiceDir)) {
|
|
96
|
-
console.log(`Tried to start service but failed: Service ${this.
|
|
141
|
+
console.log(`Tried to start service but failed: Service ${this.options.packageName} is not yet installed.`);
|
|
97
142
|
this.fetchLatestRelease();
|
|
98
143
|
this.applyUpdate();
|
|
99
|
-
this.startService();
|
|
144
|
+
this.startService(serviceName);
|
|
100
145
|
return;
|
|
101
146
|
}
|
|
102
|
-
const [executable, ...args] = this.options.
|
|
147
|
+
const [executable, ...args] = this.options.services[serviceName].run;
|
|
103
148
|
const program = executable.startsWith(`./`) ? resolve(this.currentServiceDir, executable) : executable;
|
|
104
149
|
const serviceProcess = spawn(program, args, {
|
|
105
150
|
cwd: this.currentServiceDir,
|
|
106
151
|
env: import.meta.env
|
|
107
152
|
});
|
|
108
|
-
this.
|
|
109
|
-
this.
|
|
110
|
-
console.log(
|
|
153
|
+
this.services[serviceName] = new ChildSocket(serviceProcess, `${this.options.packageName}::${serviceName}`, console);
|
|
154
|
+
this.services[serviceName].onAny((...messages) => {
|
|
155
|
+
console.log(`${this.options.packageName}::${serviceName} \uD83D\uDCAC`, ...messages);
|
|
111
156
|
});
|
|
112
|
-
this.
|
|
113
|
-
this.
|
|
157
|
+
this.services[serviceName].on(`readyToUpdate`, () => {
|
|
158
|
+
console.log(`Service ${this.options.packageName}::${serviceName} is ready to update.`);
|
|
159
|
+
this.servicesReadyToUpdate[serviceName] = true;
|
|
160
|
+
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
161
|
+
console.log(`All services are ready to update!`);
|
|
162
|
+
this.stopAllServices();
|
|
163
|
+
}
|
|
114
164
|
});
|
|
115
|
-
this.
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
165
|
+
this.services[serviceName].on(`alive`, () => {
|
|
166
|
+
this.servicesLive[this.serviceIdx[serviceName]].use(Promise.resolve());
|
|
167
|
+
this.servicesDead[this.serviceIdx[serviceName]] = new Future(() => {
|
|
118
168
|
});
|
|
169
|
+
if (this.dead.done) {
|
|
170
|
+
this.dead = new Future(() => {
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
this.dead.use(Promise.all(this.servicesDead));
|
|
119
174
|
});
|
|
120
|
-
this.
|
|
121
|
-
console.log(
|
|
122
|
-
this.
|
|
175
|
+
this.services[serviceName].process.on(`close`, (exitCode) => {
|
|
176
|
+
console.log(`${this.options.packageName}::${serviceName} exited with code ${exitCode}`);
|
|
177
|
+
this.services[serviceName] = null;
|
|
178
|
+
if (!this.servicesShouldRestart) {
|
|
179
|
+
console.log(`Service ${this.options.packageName}::${serviceName} will not be restarted.`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
123
182
|
const updatesAreReady = existsSync(this.updateServiceDir);
|
|
124
183
|
if (updatesAreReady) {
|
|
125
|
-
console.log(
|
|
184
|
+
console.log(`${this.options.packageName}::${serviceName} will be updated before startup...`);
|
|
126
185
|
this.restartTimes = [];
|
|
127
186
|
this.applyUpdate();
|
|
128
|
-
this.startService();
|
|
187
|
+
this.startService(serviceName);
|
|
129
188
|
} else {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
console.log(`Service ${this.serviceName} crashed too many times. Not restarting.`);
|
|
140
|
-
}
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
const fiveMinutesAgo = now - 5 * 60 * 1000;
|
|
191
|
+
this.restartTimes = this.restartTimes.filter((time) => time > fiveMinutesAgo);
|
|
192
|
+
this.restartTimes.push(now);
|
|
193
|
+
if (this.restartTimes.length < 5) {
|
|
194
|
+
console.log(`Service ${this.options.packageName}::${serviceName} crashed. Restarting...`);
|
|
195
|
+
this.startService(serviceName);
|
|
196
|
+
} else {
|
|
197
|
+
console.log(`Service ${this.options.packageName}::${serviceName} crashed too many times. Not restarting.`);
|
|
141
198
|
}
|
|
142
199
|
}
|
|
143
200
|
});
|
|
201
|
+
this.safety = 0;
|
|
144
202
|
}
|
|
145
203
|
applyUpdate() {
|
|
146
|
-
console.log(`Installing latest version of service ${this.
|
|
204
|
+
console.log(`Installing latest version of service ${this.options.packageName}...`);
|
|
147
205
|
if (existsSync(this.updateServiceDir)) {
|
|
148
|
-
|
|
149
|
-
|
|
206
|
+
const runningServices = toEntries(this.services).filter(([, service]) => service);
|
|
207
|
+
if (runningServices.length > 0) {
|
|
208
|
+
console.log(`Tried to apply update to ${this.options.packageName} but failed. The following services are currently running: [${runningServices.map(([serviceName]) => serviceName).join(`, `)}]`);
|
|
150
209
|
return;
|
|
151
210
|
}
|
|
152
211
|
if (existsSync(this.currentServiceDir)) {
|
|
@@ -159,14 +218,15 @@ class FlightDeck {
|
|
|
159
218
|
}
|
|
160
219
|
renameSync(this.updateServiceDir, this.currentServiceDir);
|
|
161
220
|
this.restartTimes = [];
|
|
221
|
+
this.servicesReadyToUpdate = { ...this.defaultServicesReadyToUpdate };
|
|
162
222
|
} else {
|
|
163
|
-
console.log(`Service ${this.
|
|
223
|
+
console.log(`Service ${this.options.packageName} is already up to date.`);
|
|
164
224
|
}
|
|
165
225
|
}
|
|
166
226
|
fetchLatestRelease() {
|
|
167
|
-
console.log(`Downloading latest version of service ${this.
|
|
227
|
+
console.log(`Downloading latest version of service ${this.options.packageName}...`);
|
|
168
228
|
try {
|
|
169
|
-
execSync(this.options.
|
|
229
|
+
execSync(this.options.downloadPackageToUpdatesCmd.join(` `));
|
|
170
230
|
} catch (thrown) {
|
|
171
231
|
if (thrown instanceof Error) {
|
|
172
232
|
console.error(`Failed to fetch the latest release: ${thrown.message}`);
|
|
@@ -174,19 +234,73 @@ class FlightDeck {
|
|
|
174
234
|
return;
|
|
175
235
|
}
|
|
176
236
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
this.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
237
|
+
stopAllServices() {
|
|
238
|
+
console.log(`Stopping all services...`);
|
|
239
|
+
for (const [serviceName] of toEntries(this.services)) {
|
|
240
|
+
this.stopService(serviceName);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
stopService(serviceName) {
|
|
244
|
+
if (this.services[serviceName]) {
|
|
245
|
+
console.log(`Stopping service ${this.options.packageName}::${serviceName}...`);
|
|
246
|
+
this.services[serviceName].process.kill();
|
|
247
|
+
this.services[serviceName] = null;
|
|
248
|
+
this.servicesDead[this.serviceIdx[serviceName]].use(Promise.resolve());
|
|
249
|
+
this.servicesLive[this.serviceIdx[serviceName]] = new Future(() => {
|
|
184
250
|
});
|
|
251
|
+
if (this.live.done) {
|
|
252
|
+
this.live = new Future(() => {
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
this.live.use(Promise.all(this.servicesLive));
|
|
185
256
|
} else {
|
|
186
|
-
console.error(`Failed to stop service ${this.serviceName}: Service is not running.`);
|
|
257
|
+
console.error(`Failed to stop service ${this.options.packageName}::${serviceName}: Service is not running.`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
shutdown() {
|
|
261
|
+
this.servicesShouldRestart = false;
|
|
262
|
+
this.stopAllServices();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// src/klaxon.lib.ts
|
|
266
|
+
var exports_klaxon_lib = {};
|
|
267
|
+
__export(exports_klaxon_lib, {
|
|
268
|
+
scramble: () => scramble,
|
|
269
|
+
alert: () => alert
|
|
270
|
+
});
|
|
271
|
+
async function alert({
|
|
272
|
+
secret,
|
|
273
|
+
endpoint
|
|
274
|
+
}) {
|
|
275
|
+
const response = await fetch(endpoint, {
|
|
276
|
+
method: `POST`,
|
|
277
|
+
headers: {
|
|
278
|
+
"Content-Type": `application/json`,
|
|
279
|
+
Authorization: `Bearer ${secret}`
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
return response;
|
|
283
|
+
}
|
|
284
|
+
async function scramble({
|
|
285
|
+
packageConfig,
|
|
286
|
+
secretsConfig,
|
|
287
|
+
publishedPackages
|
|
288
|
+
}) {
|
|
289
|
+
const alertResults = [];
|
|
290
|
+
for (const publishedPackage of publishedPackages) {
|
|
291
|
+
if (publishedPackage.name in packageConfig) {
|
|
292
|
+
const name = publishedPackage.name;
|
|
293
|
+
const { endpoint } = packageConfig[name];
|
|
294
|
+
const secret = secretsConfig[name];
|
|
295
|
+
const alertResultPromise = alert({ secret, endpoint }).then((alertResult) => [name, alertResult]);
|
|
296
|
+
alertResults.push(alertResultPromise);
|
|
187
297
|
}
|
|
188
298
|
}
|
|
299
|
+
const alertResultsResolved = await Promise.all(alertResults);
|
|
300
|
+
const scrambleResult = Object.fromEntries(alertResultsResolved);
|
|
301
|
+
return scrambleResult;
|
|
189
302
|
}
|
|
190
303
|
export {
|
|
304
|
+
exports_klaxon_lib as Klaxon,
|
|
191
305
|
FlightDeck
|
|
192
306
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flightdeck",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jeremy Banka",
|
|
@@ -17,29 +17,31 @@
|
|
|
17
17
|
"main": "dist/lib.js",
|
|
18
18
|
"types": "dist/lib.d.ts",
|
|
19
19
|
"bin": {
|
|
20
|
-
"flightdeck": "./dist/bin.js"
|
|
20
|
+
"flightdeck": "./dist/flightdeck.bin.js",
|
|
21
|
+
"klaxon": "./dist/klaxon.bin.js"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"zod": "3.23.8",
|
|
24
|
-
"atom.io": "0.29.
|
|
25
|
-
"comline": "0.1.
|
|
25
|
+
"atom.io": "0.29.2",
|
|
26
|
+
"comline": "0.1.1"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@types/bun": "1.1.
|
|
29
|
+
"@types/bun": "1.1.9",
|
|
29
30
|
"@types/node": "20.16.5",
|
|
30
31
|
"@types/tmp": "0.2.6",
|
|
31
|
-
"concurrently": "
|
|
32
|
+
"concurrently": "9.0.1",
|
|
32
33
|
"tmp": "0.2.3",
|
|
33
34
|
"tsup": "8.2.4",
|
|
34
35
|
"rimraf": "6.0.1",
|
|
35
|
-
"vitest": "2.
|
|
36
|
+
"vitest": "2.1.1"
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
|
-
"build": "rimraf dist && concurrently \"bun:build:*\" && bun
|
|
39
|
+
"build": "rimraf dist && concurrently \"bun:build:*\" && concurrently \"bun:schema:*\"",
|
|
40
|
+
"build:bin:flightdeck": "bun build --outdir dist --target node --external flightdeck --external atom.io --external comline --external zod -- src/flightdeck.bin.ts",
|
|
41
|
+
"build:bin:klaxon": "bun build --outdir dist --target node --external flightdeck --external atom.io --external comline --external zod -- src/klaxon.bin.ts",
|
|
39
42
|
"build:lib": "bun build --outdir dist --target node --external flightdeck --external atom.io --external comline --external zod -- src/lib.ts ",
|
|
40
|
-
"build:bin": "bun build --outdir dist --target node --external flightdeck --external atom.io --external comline --external zod -- src/bin.ts",
|
|
41
43
|
"build:dts": "tsup",
|
|
42
|
-
"schema": "bun ./src/bin.ts --outdir=dist -- schema",
|
|
44
|
+
"schema:flightdeck": "bun ./src/flightdeck.bin.ts --outdir=dist -- schema",
|
|
43
45
|
"lint:biome": "biome check -- .",
|
|
44
46
|
"lint:eslint": "eslint --flag unstable_ts_config -- .",
|
|
45
47
|
"lint:types": "tsc --noEmit",
|
|
@@ -4,56 +4,52 @@ import * as path from "node:path"
|
|
|
4
4
|
|
|
5
5
|
import type { OptionsGroup } from "comline"
|
|
6
6
|
import { cli, optional, parseArrayOption } from "comline"
|
|
7
|
-
import type { FlightDeckOptions } from "flightdeck"
|
|
8
|
-
import { FlightDeck } from "flightdeck"
|
|
9
7
|
import { z } from "zod"
|
|
10
8
|
|
|
9
|
+
import type { FlightDeckOptions } from "~/packages/flightdeck/src/flightdeck.lib"
|
|
10
|
+
import { FlightDeck } from "~/packages/flightdeck/src/flightdeck.lib"
|
|
11
|
+
|
|
11
12
|
const FLIGHTDECK_MANUAL = {
|
|
12
13
|
optionsSchema: z.object({
|
|
13
14
|
secret: z.string(),
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
packageName: z.string(),
|
|
16
|
+
services: z.record(
|
|
17
|
+
z.object({ run: z.array(z.string()), waitFor: z.boolean() }),
|
|
18
|
+
),
|
|
19
|
+
flightDeckRootDir: z.string(),
|
|
20
|
+
downloadPackageToUpdatesCmd: z.array(z.string()),
|
|
19
21
|
}),
|
|
20
22
|
options: {
|
|
21
23
|
secret: {
|
|
22
|
-
flag: `
|
|
24
|
+
flag: `x`,
|
|
23
25
|
required: true,
|
|
24
26
|
description: `Secret used to authenticate with the service.`,
|
|
25
27
|
example: `--secret=\"secret\"`,
|
|
26
28
|
},
|
|
27
|
-
|
|
28
|
-
flag: `
|
|
29
|
-
required: true,
|
|
30
|
-
description: `Name of the repository.`,
|
|
31
|
-
example: `--repo=\"sample/repo\"`,
|
|
32
|
-
},
|
|
33
|
-
app: {
|
|
34
|
-
flag: `a`,
|
|
29
|
+
packageName: {
|
|
30
|
+
flag: `p`,
|
|
35
31
|
required: true,
|
|
36
|
-
description: `Name of the
|
|
37
|
-
example: `--
|
|
32
|
+
description: `Name of the package.`,
|
|
33
|
+
example: `--packageName=\"my-app\"`,
|
|
38
34
|
},
|
|
39
|
-
|
|
40
|
-
flag: `
|
|
35
|
+
services: {
|
|
36
|
+
flag: `s`,
|
|
41
37
|
required: true,
|
|
42
|
-
description: `
|
|
43
|
-
example: `--
|
|
44
|
-
parse:
|
|
38
|
+
description: `Map of service names to executables.`,
|
|
39
|
+
example: `--services="{\\"frontend\\":{\\"run\\":[\\"./app\\"],\\"waitFor\\":false},\\"backend\\":{\\"run\\":[\\"./backend\\"],\\"waitFor\\":true}}"`,
|
|
40
|
+
parse: JSON.parse,
|
|
45
41
|
},
|
|
46
|
-
|
|
42
|
+
flightdeckRootDir: {
|
|
47
43
|
flag: `d`,
|
|
48
44
|
required: true,
|
|
49
45
|
description: `Directory where the service is stored.`,
|
|
50
|
-
example: `--
|
|
46
|
+
example: `--flightdeckRootDir=\"./services/sample/repo/my-app/current\"`,
|
|
51
47
|
},
|
|
52
|
-
|
|
48
|
+
downloadPackageToUpdatesCmd: {
|
|
53
49
|
flag: `u`,
|
|
54
50
|
required: true,
|
|
55
51
|
description: `Command to update the service.`,
|
|
56
|
-
example: `--
|
|
52
|
+
example: `--downloadPackageToUpdatesCmd=\"./app\"`,
|
|
57
53
|
parse: parseArrayOption,
|
|
58
54
|
},
|
|
59
55
|
},
|
|
@@ -106,7 +102,7 @@ switch (inputs.case) {
|
|
|
106
102
|
default: {
|
|
107
103
|
const flightDeck = new FlightDeck(inputs.opts)
|
|
108
104
|
process.on(`close`, async () => {
|
|
109
|
-
flightDeck.
|
|
105
|
+
flightDeck.stopAllServices()
|
|
110
106
|
await flightDeck.dead
|
|
111
107
|
})
|
|
112
108
|
}
|