@laurence79/wireit 0.14.13-shared-cache.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/LICENSE +202 -0
- package/README.md +1062 -0
- package/bin/wireit.js +9 -0
- package/lib/analyzer.js +1600 -0
- package/lib/caching/cache.js +7 -0
- package/lib/caching/github-actions-cache.js +832 -0
- package/lib/caching/local-cache.js +78 -0
- package/lib/caching/shared-cache.js +256 -0
- package/lib/cli-options.js +495 -0
- package/lib/cli.js +177 -0
- package/lib/config.js +18 -0
- package/lib/error.js +160 -0
- package/lib/event.js +7 -0
- package/lib/execution/base.js +108 -0
- package/lib/execution/no-command.js +32 -0
- package/lib/execution/service.js +1017 -0
- package/lib/execution/standard.js +683 -0
- package/lib/executor.js +249 -0
- package/lib/fingerprint.js +164 -0
- package/lib/ide.js +583 -0
- package/lib/language-server.js +135 -0
- package/lib/logging/combination-logger.js +41 -0
- package/lib/logging/debug-logger.js +43 -0
- package/lib/logging/logger.js +38 -0
- package/lib/logging/metrics-logger.js +108 -0
- package/lib/logging/quiet/run-tracker.js +597 -0
- package/lib/logging/quiet/stack-map.js +41 -0
- package/lib/logging/quiet/writeover-line.js +197 -0
- package/lib/logging/quiet-logger.js +78 -0
- package/lib/logging/simple-logger.js +296 -0
- package/lib/logging/watch-logger.js +81 -0
- package/lib/script-child-process.js +270 -0
- package/lib/util/ast.js +71 -0
- package/lib/util/async-cache.js +24 -0
- package/lib/util/copy.js +120 -0
- package/lib/util/deferred.js +35 -0
- package/lib/util/delete.js +120 -0
- package/lib/util/dispose.js +16 -0
- package/lib/util/fs.js +258 -0
- package/lib/util/glob.js +255 -0
- package/lib/util/line-monitor.js +69 -0
- package/lib/util/manifest.js +31 -0
- package/lib/util/optimize-mkdirs.js +55 -0
- package/lib/util/package-json-reader.js +61 -0
- package/lib/util/package-json.js +179 -0
- package/lib/util/script-data-dir.js +19 -0
- package/lib/util/shuffle.js +16 -0
- package/lib/util/unreachable.js +12 -0
- package/lib/util/windows.js +87 -0
- package/lib/util/worker-pool.js +61 -0
- package/lib/watcher.js +396 -0
- package/package.json +470 -0
- package/schema.json +132 -0
- package/wireit.svg +1 -0
|
@@ -0,0 +1,1017 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2022 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { BaseExecutionWithCommand } from './base.js';
|
|
7
|
+
import { Fingerprint } from '../fingerprint.js';
|
|
8
|
+
import { Deferred } from '../util/deferred.js';
|
|
9
|
+
import { ScriptChildProcess } from '../script-child-process.js';
|
|
10
|
+
import { LineMonitor } from '../util/line-monitor.js';
|
|
11
|
+
function unknownState(state) {
|
|
12
|
+
return new Error(`Unknown service state ${state.id}`);
|
|
13
|
+
}
|
|
14
|
+
function unexpectedState(state) {
|
|
15
|
+
return new Error(`Unexpected service state ${state.id}`);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execution for a {@link ServiceScriptConfig}.
|
|
19
|
+
*
|
|
20
|
+
* Note that this class represents a service _bound to one particular execution_
|
|
21
|
+
* of the script graph. In non-watch mode (`npm run ...`), there will be one
|
|
22
|
+
* instance of this class per service. In watch mode (`npm run --watch ...`),
|
|
23
|
+
* there will be one instance of this class per service _per watch iteration_,
|
|
24
|
+
* and the underlying child process will be transfered between instances of this
|
|
25
|
+
* class whenever possible to avoid restarts.
|
|
26
|
+
*
|
|
27
|
+
* ```
|
|
28
|
+
* ┌─────────┐
|
|
29
|
+
* ╭─◄─ abort ────┤ INITIAL │
|
|
30
|
+
* │ └────┬────┘
|
|
31
|
+
* │ │
|
|
32
|
+
* ▼ execute
|
|
33
|
+
* │ │
|
|
34
|
+
* │ ┌───────▼────────┐
|
|
35
|
+
* ├─◄─ abort ─┤ EXECUTING_DEPS ├──── depExecErr ────►────╮
|
|
36
|
+
* │ └───────┬────────┘ │
|
|
37
|
+
* │ │ │
|
|
38
|
+
* ▼ depsExecuted │
|
|
39
|
+
* │ │ │
|
|
40
|
+
* │ ┌───────▼────────┐ │
|
|
41
|
+
* ├─◄─ abort ─┤ FINGERPRINTING │ │
|
|
42
|
+
* │ └───────┬────────┘ │
|
|
43
|
+
* │ │ │
|
|
44
|
+
* │ fingerprinted ▼
|
|
45
|
+
* │ │ │
|
|
46
|
+
* │ ╔══════════▼════════════╗ │
|
|
47
|
+
* ▼ ║ adoptee has different ╟─ yes ─╮ │
|
|
48
|
+
* │ ║ fingerprint? ║ │ │
|
|
49
|
+
* │ ╚══════════╤════════════╝ │ │
|
|
50
|
+
* │ │ ▼ │
|
|
51
|
+
* │ no │ │
|
|
52
|
+
* │ │ │ │
|
|
53
|
+
* │ │ ┌─────────▼────────┐ │
|
|
54
|
+
* ├─◄─ abort ─────────│─────◄────┤ STOPPING_ADOPTEE │ │
|
|
55
|
+
* │ │ └─────────┬────────┘ │
|
|
56
|
+
* │ │ │ │
|
|
57
|
+
* │ ▼ adopteeStopped │
|
|
58
|
+
* │ │ │ │
|
|
59
|
+
* │ ├─────◄──────────────╯ │
|
|
60
|
+
* │ │ │
|
|
61
|
+
* ▼ ╔═══════▼════════╗ │
|
|
62
|
+
* │ ║ is persistent? ╟───── yes ──╮ │
|
|
63
|
+
* │ ╚═══════╤════════╝ │ │
|
|
64
|
+
* │ │ │ │
|
|
65
|
+
* │ no │ │
|
|
66
|
+
* │ │ │ │
|
|
67
|
+
* │ ┌─────▼─────┐ │ │
|
|
68
|
+
* ├─◄─ abort ───┤ UNSTARTED │ ▼ ▼
|
|
69
|
+
* │ └─────┬─────┘ │ │
|
|
70
|
+
* │ │ │ │
|
|
71
|
+
* │ start │ │
|
|
72
|
+
* │ │ │ │
|
|
73
|
+
* │ │ ╭─────────◄────────╯ │
|
|
74
|
+
* │ │ │ │
|
|
75
|
+
* │ │ │ ╭─╮ │
|
|
76
|
+
* │ │ │ │start │
|
|
77
|
+
* │ ┌───────▼──▼─▼─┴┐ │
|
|
78
|
+
* ├─◄─ abort ─┤ DEPS_STARTING ├───── depStartErr ───►────┤
|
|
79
|
+
* │ └───────┬───────┘ │
|
|
80
|
+
* │ │ │
|
|
81
|
+
* │ depsStarted │
|
|
82
|
+
* │ │ │
|
|
83
|
+
* │ │ ┌────────────────┐ ╔═════▼════════╗
|
|
84
|
+
* │ ╭◄─ abort ─────│─◄─┤ STARTED_BROKEN ◄─ yes ─╢ has adoptee? ║
|
|
85
|
+
* │ │ │ └───────┬────────┘ ╚═════╤════════╝
|
|
86
|
+
* │ │ │ │ │
|
|
87
|
+
* │ │ │ detach no
|
|
88
|
+
* │ │ │ │ │
|
|
89
|
+
* │ │ │ ╰────────►────────╮ │
|
|
90
|
+
* ▼ │ ╔══════▼═══════╗ │ │
|
|
91
|
+
* │ ▼ ║ has adoptee? ╟───── yes ───────╮ │ │
|
|
92
|
+
* │ │ ╚══════╤═══════╝ │ │ │
|
|
93
|
+
* │ │ │ │ │ │
|
|
94
|
+
* │ │ no │ │ │
|
|
95
|
+
* │ │ │ ╭─╮ ▼ ▼ ▼
|
|
96
|
+
* │ │ │ │ start │ │ │
|
|
97
|
+
* │ │ ┌────▼──▼─┴┐ │ │ │
|
|
98
|
+
* │ ├◄─ abort ┤ STARTING ├──── startErr ──────►───────┤
|
|
99
|
+
* │ │ └────┬────┬┘ │ │ │
|
|
100
|
+
* │ │ │ │ │ │ │
|
|
101
|
+
* │ │ │ ╰─ depServiceExit ───────────►──────────╮
|
|
102
|
+
* │ │ │ (unless watch mode) │ │ │ │
|
|
103
|
+
* │ │ │ │ │ │ │
|
|
104
|
+
* │ │ started │ │ │ │
|
|
105
|
+
* │ │ │ │ │ │ │
|
|
106
|
+
* │ │ ╔══════════▼═══════════╗ │ │ │ │
|
|
107
|
+
* ▼ │ ║ has ready condition? ╟──╮ │ │ │ │
|
|
108
|
+
* │ │ ╚══════════╤═══════════╝ │ │ │ │ │
|
|
109
|
+
* │ │ │ │ │ │ │ │
|
|
110
|
+
* │ │ no yes │ │ │ │
|
|
111
|
+
* │ │ │ │ │ │ │ │
|
|
112
|
+
* │ ▼ ▼ ┌────▼─────┐ ▼ ▼ ▼ ▼
|
|
113
|
+
* │ │ │ │ READYING │ │ │ │ │
|
|
114
|
+
* │ │ │ └────┬───┬─┘ │ │ │ │
|
|
115
|
+
* │ │ │ │ │ │ │ │ │
|
|
116
|
+
* │ │ │ ready ╰── depServiceExit ───►───┤
|
|
117
|
+
* │ │ │ │ (unless watch mode) │
|
|
118
|
+
* │ │ │ ╭─────◄──────╯ │ │ │ │
|
|
119
|
+
* │ │ │ │ │ │ │ │
|
|
120
|
+
* │ │ ╭─╮ │ │ ╭──────────◄──────────╯ │ │ │
|
|
121
|
+
* │ │ start │ │ │ │ │ │ │
|
|
122
|
+
* │ │ ┌▼─┴─▼─▼─▼┐ │ │ │
|
|
123
|
+
* │ ├◄─ abort ┤ STARTED ├── exit ──────────►──────────┤ │
|
|
124
|
+
* │ │ └──────┬─┬┘ │ │ │
|
|
125
|
+
* │ │ │ │ │ │ │
|
|
126
|
+
* │ │ │ ╰── depServiceExit ────────────►─────────┤
|
|
127
|
+
* │ │ │ (unless watch mode) │ │ │
|
|
128
|
+
* │ ▼ │ │ │ │
|
|
129
|
+
* │ │ ╰─── detach ──►─┬─────◄─────╯ │ │
|
|
130
|
+
* │ │ │ │ │
|
|
131
|
+
* ▼ │ │ │ │
|
|
132
|
+
* │ │ ┌──────────┐ │ │ ┌────▼────┐
|
|
133
|
+
* │ ╰─────────► STOPPING │ ▼ ▼ │ FAILING │
|
|
134
|
+
* │ └┬─▲─┬─────┘ │ │ └────┬────┘
|
|
135
|
+
* │ abort │ │ │ │ │
|
|
136
|
+
* │ ╰─╯ │ │ │ exit
|
|
137
|
+
* │ exit │ │ │
|
|
138
|
+
* │ │ ╭─╮ │ │ ╭─╮ │
|
|
139
|
+
* │ │ │ start │ │ │ start │
|
|
140
|
+
* │ ┌────▼─▼─┴┐ ┌────▼─────┐ ┌───▼─▼─┴┐ │
|
|
141
|
+
* ╰──────────────► STOPPED │ │ DETACHED │ │ FAILED ◄────╯
|
|
142
|
+
* └┬─▲──────┘ └┬─▲───────┘ └┬─▲─────┘
|
|
143
|
+
* abort │ *all* │ abort │
|
|
144
|
+
* ╰─╯ ╰─╯ ╰─╯
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export class ServiceScriptExecution extends BaseExecutionWithCommand {
|
|
148
|
+
#state;
|
|
149
|
+
#terminated;
|
|
150
|
+
#isWatchMode;
|
|
151
|
+
constructor(config, executor, logger, entireExecutionAborted, adoptee, isWatchMode) {
|
|
152
|
+
super(config, executor, logger);
|
|
153
|
+
this.#terminated = new Deferred();
|
|
154
|
+
/**
|
|
155
|
+
* Resolves as "ok" when this script decides it is no longer needed, and
|
|
156
|
+
* either has begun shutting down, or never needed to start in the first
|
|
157
|
+
* place.
|
|
158
|
+
*
|
|
159
|
+
* Resolves with an error if this service exited unexpectedly, or if any of
|
|
160
|
+
* its own service dependencies exited unexpectedly.
|
|
161
|
+
*/
|
|
162
|
+
this.terminated = this.#terminated.promise;
|
|
163
|
+
this.#isWatchMode = isWatchMode;
|
|
164
|
+
this.#state = {
|
|
165
|
+
id: 'initial',
|
|
166
|
+
entireExecutionAborted,
|
|
167
|
+
adoptee,
|
|
168
|
+
};
|
|
169
|
+
// Doing this here ensures that we always log when the
|
|
170
|
+
// service stops, no matter how that happens.
|
|
171
|
+
void this.#terminated.promise.then(() => {
|
|
172
|
+
this._logger.log({
|
|
173
|
+
script: this._config,
|
|
174
|
+
type: 'info',
|
|
175
|
+
detail: 'service-stopped',
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Return the fingerprint of this service. Throws if the fingerprint is not
|
|
181
|
+
* yet available. Returns undefined if the service is stopped/failed/detached.
|
|
182
|
+
*/
|
|
183
|
+
get fingerprint() {
|
|
184
|
+
switch (this.#state.id) {
|
|
185
|
+
case 'stoppingAdoptee':
|
|
186
|
+
case 'unstarted':
|
|
187
|
+
case 'depsStarting':
|
|
188
|
+
case 'starting':
|
|
189
|
+
case 'readying':
|
|
190
|
+
case 'started':
|
|
191
|
+
case 'started-broken':
|
|
192
|
+
case 'stopping':
|
|
193
|
+
case 'failing': {
|
|
194
|
+
return this.#state.fingerprint;
|
|
195
|
+
}
|
|
196
|
+
case 'stopped':
|
|
197
|
+
case 'failed': {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
case 'initial':
|
|
201
|
+
case 'executingDeps':
|
|
202
|
+
case 'fingerprinting':
|
|
203
|
+
case 'detached': {
|
|
204
|
+
throw unexpectedState(this.#state);
|
|
205
|
+
}
|
|
206
|
+
default: {
|
|
207
|
+
throw unknownState(this.#state);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Take over ownership of this service's running child process, if there is
|
|
213
|
+
* one.
|
|
214
|
+
*/
|
|
215
|
+
detach() {
|
|
216
|
+
switch (this.#state.id) {
|
|
217
|
+
case 'started':
|
|
218
|
+
case 'started-broken':
|
|
219
|
+
case 'stopping':
|
|
220
|
+
case 'failing': {
|
|
221
|
+
const { child, fingerprint } = this.#state;
|
|
222
|
+
this.#state = { id: 'detached' };
|
|
223
|
+
this.#stopLoggingChildStdio(child);
|
|
224
|
+
return { child, fingerprint };
|
|
225
|
+
}
|
|
226
|
+
case 'stopped':
|
|
227
|
+
case 'failed': {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
case 'unstarted':
|
|
231
|
+
case 'depsStarting':
|
|
232
|
+
case 'starting':
|
|
233
|
+
case 'readying':
|
|
234
|
+
case 'initial':
|
|
235
|
+
case 'executingDeps':
|
|
236
|
+
case 'fingerprinting':
|
|
237
|
+
case 'stoppingAdoptee':
|
|
238
|
+
case 'detached': {
|
|
239
|
+
throw unexpectedState(this.#state);
|
|
240
|
+
}
|
|
241
|
+
default: {
|
|
242
|
+
throw unknownState(this.#state);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Note `execute` is a bit of a misnomer here, because we don't actually
|
|
248
|
+
* execute the command at this stage in the case of services.
|
|
249
|
+
*/
|
|
250
|
+
_execute() {
|
|
251
|
+
switch (this.#state.id) {
|
|
252
|
+
case 'initial': {
|
|
253
|
+
const allConsumersDone = Promise.all(this._config.serviceConsumers.map((consumer) => this._executor.getExecution(consumer).servicesNotNeeded));
|
|
254
|
+
const abort = this._config.isPersistent
|
|
255
|
+
? Promise.all([this.#state.entireExecutionAborted, allConsumersDone])
|
|
256
|
+
: allConsumersDone;
|
|
257
|
+
void abort.then(() => {
|
|
258
|
+
void this.abort();
|
|
259
|
+
});
|
|
260
|
+
this.#state = {
|
|
261
|
+
id: 'executingDeps',
|
|
262
|
+
deferredFingerprint: new Deferred(),
|
|
263
|
+
adoptee: this.#state.adoptee,
|
|
264
|
+
};
|
|
265
|
+
void this._executeDependencies().then((result) => {
|
|
266
|
+
if (result.ok) {
|
|
267
|
+
this.#onDepsExecuted(result.value);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
this.#onDepExecErr(result);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
return this.#state.deferredFingerprint.promise;
|
|
274
|
+
}
|
|
275
|
+
case 'executingDeps':
|
|
276
|
+
case 'fingerprinting':
|
|
277
|
+
case 'stoppingAdoptee':
|
|
278
|
+
case 'unstarted':
|
|
279
|
+
case 'depsStarting':
|
|
280
|
+
case 'starting':
|
|
281
|
+
case 'readying':
|
|
282
|
+
case 'started':
|
|
283
|
+
case 'started-broken':
|
|
284
|
+
case 'stopping':
|
|
285
|
+
case 'stopped':
|
|
286
|
+
case 'failed':
|
|
287
|
+
case 'failing':
|
|
288
|
+
case 'detached': {
|
|
289
|
+
throw unexpectedState(this.#state);
|
|
290
|
+
}
|
|
291
|
+
default: {
|
|
292
|
+
throw unknownState(this.#state);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
#onDepsExecuted(depFingerprints) {
|
|
297
|
+
switch (this.#state.id) {
|
|
298
|
+
case 'executingDeps': {
|
|
299
|
+
this.#state = {
|
|
300
|
+
id: 'fingerprinting',
|
|
301
|
+
deferredFingerprint: this.#state.deferredFingerprint,
|
|
302
|
+
adoptee: this.#state.adoptee,
|
|
303
|
+
};
|
|
304
|
+
void Fingerprint.compute(this._config, depFingerprints).then((result) => {
|
|
305
|
+
if (!result.ok) {
|
|
306
|
+
this.#onFingerprintingErr(result.error);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
this.#onFingerprinted(result.value);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
case 'stopped':
|
|
315
|
+
case 'failed': {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
case 'initial':
|
|
319
|
+
case 'fingerprinting':
|
|
320
|
+
case 'stoppingAdoptee':
|
|
321
|
+
case 'unstarted':
|
|
322
|
+
case 'depsStarting':
|
|
323
|
+
case 'starting':
|
|
324
|
+
case 'readying':
|
|
325
|
+
case 'started':
|
|
326
|
+
case 'started-broken':
|
|
327
|
+
case 'stopping':
|
|
328
|
+
case 'failing':
|
|
329
|
+
case 'detached': {
|
|
330
|
+
throw unexpectedState(this.#state);
|
|
331
|
+
}
|
|
332
|
+
default: {
|
|
333
|
+
throw unknownState(this.#state);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
#onDepExecErr(result) {
|
|
338
|
+
switch (this.#state.id) {
|
|
339
|
+
case 'executingDeps': {
|
|
340
|
+
this.#state.deferredFingerprint.resolve(result);
|
|
341
|
+
const failure = result.error[0];
|
|
342
|
+
const detached = this.#state.adoptee?.detach();
|
|
343
|
+
if (detached !== undefined) {
|
|
344
|
+
this.#enterStartedBrokenState(failure, detached);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
this.#enterFailedState(failure);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
case 'started-broken':
|
|
352
|
+
case 'stopped':
|
|
353
|
+
case 'failed': {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
case 'initial':
|
|
357
|
+
case 'fingerprinting':
|
|
358
|
+
case 'stoppingAdoptee':
|
|
359
|
+
case 'unstarted':
|
|
360
|
+
case 'depsStarting':
|
|
361
|
+
case 'starting':
|
|
362
|
+
case 'readying':
|
|
363
|
+
case 'started':
|
|
364
|
+
case 'stopping':
|
|
365
|
+
case 'failing':
|
|
366
|
+
case 'detached': {
|
|
367
|
+
throw unexpectedState(this.#state);
|
|
368
|
+
}
|
|
369
|
+
default: {
|
|
370
|
+
throw unknownState(this.#state);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
#onFingerprintingErr(failure) {
|
|
375
|
+
switch (this.#state.id) {
|
|
376
|
+
case 'fingerprinting': {
|
|
377
|
+
const detached = this.#state.adoptee?.detach();
|
|
378
|
+
if (detached !== undefined) {
|
|
379
|
+
this.#enterStartedBrokenState(failure, detached);
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
this.#enterFailedState(failure);
|
|
383
|
+
}
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
case 'failed':
|
|
387
|
+
case 'stopped': {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
case 'initial':
|
|
391
|
+
case 'executingDeps':
|
|
392
|
+
case 'stoppingAdoptee':
|
|
393
|
+
case 'unstarted':
|
|
394
|
+
case 'depsStarting':
|
|
395
|
+
case 'starting':
|
|
396
|
+
case 'readying':
|
|
397
|
+
case 'started':
|
|
398
|
+
case 'started-broken':
|
|
399
|
+
case 'stopping':
|
|
400
|
+
case 'failing':
|
|
401
|
+
case 'detached': {
|
|
402
|
+
throw unexpectedState(this.#state);
|
|
403
|
+
}
|
|
404
|
+
default: {
|
|
405
|
+
throw unknownState(this.#state);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
#onFingerprinted(fingerprint) {
|
|
410
|
+
switch (this.#state.id) {
|
|
411
|
+
case 'fingerprinting': {
|
|
412
|
+
const adoptee = this.#state.adoptee;
|
|
413
|
+
if (adoptee?.fingerprint !== undefined &&
|
|
414
|
+
!adoptee.fingerprint.equal(fingerprint)) {
|
|
415
|
+
// There is a previous running version of this service, but the
|
|
416
|
+
// fingerprint changed, so we need to restart it.
|
|
417
|
+
this.#state = {
|
|
418
|
+
id: 'stoppingAdoptee',
|
|
419
|
+
fingerprint,
|
|
420
|
+
deferredFingerprint: this.#state.deferredFingerprint,
|
|
421
|
+
};
|
|
422
|
+
void adoptee.abort().then(() => {
|
|
423
|
+
this.#onAdopteeStopped();
|
|
424
|
+
});
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
this.#state.deferredFingerprint.resolve({
|
|
428
|
+
ok: true,
|
|
429
|
+
value: fingerprint,
|
|
430
|
+
});
|
|
431
|
+
this.#state = {
|
|
432
|
+
id: 'unstarted',
|
|
433
|
+
fingerprint,
|
|
434
|
+
adoptee,
|
|
435
|
+
};
|
|
436
|
+
if (this._config.isPersistent) {
|
|
437
|
+
void this.start();
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
case 'failed':
|
|
442
|
+
case 'stopped': {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
case 'initial':
|
|
446
|
+
case 'executingDeps':
|
|
447
|
+
case 'stoppingAdoptee':
|
|
448
|
+
case 'unstarted':
|
|
449
|
+
case 'depsStarting':
|
|
450
|
+
case 'starting':
|
|
451
|
+
case 'readying':
|
|
452
|
+
case 'started':
|
|
453
|
+
case 'started-broken':
|
|
454
|
+
case 'stopping':
|
|
455
|
+
case 'failing':
|
|
456
|
+
case 'detached': {
|
|
457
|
+
throw unexpectedState(this.#state);
|
|
458
|
+
}
|
|
459
|
+
default: {
|
|
460
|
+
throw unknownState(this.#state);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
#onAdopteeStopped() {
|
|
465
|
+
switch (this.#state.id) {
|
|
466
|
+
case 'stoppingAdoptee': {
|
|
467
|
+
this.#state.deferredFingerprint.resolve({
|
|
468
|
+
ok: true,
|
|
469
|
+
value: this.#state.fingerprint,
|
|
470
|
+
});
|
|
471
|
+
this.#state = {
|
|
472
|
+
id: 'unstarted',
|
|
473
|
+
fingerprint: this.#state.fingerprint,
|
|
474
|
+
adoptee: undefined,
|
|
475
|
+
};
|
|
476
|
+
if (this._config.isPersistent) {
|
|
477
|
+
void this.start();
|
|
478
|
+
}
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
case 'failed':
|
|
482
|
+
case 'stopped': {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
case 'initial':
|
|
486
|
+
case 'executingDeps':
|
|
487
|
+
case 'fingerprinting':
|
|
488
|
+
case 'unstarted':
|
|
489
|
+
case 'depsStarting':
|
|
490
|
+
case 'starting':
|
|
491
|
+
case 'readying':
|
|
492
|
+
case 'started':
|
|
493
|
+
case 'started-broken':
|
|
494
|
+
case 'stopping':
|
|
495
|
+
case 'failing':
|
|
496
|
+
case 'detached': {
|
|
497
|
+
throw unexpectedState(this.#state);
|
|
498
|
+
}
|
|
499
|
+
default: {
|
|
500
|
+
throw unknownState(this.#state);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Start this service if it isn't already started.
|
|
506
|
+
*/
|
|
507
|
+
start() {
|
|
508
|
+
switch (this.#state.id) {
|
|
509
|
+
case 'unstarted': {
|
|
510
|
+
const started = new Deferred();
|
|
511
|
+
this.#state = {
|
|
512
|
+
id: 'depsStarting',
|
|
513
|
+
started,
|
|
514
|
+
fingerprint: this.#state.fingerprint,
|
|
515
|
+
adoptee: this.#state.adoptee,
|
|
516
|
+
};
|
|
517
|
+
void this._startServices().then((result) => {
|
|
518
|
+
if (result.ok) {
|
|
519
|
+
this.#onDepsStarted();
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
this.#onDepStartErr(result);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
void this.terminated.then((result) => {
|
|
526
|
+
if (started.settled) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
// This service terminated before it started. Either a failure occured
|
|
530
|
+
// or we were aborted. If we were aborted, convert to a failure,
|
|
531
|
+
// because this is the start method, where ok means the service
|
|
532
|
+
// started.
|
|
533
|
+
started.resolve(!result.ok
|
|
534
|
+
? result
|
|
535
|
+
: {
|
|
536
|
+
ok: false,
|
|
537
|
+
error: {
|
|
538
|
+
type: 'failure',
|
|
539
|
+
script: this._config,
|
|
540
|
+
reason: 'aborted',
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
return this.#state.started.promise;
|
|
545
|
+
}
|
|
546
|
+
case 'depsStarting':
|
|
547
|
+
case 'starting':
|
|
548
|
+
case 'readying': {
|
|
549
|
+
return this.#state.started.promise;
|
|
550
|
+
}
|
|
551
|
+
case 'started': {
|
|
552
|
+
return Promise.resolve({ ok: true, value: undefined });
|
|
553
|
+
}
|
|
554
|
+
case 'started-broken':
|
|
555
|
+
case 'failing':
|
|
556
|
+
case 'failed': {
|
|
557
|
+
return Promise.resolve({ ok: false, error: this.#state.failure });
|
|
558
|
+
}
|
|
559
|
+
case 'stopping':
|
|
560
|
+
case 'stopped': {
|
|
561
|
+
return Promise.resolve({
|
|
562
|
+
ok: false,
|
|
563
|
+
error: {
|
|
564
|
+
type: 'failure',
|
|
565
|
+
script: this._config,
|
|
566
|
+
reason: 'aborted',
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
case 'initial':
|
|
571
|
+
case 'executingDeps':
|
|
572
|
+
case 'stoppingAdoptee':
|
|
573
|
+
case 'fingerprinting':
|
|
574
|
+
case 'detached': {
|
|
575
|
+
throw unexpectedState(this.#state);
|
|
576
|
+
}
|
|
577
|
+
default: {
|
|
578
|
+
throw unknownState(this.#state);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
#onDepsStarted() {
|
|
583
|
+
switch (this.#state.id) {
|
|
584
|
+
case 'depsStarting': {
|
|
585
|
+
const detached = this.#state.adoptee?.detach();
|
|
586
|
+
if (detached === undefined) {
|
|
587
|
+
const child = new ScriptChildProcess(this._config);
|
|
588
|
+
this.#state = {
|
|
589
|
+
id: 'starting',
|
|
590
|
+
child,
|
|
591
|
+
started: this.#state.started,
|
|
592
|
+
fingerprint: this.#state.fingerprint,
|
|
593
|
+
readyMonitor: this._config.service.readyWhen.lineMatches === undefined
|
|
594
|
+
? undefined
|
|
595
|
+
: new LineMonitor(child, this._config.service.readyWhen.lineMatches),
|
|
596
|
+
};
|
|
597
|
+
void this.#state.child.started.then(() => {
|
|
598
|
+
this.#onChildStarted();
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
this.#state.started.resolve({ ok: true, value: undefined });
|
|
603
|
+
this.#state = {
|
|
604
|
+
id: 'started',
|
|
605
|
+
child: detached.child,
|
|
606
|
+
fingerprint: this.#state.fingerprint,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
void this.#state.child.completed.then(() => {
|
|
610
|
+
this.#onChildExited();
|
|
611
|
+
});
|
|
612
|
+
this.#startLoggingChildStdio(this.#state.child);
|
|
613
|
+
if (!this.#isWatchMode) {
|
|
614
|
+
// If we're in watch mode, we don't care about our dependency services
|
|
615
|
+
// exiting because:
|
|
616
|
+
//
|
|
617
|
+
// 1. If we're iteration N-1 which is about to be adopted into
|
|
618
|
+
// iteration N, our dependencies will sometimes intentionally
|
|
619
|
+
// restart. This should not cause us to fail, since we'll either
|
|
620
|
+
// also restart very shortly (when cascade is true), or we'll just
|
|
621
|
+
// keep running (when cascade is false).
|
|
622
|
+
//
|
|
623
|
+
// 2. If we're iteration N and our dependency unexpectedly exits by
|
|
624
|
+
// itself, it's not actually helpful if we also exit. In non-watch
|
|
625
|
+
// mode it's important because we want wireit itself to exit as
|
|
626
|
+
// soon as this happens, but not so in watch mode.
|
|
627
|
+
void this._anyServiceTerminated.then(() => {
|
|
628
|
+
this.#onDepServiceExit();
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
case 'failed': {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
case 'initial':
|
|
637
|
+
case 'executingDeps':
|
|
638
|
+
case 'fingerprinting':
|
|
639
|
+
case 'stoppingAdoptee':
|
|
640
|
+
case 'unstarted':
|
|
641
|
+
case 'starting':
|
|
642
|
+
case 'readying':
|
|
643
|
+
case 'started':
|
|
644
|
+
case 'started-broken':
|
|
645
|
+
case 'stopping':
|
|
646
|
+
case 'stopped':
|
|
647
|
+
case 'failing':
|
|
648
|
+
case 'detached': {
|
|
649
|
+
throw unexpectedState(this.#state);
|
|
650
|
+
}
|
|
651
|
+
default: {
|
|
652
|
+
throw unknownState(this.#state);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
#onDepStartErr(result) {
|
|
657
|
+
switch (this.#state.id) {
|
|
658
|
+
case 'depsStarting': {
|
|
659
|
+
// TODO(aomarks) The inconsistency between using single vs multiple
|
|
660
|
+
// failure result types is inconvenient. It's ok to just use the first
|
|
661
|
+
// one here, but would make more sense to return all of them.
|
|
662
|
+
const failure = result.error[0];
|
|
663
|
+
const detached = this.#state.adoptee?.detach();
|
|
664
|
+
if (detached !== undefined) {
|
|
665
|
+
this.#enterStartedBrokenState(failure, detached);
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
this.#enterFailedState(failure);
|
|
669
|
+
}
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
case 'failing':
|
|
673
|
+
case 'failed':
|
|
674
|
+
case 'stopping':
|
|
675
|
+
case 'stopped': {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
case 'initial':
|
|
679
|
+
case 'executingDeps':
|
|
680
|
+
case 'fingerprinting':
|
|
681
|
+
case 'stoppingAdoptee':
|
|
682
|
+
case 'unstarted':
|
|
683
|
+
case 'starting':
|
|
684
|
+
case 'readying':
|
|
685
|
+
case 'started':
|
|
686
|
+
case 'started-broken':
|
|
687
|
+
case 'detached': {
|
|
688
|
+
throw unexpectedState(this.#state);
|
|
689
|
+
}
|
|
690
|
+
default: {
|
|
691
|
+
throw unknownState(this.#state);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
#onDepServiceExit() {
|
|
696
|
+
switch (this.#state.id) {
|
|
697
|
+
case 'started':
|
|
698
|
+
case 'started-broken': {
|
|
699
|
+
this.#state.child.kill();
|
|
700
|
+
this.#state = {
|
|
701
|
+
id: 'failing',
|
|
702
|
+
child: this.#state.child,
|
|
703
|
+
fingerprint: this.#state.fingerprint,
|
|
704
|
+
failure: {
|
|
705
|
+
type: 'failure',
|
|
706
|
+
script: this._config,
|
|
707
|
+
reason: 'dependency-service-exited-unexpectedly',
|
|
708
|
+
},
|
|
709
|
+
};
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
case 'starting':
|
|
713
|
+
case 'readying': {
|
|
714
|
+
this.#state = {
|
|
715
|
+
id: 'failing',
|
|
716
|
+
child: this.#state.child,
|
|
717
|
+
fingerprint: this.#state.fingerprint,
|
|
718
|
+
failure: {
|
|
719
|
+
type: 'failure',
|
|
720
|
+
script: this._config,
|
|
721
|
+
reason: 'dependency-service-exited-unexpectedly',
|
|
722
|
+
},
|
|
723
|
+
};
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
case 'stopped':
|
|
727
|
+
case 'stopping':
|
|
728
|
+
case 'failing':
|
|
729
|
+
case 'failed':
|
|
730
|
+
case 'detached': {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
case 'depsStarting':
|
|
734
|
+
case 'initial':
|
|
735
|
+
case 'executingDeps':
|
|
736
|
+
case 'fingerprinting':
|
|
737
|
+
case 'stoppingAdoptee':
|
|
738
|
+
case 'unstarted': {
|
|
739
|
+
throw unexpectedState(this.#state);
|
|
740
|
+
}
|
|
741
|
+
default: {
|
|
742
|
+
throw unknownState(this.#state);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
#onChildStarted() {
|
|
747
|
+
switch (this.#state.id) {
|
|
748
|
+
case 'starting': {
|
|
749
|
+
this._logger.log({
|
|
750
|
+
script: this._config,
|
|
751
|
+
type: 'info',
|
|
752
|
+
detail: 'service-process-started',
|
|
753
|
+
});
|
|
754
|
+
if (this.#state.readyMonitor !== undefined) {
|
|
755
|
+
this.#state = {
|
|
756
|
+
id: 'readying',
|
|
757
|
+
child: this.#state.child,
|
|
758
|
+
fingerprint: this.#state.fingerprint,
|
|
759
|
+
started: this.#state.started,
|
|
760
|
+
readyMonitor: this.#state.readyMonitor,
|
|
761
|
+
};
|
|
762
|
+
void this.#state.readyMonitor.matched.then((result) => {
|
|
763
|
+
if (result.ok) {
|
|
764
|
+
this.#onChildReady();
|
|
765
|
+
}
|
|
766
|
+
// Otherwise the ready monitor aborted, so we don't care.
|
|
767
|
+
});
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
this.#state.started.resolve({ ok: true, value: undefined });
|
|
771
|
+
this._logger.log({
|
|
772
|
+
script: this._config,
|
|
773
|
+
type: 'info',
|
|
774
|
+
detail: 'service-ready',
|
|
775
|
+
});
|
|
776
|
+
this.#state = {
|
|
777
|
+
id: 'started',
|
|
778
|
+
child: this.#state.child,
|
|
779
|
+
fingerprint: this.#state.fingerprint,
|
|
780
|
+
};
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
case 'stopping':
|
|
784
|
+
case 'failing': {
|
|
785
|
+
this.#state.child.kill();
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
case 'initial':
|
|
789
|
+
case 'executingDeps':
|
|
790
|
+
case 'fingerprinting':
|
|
791
|
+
case 'stoppingAdoptee':
|
|
792
|
+
case 'unstarted':
|
|
793
|
+
case 'depsStarting':
|
|
794
|
+
case 'readying':
|
|
795
|
+
case 'started':
|
|
796
|
+
case 'started-broken':
|
|
797
|
+
case 'stopped':
|
|
798
|
+
case 'failed':
|
|
799
|
+
case 'detached': {
|
|
800
|
+
throw unexpectedState(this.#state);
|
|
801
|
+
}
|
|
802
|
+
default: {
|
|
803
|
+
throw unknownState(this.#state);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
#onChildReady() {
|
|
808
|
+
switch (this.#state.id) {
|
|
809
|
+
case 'readying': {
|
|
810
|
+
this.#state.started.resolve({ ok: true, value: undefined });
|
|
811
|
+
this._logger.log({
|
|
812
|
+
script: this._config,
|
|
813
|
+
type: 'info',
|
|
814
|
+
detail: 'service-ready',
|
|
815
|
+
});
|
|
816
|
+
this.#state = {
|
|
817
|
+
id: 'started',
|
|
818
|
+
child: this.#state.child,
|
|
819
|
+
fingerprint: this.#state.fingerprint,
|
|
820
|
+
};
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
case 'starting':
|
|
824
|
+
case 'stopping':
|
|
825
|
+
case 'failing':
|
|
826
|
+
case 'initial':
|
|
827
|
+
case 'executingDeps':
|
|
828
|
+
case 'fingerprinting':
|
|
829
|
+
case 'stoppingAdoptee':
|
|
830
|
+
case 'unstarted':
|
|
831
|
+
case 'depsStarting':
|
|
832
|
+
case 'started':
|
|
833
|
+
case 'started-broken':
|
|
834
|
+
case 'stopped':
|
|
835
|
+
case 'failed':
|
|
836
|
+
case 'detached': {
|
|
837
|
+
throw unexpectedState(this.#state);
|
|
838
|
+
}
|
|
839
|
+
default: {
|
|
840
|
+
throw unknownState(this.#state);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
#onChildExited() {
|
|
845
|
+
switch (this.#state.id) {
|
|
846
|
+
case 'stopping': {
|
|
847
|
+
this.#enterStoppedState();
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
case 'readying': {
|
|
851
|
+
this.#state.readyMonitor.abort();
|
|
852
|
+
const event = {
|
|
853
|
+
script: this._config,
|
|
854
|
+
type: 'failure',
|
|
855
|
+
reason: 'service-exited-unexpectedly',
|
|
856
|
+
};
|
|
857
|
+
this._logger.log(event);
|
|
858
|
+
this.#enterFailedState(event);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
case 'started':
|
|
862
|
+
case 'started-broken': {
|
|
863
|
+
const event = {
|
|
864
|
+
script: this._config,
|
|
865
|
+
type: 'failure',
|
|
866
|
+
reason: 'service-exited-unexpectedly',
|
|
867
|
+
};
|
|
868
|
+
this._logger.log(event);
|
|
869
|
+
this.#enterFailedState(event);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
case 'failing': {
|
|
873
|
+
this.#enterFailedState(this.#state.failure);
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
case 'failed':
|
|
877
|
+
case 'detached': {
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
case 'initial':
|
|
881
|
+
case 'executingDeps':
|
|
882
|
+
case 'fingerprinting':
|
|
883
|
+
case 'stoppingAdoptee':
|
|
884
|
+
case 'unstarted':
|
|
885
|
+
case 'depsStarting':
|
|
886
|
+
case 'starting':
|
|
887
|
+
case 'stopped': {
|
|
888
|
+
throw unexpectedState(this.#state);
|
|
889
|
+
}
|
|
890
|
+
default: {
|
|
891
|
+
throw unknownState(this.#state);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Stop this service if it has started, and return a promise that resolves
|
|
897
|
+
* when it is stopped.
|
|
898
|
+
*/
|
|
899
|
+
abort() {
|
|
900
|
+
switch (this.#state.id) {
|
|
901
|
+
case 'started':
|
|
902
|
+
case 'started-broken': {
|
|
903
|
+
this.#state.child.kill();
|
|
904
|
+
this.#state = {
|
|
905
|
+
id: 'stopping',
|
|
906
|
+
child: this.#state.child,
|
|
907
|
+
fingerprint: this.#state.fingerprint,
|
|
908
|
+
};
|
|
909
|
+
break;
|
|
910
|
+
}
|
|
911
|
+
case 'starting': {
|
|
912
|
+
this.#state.readyMonitor?.abort();
|
|
913
|
+
this.#state = {
|
|
914
|
+
id: 'stopping',
|
|
915
|
+
child: this.#state.child,
|
|
916
|
+
fingerprint: this.#state.fingerprint,
|
|
917
|
+
};
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
case 'readying': {
|
|
921
|
+
this.#state.readyMonitor.abort();
|
|
922
|
+
this.#state.child.kill();
|
|
923
|
+
this.#state = {
|
|
924
|
+
id: 'stopping',
|
|
925
|
+
child: this.#state.child,
|
|
926
|
+
fingerprint: this.#state.fingerprint,
|
|
927
|
+
};
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
case 'executingDeps':
|
|
931
|
+
case 'fingerprinting':
|
|
932
|
+
case 'stoppingAdoptee':
|
|
933
|
+
this.#state.deferredFingerprint.resolve({
|
|
934
|
+
ok: false,
|
|
935
|
+
error: [
|
|
936
|
+
{
|
|
937
|
+
type: 'failure',
|
|
938
|
+
script: this._config,
|
|
939
|
+
reason: 'aborted',
|
|
940
|
+
},
|
|
941
|
+
],
|
|
942
|
+
});
|
|
943
|
+
this.#enterStoppedState();
|
|
944
|
+
break;
|
|
945
|
+
case 'initial':
|
|
946
|
+
case 'unstarted':
|
|
947
|
+
case 'depsStarting': {
|
|
948
|
+
this.#enterStoppedState();
|
|
949
|
+
break;
|
|
950
|
+
}
|
|
951
|
+
case 'stopping':
|
|
952
|
+
case 'stopped':
|
|
953
|
+
case 'failing':
|
|
954
|
+
case 'failed':
|
|
955
|
+
case 'detached': {
|
|
956
|
+
break;
|
|
957
|
+
}
|
|
958
|
+
default: {
|
|
959
|
+
throw unknownState(this.#state);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return this.#terminated.promise.then(() => undefined);
|
|
963
|
+
}
|
|
964
|
+
#enterStoppedState() {
|
|
965
|
+
this.#state = { id: 'stopped' };
|
|
966
|
+
this.#terminated.resolve({ ok: true, value: undefined });
|
|
967
|
+
this._servicesNotNeeded.resolve();
|
|
968
|
+
}
|
|
969
|
+
#enterFailedState(failure) {
|
|
970
|
+
this.#state = {
|
|
971
|
+
id: 'failed',
|
|
972
|
+
failure,
|
|
973
|
+
};
|
|
974
|
+
this._executor.notifyFailure();
|
|
975
|
+
this.#terminated.resolve({ ok: false, error: failure });
|
|
976
|
+
this._servicesNotNeeded.resolve();
|
|
977
|
+
}
|
|
978
|
+
#enterStartedBrokenState(failure, { child, fingerprint }) {
|
|
979
|
+
this.#startLoggingChildStdio(child);
|
|
980
|
+
void child.completed.then(() => {
|
|
981
|
+
this.#onChildExited();
|
|
982
|
+
});
|
|
983
|
+
this.#state = {
|
|
984
|
+
id: 'started-broken',
|
|
985
|
+
child,
|
|
986
|
+
fingerprint,
|
|
987
|
+
failure,
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
#startLoggingChildStdio(child) {
|
|
991
|
+
child.stdout.on('data', (data) => {
|
|
992
|
+
this._logger.log({
|
|
993
|
+
script: this._config,
|
|
994
|
+
type: 'output',
|
|
995
|
+
stream: 'stdout',
|
|
996
|
+
data,
|
|
997
|
+
});
|
|
998
|
+
});
|
|
999
|
+
child.stderr.on('data', (data) => {
|
|
1000
|
+
this._logger.log({
|
|
1001
|
+
script: this._config,
|
|
1002
|
+
type: 'output',
|
|
1003
|
+
stream: 'stderr',
|
|
1004
|
+
data,
|
|
1005
|
+
});
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
#stopLoggingChildStdio(child) {
|
|
1009
|
+
// Note that for some reason, removing all listeners from stdout/stderr
|
|
1010
|
+
// without specifying the "data" event will also remove the listeners
|
|
1011
|
+
// directly on "child" inside the ScriptChildProceess for noticing when e.g.
|
|
1012
|
+
// the process has exited.
|
|
1013
|
+
child.stdout.removeAllListeners('data');
|
|
1014
|
+
child.stderr.removeAllListeners('data');
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
//# sourceMappingURL=service.js.map
|