@jsenv/core 23.1.3 → 23.2.2
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/jsenv_browser_system.js +36 -99
- package/dist/jsenv_browser_system.js.map +12 -21
- package/dist/jsenv_compile_proxy.js +18 -82
- package/dist/jsenv_compile_proxy.js.map +11 -21
- package/dist/jsenv_exploring_index.js +127 -274
- package/dist/jsenv_exploring_index.js.map +76 -90
- package/dist/jsenv_exploring_redirector.js +21 -89
- package/dist/jsenv_exploring_redirector.js.map +13 -25
- package/dist/jsenv_toolbar.js +81 -149
- package/dist/jsenv_toolbar.js.map +50 -61
- package/dist/jsenv_toolbar_injector.js +185 -231
- package/dist/jsenv_toolbar_injector.js.map +30 -42
- package/package.json +8 -9
- package/src/abort/abortable.js +172 -0
- package/src/abort/callback_list.js +64 -0
- package/src/abort/callback_race.js +34 -0
- package/src/abort/cleaner.js +22 -0
- package/src/abort/main.js +32 -0
- package/src/abort/process_teardown_events.js +59 -0
- package/src/buildProject.js +132 -123
- package/src/execute.js +108 -107
- package/src/executeTestPlan.js +107 -125
- package/src/importUsingChildProcess.js +2 -1
- package/src/internal/browser-launcher/executeHtmlFile.js +33 -12
- package/src/internal/browser-utils/fetch-browser.js +4 -29
- package/src/internal/browser-utils/fetchUsingXHR.js +5 -7
- package/src/internal/building/buildUsingRollup.js +60 -24
- package/src/internal/building/createJsenvRollupPlugin.js +13 -31
- package/src/internal/building/ressource_builder.js +3 -6
- package/src/internal/building/sourcemap_loader.js +4 -5
- package/src/internal/building/url_fetcher.js +2 -5
- package/src/internal/building/url_loader.js +3 -6
- package/src/internal/compiling/compileFile.js +1 -2
- package/src/internal/compiling/createCompiledFileService.js +8 -9
- package/src/internal/compiling/startCompileServer.js +74 -135
- package/src/internal/executing/coverage/generateCoverageJsonFile.js +20 -3
- package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +19 -30
- package/src/internal/executing/coverage/reportToCoverage.js +44 -24
- package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +2 -15
- package/src/internal/executing/createSummaryLog.js +50 -37
- package/src/internal/executing/executeConcurrently.js +89 -47
- package/src/internal/executing/executePlan.js +33 -7
- package/src/internal/executing/executionLogs.js +25 -28
- package/src/internal/executing/execution_colors.js +15 -0
- package/src/internal/executing/generateExecutionSteps.js +3 -2
- package/src/internal/executing/launchAndExecute.js +217 -261
- package/src/internal/exploring/fetchExploringJson.js +3 -4
- package/src/internal/fetchUrl.js +6 -2
- package/src/internal/logs/log_style.js +16 -28
- package/src/internal/logs/msAsDuration.js +1 -1
- package/src/internal/node-launcher/createChildProcessOptions.js +4 -5
- package/src/internal/node-launcher/createControllableNodeProcess.js +117 -229
- package/src/internal/node-launcher/kill_process_tree.js +76 -0
- package/src/internal/node-launcher/nodeControllableFile.mjs +16 -10
- package/src/internal/{promise_track_race.js → promise_race.js} +2 -2
- package/src/internal/runtime/s.js +25 -24
- package/src/internal/toolbar/toolbar.html +157 -61
- package/src/internal/toolbar/toolbar.injector.js +8 -0
- package/src/internal/toolbar/util/animation.js +3 -7
- package/src/internal/toolbar/util/fetching.js +1 -30
- package/src/jsenvServiceWorkerFinalizer.js +1 -2
- package/src/launchBrowser.js +131 -127
- package/src/launchNode.js +29 -17
- package/src/playwright_browser_versions.js +3 -3
- package/src/requireUsingChildProcess.js +2 -1
- package/src/signal/signal.js +65 -0
- package/src/startExploring.js +70 -72
- package/src/internal/executeJsenvAsyncFunction.js +0 -34
- package/src/internal/toolbar/animation/toolbar-movie-icon.svg +0 -15
- package/src/internal/toolbar/compilation/flask.svg +0 -7
- package/src/internal/toolbar/compilation/info.svg +0 -9
- package/src/internal/toolbar/compilation/loupe.svg +0 -11
- package/src/internal/toolbar/compilation/toolbar_compilation.svg +0 -11
- package/src/internal/toolbar/eventsource/toolbar-power-icon.svg +0 -10
- package/src/internal/toolbar/eventsource/toolbar-power-off-icon.svg +0 -10
- package/src/internal/toolbar/responsive/toolbar-dots-icon.svg +0 -10
- package/src/internal/toolbar/settings/toolbar-settings-icon.svg +0 -9
- package/src/internal/toolbar/theme/toolbar-palette-icon.svg +0 -10
- package/src/internal/toolbar/toolbar-cross-icon.svg +0 -10
- package/src/internal/toolbar/toolbar-loading-icon.svg +0 -102
- package/src/internal/toolbar/toolbar-notif-icon.svg +0 -9
- package/src/internal/trackRessources.js +0 -23
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createCancellationToken } from "@jsenv/cancellation"
|
|
2
1
|
import { findFreePort } from "@jsenv/server"
|
|
3
2
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
4
3
|
|
|
@@ -14,7 +13,7 @@ const AVAILABLE_DEBUG_MODE = [
|
|
|
14
13
|
]
|
|
15
14
|
|
|
16
15
|
export const createChildProcessOptions = async ({
|
|
17
|
-
|
|
16
|
+
signal = new AbortController().signal,
|
|
18
17
|
// https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_automatically-attach-debugger-to-nodejs-subprocesses
|
|
19
18
|
processExecArgv = process.execArgv,
|
|
20
19
|
processDebugPort = process.debugPort,
|
|
@@ -38,7 +37,7 @@ export const createChildProcessOptions = async ({
|
|
|
38
37
|
const childProcessOptions = processOptionsFromExecArgv(processExecArgv)
|
|
39
38
|
|
|
40
39
|
await mutateDebuggingOptions(childProcessOptions, {
|
|
41
|
-
|
|
40
|
+
signal,
|
|
42
41
|
processDebugPort,
|
|
43
42
|
debugMode,
|
|
44
43
|
debugPort,
|
|
@@ -52,7 +51,7 @@ const mutateDebuggingOptions = async (
|
|
|
52
51
|
childProcessOptions,
|
|
53
52
|
{
|
|
54
53
|
// ensure multiline
|
|
55
|
-
|
|
54
|
+
signal,
|
|
56
55
|
processDebugPort,
|
|
57
56
|
debugMode,
|
|
58
57
|
debugPort,
|
|
@@ -92,7 +91,7 @@ const mutateDebuggingOptions = async (
|
|
|
92
91
|
// support assigning a child spawned without a specific port
|
|
93
92
|
const childDebugPortOptionValue =
|
|
94
93
|
debugPort === 0
|
|
95
|
-
? await findFreePort(processDebugPort + 37, {
|
|
94
|
+
? await findFreePort(processDebugPort + 37, { signal })
|
|
96
95
|
: debugPort
|
|
97
96
|
// replace child debug port
|
|
98
97
|
if (parentDebugPortOptionName) {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import { fork as forkChildProcess } from "node:child_process"
|
|
3
|
-
|
|
1
|
+
import { fork } from "node:child_process"
|
|
4
2
|
import { uneval } from "@jsenv/uneval"
|
|
5
|
-
import { createCancellationToken } from "@jsenv/cancellation"
|
|
6
3
|
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
7
4
|
import {
|
|
8
5
|
urlToFileSystemPath,
|
|
@@ -10,14 +7,17 @@ import {
|
|
|
10
7
|
assertFilePresence,
|
|
11
8
|
} from "@jsenv/filesystem"
|
|
12
9
|
|
|
10
|
+
import { Abortable } from "@jsenv/core/src/abort/main.js"
|
|
11
|
+
import { raceCallbacks } from "@jsenv/core/src/abort/callback_race.js"
|
|
12
|
+
import { createSignal } from "@jsenv/core/src/signal/signal.js"
|
|
13
13
|
import { nodeSupportsDynamicImport } from "../runtime/node-feature-detect/nodeSupportsDynamicImport.js"
|
|
14
14
|
import { jsenvCoreDirectoryUrl } from "../jsenvCoreDirectoryUrl.js"
|
|
15
|
-
import { require } from "../require.js"
|
|
16
15
|
import { createChildProcessOptions } from "./createChildProcessOptions.js"
|
|
17
16
|
import {
|
|
18
17
|
processOptionsFromExecArgv,
|
|
19
18
|
execArgvFromProcessOptions,
|
|
20
19
|
} from "./processOptions.js"
|
|
20
|
+
import { killProcessTree } from "./kill_process_tree.js"
|
|
21
21
|
|
|
22
22
|
const nodeControllableFileUrl = resolveUrl(
|
|
23
23
|
"./src/internal/node-launcher/nodeControllableFile.mjs",
|
|
@@ -40,7 +40,7 @@ const STOP_SIGNAL = "SIGKILL"
|
|
|
40
40
|
const GRACEFUL_STOP_FAILED_SIGNAL = "SIGKILL"
|
|
41
41
|
|
|
42
42
|
export const createControllableNodeProcess = async ({
|
|
43
|
-
|
|
43
|
+
signal = new AbortController().signal,
|
|
44
44
|
logLevel,
|
|
45
45
|
debugPort,
|
|
46
46
|
debugMode,
|
|
@@ -61,7 +61,7 @@ export const createControllableNodeProcess = async ({
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const childProcessOptions = await createChildProcessOptions({
|
|
64
|
-
|
|
64
|
+
signal,
|
|
65
65
|
debugPort,
|
|
66
66
|
debugMode,
|
|
67
67
|
debugModeInheritBreak,
|
|
@@ -81,22 +81,19 @@ export const createControllableNodeProcess = async ({
|
|
|
81
81
|
...(inheritProcessEnv ? process.env : {}),
|
|
82
82
|
...env,
|
|
83
83
|
}
|
|
84
|
-
const childProcess =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
env: envForChildProcess,
|
|
91
|
-
},
|
|
92
|
-
)
|
|
84
|
+
const childProcess = fork(urlToFileSystemPath(nodeControllableFileUrl), {
|
|
85
|
+
execArgv,
|
|
86
|
+
// silent: true
|
|
87
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
88
|
+
env: envForChildProcess,
|
|
89
|
+
})
|
|
93
90
|
|
|
94
|
-
logger.debug(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
logger.debug(
|
|
92
|
+
createDetailedMessage(`fork child process pid ${childProcess.pid}`, {
|
|
93
|
+
"execArgv": execArgv.join(`\n`),
|
|
94
|
+
"custom env": JSON.stringify(env, null, " "),
|
|
95
|
+
}),
|
|
96
|
+
)
|
|
100
97
|
|
|
101
98
|
// if we passe stream, pipe them https://github.com/sindresorhus/execa/issues/81
|
|
102
99
|
if (typeof stdin === "object") {
|
|
@@ -120,199 +117,121 @@ ${JSON.stringify(env, null, " ")}`)
|
|
|
120
117
|
onceProcessMessage(childProcess, "ready", resolve)
|
|
121
118
|
})
|
|
122
119
|
|
|
123
|
-
const
|
|
124
|
-
const registerConsoleCallback = (callback) => {
|
|
125
|
-
consoleCallbackArray.push(callback)
|
|
126
|
-
}
|
|
120
|
+
const outputSignal = createSignal()
|
|
127
121
|
const removeOutputListener = installProcessOutputListener(
|
|
128
122
|
childProcess,
|
|
129
123
|
({ type, text }) => {
|
|
130
|
-
|
|
131
|
-
callback({
|
|
132
|
-
type,
|
|
133
|
-
text,
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
},
|
|
137
|
-
)
|
|
138
|
-
// keep listening process outputs while child process is killed to catch
|
|
139
|
-
// outputs until it's actually disconnected
|
|
140
|
-
// registerCleanupCallback(removeProcessOutputListener)
|
|
141
|
-
|
|
142
|
-
const errorCallbackArray = []
|
|
143
|
-
const registerErrorCallback = (callback) => {
|
|
144
|
-
errorCallbackArray.push(callback)
|
|
145
|
-
return () => {
|
|
146
|
-
const index = errorCallbackArray.indexOf(callback)
|
|
147
|
-
if (index > -1) {
|
|
148
|
-
errorCallbackArray.splice(index, 1)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
let killing = false
|
|
153
|
-
const removeErrorListener = installProcessErrorListener(
|
|
154
|
-
childProcess,
|
|
155
|
-
(error) => {
|
|
156
|
-
removeOutputListener()
|
|
157
|
-
if (!childProcess.connected && error.code === "ERR_IPC_DISCONNECTED") {
|
|
158
|
-
return
|
|
159
|
-
}
|
|
160
|
-
// on windows killProcessTree uses taskkill which seems to kill the process
|
|
161
|
-
// with an exitCode of 1
|
|
162
|
-
if (process.platform === "win32" && killing && error.exitCode === 1) {
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
errorCallbackArray.forEach((callback) => {
|
|
166
|
-
callback(error)
|
|
167
|
-
})
|
|
124
|
+
outputSignal.emit({ type, text })
|
|
168
125
|
},
|
|
169
126
|
)
|
|
170
|
-
// keep listening process errors while child process is killed to catch
|
|
171
|
-
// errors until it's actually disconnected
|
|
172
|
-
// registerCleanupCallback(removeProcessErrorListener)
|
|
173
|
-
|
|
174
|
-
// https://nodejs.org/api/child_process.html#child_process_event_disconnect
|
|
175
|
-
let resolveDisconnect
|
|
176
|
-
let hasExitedOrDisconnected = false
|
|
177
|
-
const disconnected = new Promise((resolve) => {
|
|
178
|
-
resolveDisconnect = () => {
|
|
179
|
-
hasExitedOrDisconnected = true
|
|
180
|
-
removeExitListener()
|
|
181
|
-
removeDisconnectListener()
|
|
182
|
-
}
|
|
183
127
|
|
|
184
|
-
|
|
185
|
-
childProcess,
|
|
186
|
-
"disconnect",
|
|
187
|
-
() => {
|
|
188
|
-
hasExitedOrDisconnected = true
|
|
189
|
-
removeErrorListener()
|
|
190
|
-
removeExitListener()
|
|
191
|
-
resolve()
|
|
192
|
-
},
|
|
193
|
-
)
|
|
128
|
+
const errorSignal = createSignal()
|
|
194
129
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
removeErrorListener()
|
|
198
|
-
removeDisconnectListener()
|
|
199
|
-
resolve()
|
|
200
|
-
})
|
|
130
|
+
const stoppedSignal = createSignal({
|
|
131
|
+
once: true,
|
|
201
132
|
})
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
killing = true
|
|
226
|
-
logger.debug(`send ${signal} to child process with pid ${childProcess.pid}`)
|
|
227
|
-
|
|
228
|
-
await new Promise((resolve) => {
|
|
229
|
-
// see also https://github.com/sindresorhus/execa/issues/96
|
|
230
|
-
const killProcessTree = require("tree-kill")
|
|
231
|
-
killProcessTree(childProcess.pid, signal, (error) => {
|
|
232
|
-
if (error) {
|
|
233
|
-
// on windows: process with pid cannot be found
|
|
234
|
-
if (
|
|
235
|
-
error.stack.includes(`The process "${childProcess.pid}" not found`)
|
|
236
|
-
) {
|
|
237
|
-
resolve()
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
// on windows: child process with a pid cannot be found
|
|
133
|
+
raceCallbacks(
|
|
134
|
+
{
|
|
135
|
+
// https://nodejs.org/api/child_process.html#child_process_event_disconnect
|
|
136
|
+
// disconnect: (cb) => {
|
|
137
|
+
// return onceProcessEvent(childProcess, "disconnect", cb)
|
|
138
|
+
// },
|
|
139
|
+
// https://nodejs.org/api/child_process.html#child_process_event_error
|
|
140
|
+
error: (cb) => {
|
|
141
|
+
return onceProcessEvent(childProcess, "error", cb)
|
|
142
|
+
},
|
|
143
|
+
exit: (cb) => {
|
|
144
|
+
return onceProcessEvent(childProcess, "exit", (code, signal) => {
|
|
145
|
+
cb({ code, signal })
|
|
146
|
+
})
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
(winner) => {
|
|
150
|
+
const raceEffects = {
|
|
151
|
+
// disconnect: () => {
|
|
152
|
+
// stoppedSignal.emit()
|
|
153
|
+
// },
|
|
154
|
+
error: (error) => {
|
|
155
|
+
removeOutputListener()
|
|
241
156
|
if (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
)
|
|
157
|
+
!childProcess.connected &&
|
|
158
|
+
error.code === "ERR_IPC_DISCONNECTED"
|
|
245
159
|
) {
|
|
246
|
-
resolve()
|
|
247
160
|
return
|
|
248
161
|
}
|
|
249
|
-
|
|
162
|
+
errorSignal.emit(error)
|
|
163
|
+
},
|
|
164
|
+
exit: ({ code, signal }) => {
|
|
165
|
+
// process.exit(1) in child process or process.exitCode = 1 + process.exit()
|
|
166
|
+
// means there was an error even if we don't know exactly what.
|
|
250
167
|
if (
|
|
251
|
-
|
|
168
|
+
code !== null &&
|
|
169
|
+
code !== 0 &&
|
|
170
|
+
code !== SIGINT_EXIT_CODE &&
|
|
171
|
+
code !== SIGTERM_EXIT_CODE &&
|
|
172
|
+
code !== SIGABORT_EXIT_CODE
|
|
252
173
|
) {
|
|
253
|
-
|
|
254
|
-
return
|
|
174
|
+
errorSignal.emit(createExitWithFailureCodeError(code))
|
|
255
175
|
}
|
|
176
|
+
stoppedSignal.emit({ code, signal })
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
raceEffects[winner.name](winner.data)
|
|
180
|
+
},
|
|
181
|
+
)
|
|
256
182
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
["error stack"]: error.stack,
|
|
262
|
-
["process.pid"]: childProcess.pid,
|
|
263
|
-
},
|
|
264
|
-
),
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
// even if we could not kill the child
|
|
268
|
-
// we will ask it to disconnect
|
|
269
|
-
resolve()
|
|
270
|
-
return
|
|
271
|
-
}
|
|
183
|
+
const stop = async ({ gracefulStopAllocatedMs } = {}) => {
|
|
184
|
+
if (stoppedSignal.emitted) {
|
|
185
|
+
return {}
|
|
186
|
+
}
|
|
272
187
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
188
|
+
const createStoppedPromise = async () => {
|
|
189
|
+
if (stoppedSignal.emitted) {
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
await new Promise((resolve) => stoppedSignal.addCallback(resolve))
|
|
193
|
+
}
|
|
276
194
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
195
|
+
if (gracefulStopAllocatedMs) {
|
|
196
|
+
try {
|
|
197
|
+
await killProcessTree(childProcess.pid, {
|
|
198
|
+
signal: GRACEFUL_STOP_SIGNAL,
|
|
199
|
+
timeout: gracefulStopAllocatedMs,
|
|
200
|
+
})
|
|
201
|
+
await createStoppedPromise()
|
|
202
|
+
return { graceful: true }
|
|
203
|
+
} catch (e) {
|
|
204
|
+
if (e.code === "TIMEOUT") {
|
|
205
|
+
logger.debug(
|
|
206
|
+
`kill with SIGTERM because gracefulStop still pending after ${gracefulStopAllocatedMs}ms`,
|
|
207
|
+
)
|
|
208
|
+
await killProcessTree(childProcess.pid, {
|
|
209
|
+
signal: GRACEFUL_STOP_FAILED_SIGNAL,
|
|
210
|
+
})
|
|
211
|
+
await createStoppedPromise()
|
|
212
|
+
return { graceful: false }
|
|
213
|
+
}
|
|
214
|
+
throw e
|
|
215
|
+
}
|
|
216
|
+
}
|
|
282
217
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
new Promise((resolve, reject) => {
|
|
287
|
-
unregisterErrorCallback = registerErrorCallback(reject)
|
|
288
|
-
}),
|
|
289
|
-
killChildProcess({
|
|
290
|
-
signal: gracefulFailed ? GRACEFUL_STOP_FAILED_SIGNAL : STOP_SIGNAL,
|
|
291
|
-
}),
|
|
292
|
-
])
|
|
293
|
-
unregisterErrorCallback()
|
|
218
|
+
await killProcessTree(childProcess.pid, { signal: STOP_SIGNAL })
|
|
219
|
+
await createStoppedPromise()
|
|
220
|
+
return { graceful: false }
|
|
294
221
|
}
|
|
295
222
|
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
killChildProcess({ signal: GRACEFUL_STOP_SIGNAL }),
|
|
303
|
-
])
|
|
304
|
-
unregisterErrorCallback()
|
|
305
|
-
}
|
|
223
|
+
const requestActionOnChildProcess = ({
|
|
224
|
+
signal,
|
|
225
|
+
actionType,
|
|
226
|
+
actionParams,
|
|
227
|
+
}) => {
|
|
228
|
+
const actionAbortable = Abortable.fromSignal(signal)
|
|
306
229
|
|
|
307
|
-
const requestActionOnChildProcess = ({ actionType, actionParams }) => {
|
|
308
230
|
return new Promise(async (resolve, reject) => {
|
|
231
|
+
Abortable.throwIfAborted(actionAbortable)
|
|
232
|
+
await childProcessReadyPromise
|
|
233
|
+
|
|
309
234
|
onceProcessMessage(childProcess, "action-result", ({ status, value }) => {
|
|
310
|
-
logger.debug(
|
|
311
|
-
createDetailedMessage(`child process sent an action result.`, {
|
|
312
|
-
status,
|
|
313
|
-
value: JSON.stringify(value, null, " "),
|
|
314
|
-
}),
|
|
315
|
-
)
|
|
316
235
|
if (status === "action-completed") {
|
|
317
236
|
resolve(value)
|
|
318
237
|
} else {
|
|
@@ -327,13 +246,16 @@ ${JSON.stringify(env, null, " ")}`)
|
|
|
327
246
|
}),
|
|
328
247
|
)
|
|
329
248
|
|
|
330
|
-
await childProcessReadyPromise
|
|
331
249
|
try {
|
|
250
|
+
Abortable.throwIfAborted(actionAbortable)
|
|
332
251
|
await sendToProcess(childProcess, "action", {
|
|
333
252
|
actionType,
|
|
334
253
|
actionParams,
|
|
335
254
|
})
|
|
336
255
|
} catch (e) {
|
|
256
|
+
if (actionAbortable.signal.aborted && e.name === "AbortError") {
|
|
257
|
+
throw e
|
|
258
|
+
}
|
|
337
259
|
logger.error(
|
|
338
260
|
createDetailedMessage(`error while sending message to child`, {
|
|
339
261
|
["error stack"]: e.stack,
|
|
@@ -346,15 +268,11 @@ ${JSON.stringify(env, null, " ")}`)
|
|
|
346
268
|
|
|
347
269
|
return {
|
|
348
270
|
execArgv,
|
|
349
|
-
|
|
271
|
+
stoppedSignal,
|
|
272
|
+
errorSignal,
|
|
273
|
+
outputSignal,
|
|
350
274
|
stop,
|
|
351
|
-
disconnected,
|
|
352
|
-
registerErrorCallback,
|
|
353
|
-
registerConsoleCallback,
|
|
354
275
|
requestActionOnChildProcess,
|
|
355
|
-
onceChildProcessEvent: (event, callback) => {
|
|
356
|
-
onceProcessEvent(childProcess, event, callback)
|
|
357
|
-
},
|
|
358
276
|
}
|
|
359
277
|
}
|
|
360
278
|
|
|
@@ -390,36 +308,6 @@ const installProcessOutputListener = (childProcess, callback) => {
|
|
|
390
308
|
}
|
|
391
309
|
}
|
|
392
310
|
|
|
393
|
-
const installProcessErrorListener = (childProcess, callback) => {
|
|
394
|
-
// https://nodejs.org/api/child_process.html#child_process_event_error
|
|
395
|
-
const removeErrorListener = onceProcessMessage(
|
|
396
|
-
childProcess,
|
|
397
|
-
"error",
|
|
398
|
-
(error) => {
|
|
399
|
-
removeExitListener() // if an error occured we ignore the child process exitCode
|
|
400
|
-
callback(error)
|
|
401
|
-
},
|
|
402
|
-
)
|
|
403
|
-
// process.exit(1) in child process or process.exitCode = 1 + process.exit()
|
|
404
|
-
// means there was an error even if we don't know exactly what.
|
|
405
|
-
const removeExitListener = onceProcessEvent(childProcess, "exit", (code) => {
|
|
406
|
-
if (
|
|
407
|
-
code !== null &&
|
|
408
|
-
code !== 0 &&
|
|
409
|
-
code !== SIGINT_EXIT_CODE &&
|
|
410
|
-
code !== SIGTERM_EXIT_CODE &&
|
|
411
|
-
code !== SIGABORT_EXIT_CODE
|
|
412
|
-
) {
|
|
413
|
-
removeErrorListener()
|
|
414
|
-
callback(createExitWithFailureCodeError(code))
|
|
415
|
-
}
|
|
416
|
-
})
|
|
417
|
-
return () => {
|
|
418
|
-
removeErrorListener()
|
|
419
|
-
removeExitListener()
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
311
|
const createExitWithFailureCodeError = (code) => {
|
|
424
312
|
if (code === 12) {
|
|
425
313
|
return new Error(
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { require } from "../require.js"
|
|
2
|
+
|
|
3
|
+
// see also https://github.com/sindresorhus/execa/issues/96
|
|
4
|
+
export const killProcessTree = async (
|
|
5
|
+
processId,
|
|
6
|
+
{ signal, timeout = 2000 },
|
|
7
|
+
) => {
|
|
8
|
+
var pidtree = require("pidtree")
|
|
9
|
+
|
|
10
|
+
let descendantProcessIds
|
|
11
|
+
try {
|
|
12
|
+
descendantProcessIds = await pidtree(processId)
|
|
13
|
+
} catch (e) {
|
|
14
|
+
if (e.message === "No matching pid found") {
|
|
15
|
+
descendantProcessIds = []
|
|
16
|
+
} else {
|
|
17
|
+
throw e
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
descendantProcessIds.forEach((descendantProcessId) => {
|
|
21
|
+
try {
|
|
22
|
+
process.kill(descendantProcessId, signal)
|
|
23
|
+
} catch (error) {
|
|
24
|
+
// ignore
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
process.kill(processId, signal)
|
|
30
|
+
} catch (e) {
|
|
31
|
+
if (e.code !== "ESRCH") {
|
|
32
|
+
throw e
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let remainingIds = [...descendantProcessIds, processId]
|
|
37
|
+
|
|
38
|
+
const updateRemainingIds = () => {
|
|
39
|
+
remainingIds = remainingIds.filter((remainingId) => {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(remainingId, 0)
|
|
42
|
+
return true
|
|
43
|
+
} catch (e) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let timeSpentWaiting = 0
|
|
50
|
+
|
|
51
|
+
const check = async () => {
|
|
52
|
+
updateRemainingIds()
|
|
53
|
+
if (remainingIds.length === 0) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (timeSpentWaiting > timeout) {
|
|
58
|
+
const timeoutError = new Error(
|
|
59
|
+
`timed out waiting for ${
|
|
60
|
+
remainingIds.length
|
|
61
|
+
} process to exit (${remainingIds.join(" ")})`,
|
|
62
|
+
)
|
|
63
|
+
timeoutError.code = "TIMEOUT"
|
|
64
|
+
throw timeoutError
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
await new Promise((resolve) => setTimeout(resolve, 400))
|
|
68
|
+
timeSpentWaiting += 400
|
|
69
|
+
await check()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await new Promise((resolve) => {
|
|
73
|
+
setTimeout(resolve, 0)
|
|
74
|
+
})
|
|
75
|
+
await check()
|
|
76
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import v8 from "node:v8"
|
|
1
2
|
import { uneval } from "@jsenv/uneval"
|
|
2
3
|
|
|
3
4
|
import { jsenvNodeSystemFileInfo } from "@jsenv/core/src/internal/jsenvInternalFiles.js"
|
|
@@ -116,13 +117,6 @@ const onceProcessMessage = (type, callback) => {
|
|
|
116
117
|
return removeListener
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
const onceSIGTERM = (callback) => {
|
|
120
|
-
process.once("SIGTERM", callback)
|
|
121
|
-
return () => {
|
|
122
|
-
process.removeListener("SIGTERM", callback)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
120
|
const removeActionRequestListener = onceProcessMessage(
|
|
127
121
|
ACTION_REQUEST_EVENT_NAME,
|
|
128
122
|
async ({ actionType, actionParams }) => {
|
|
@@ -141,6 +135,15 @@ const removeActionRequestListener = onceProcessMessage(
|
|
|
141
135
|
value = e
|
|
142
136
|
}
|
|
143
137
|
|
|
138
|
+
if (process.env.NODE_V8_COVERAGE) {
|
|
139
|
+
v8.takeCoverage()
|
|
140
|
+
// if (actionParams.stopCoverageAfterExecution) {
|
|
141
|
+
// v8.stopCoverage()
|
|
142
|
+
// }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// setTimeout(() => {}, 100)
|
|
146
|
+
|
|
144
147
|
if (failed) {
|
|
145
148
|
sendActionFailed(value)
|
|
146
149
|
} else {
|
|
@@ -149,8 +152,10 @@ const removeActionRequestListener = onceProcessMessage(
|
|
|
149
152
|
|
|
150
153
|
// removeActionRequestListener()
|
|
151
154
|
if (actionParams.exitAfterAction) {
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
removeActionRequestListener()
|
|
156
|
+
|
|
157
|
+
// for some reason this fixes v8 coverage directory sometimes empty on Ubuntu
|
|
158
|
+
// process.exit()
|
|
154
159
|
}
|
|
155
160
|
},
|
|
156
161
|
)
|
|
@@ -158,6 +163,7 @@ const removeActionRequestListener = onceProcessMessage(
|
|
|
158
163
|
// remove listener to process.on('message')
|
|
159
164
|
// which is sufficient to let child process die
|
|
160
165
|
// assuming nothing else keeps it alive
|
|
161
|
-
|
|
166
|
+
// process.once("SIGTERM", removeActionRequestListener)
|
|
167
|
+
// process.once("SIGINT", removeActionRequestListener)
|
|
162
168
|
|
|
163
169
|
setTimeout(() => sendToParent("ready"))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const racePromises = (promiseArray) => {
|
|
2
2
|
return new Promise((resolve, reject) => {
|
|
3
3
|
let resolved = false
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ export const promiseTrackRace = (promiseArray) => {
|
|
|
7
7
|
promise.then((value) => {
|
|
8
8
|
if (resolved) return
|
|
9
9
|
resolved = true
|
|
10
|
-
resolve({
|
|
10
|
+
resolve({ promise, value, index })
|
|
11
11
|
}, reject)
|
|
12
12
|
}
|
|
13
13
|
|