mikser-io 9.73.0 → 9.74.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/app.js +3 -6
- package/docs/diagnostics.md +3 -2
- package/package.json +1 -1
- package/src/engine.js +0 -1
- package/src/instance.js +7 -52
package/app.js
CHANGED
|
@@ -49,8 +49,6 @@ function locate(argv) {
|
|
|
49
49
|
longRunning,
|
|
50
50
|
workingFolder: value('--working-folder', '-i') ?? '.',
|
|
51
51
|
config: value('--config', '-c') ?? 'mikser.config.js',
|
|
52
|
-
// Commander's negated form: `attach` is true unless --no-attach said so.
|
|
53
|
-
attach: has('--no-attach') ? false : true,
|
|
54
52
|
request,
|
|
55
53
|
}
|
|
56
54
|
}
|
|
@@ -62,18 +60,17 @@ async function main() {
|
|
|
62
60
|
// A second server or watcher is the hazard this whole surface exists to
|
|
63
61
|
// remove, and it is the one shape that cannot be answered by forwarding.
|
|
64
62
|
// So it stops, rather than silently doing something else.
|
|
65
|
-
if (where.
|
|
63
|
+
if (where.longRunning) {
|
|
66
64
|
if (await isInstanceLive(workingFolder)) {
|
|
67
65
|
process.stderr.write(
|
|
68
66
|
'mikser: another mikser is already running in this folder, and a server or watcher cannot be '
|
|
69
67
|
+ 'forwarded to it — it would have to open a port on your behalf.\n'
|
|
70
|
-
+ 'Stop that one
|
|
71
|
-
+ 'catalogue and the output tree, with no lock between them).\n')
|
|
68
|
+
+ 'Stop that one first.\n')
|
|
72
69
|
process.exit(1)
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
72
|
|
|
76
|
-
if (
|
|
73
|
+
if (!where.longRunning) {
|
|
77
74
|
const code = await forward({
|
|
78
75
|
workingFolder,
|
|
79
76
|
config: path.resolve(where.workingFolder, where.config),
|
package/docs/diagnostics.md
CHANGED
|
@@ -760,8 +760,9 @@ Three things it refuses or reports rather than guessing:
|
|
|
760
760
|
to *become* the instance, which is not something a running one can do for
|
|
761
761
|
you — it would have to open a port in your process. They exit 1 and say so,
|
|
762
762
|
rather than building and leaving nothing on the port.
|
|
763
|
-
-
|
|
764
|
-
|
|
763
|
+
There is no opt-out. A flag for running a second engine on a held folder
|
|
764
|
+
only ever enabled the accident this surface prevents, and stopping the
|
|
765
|
+
instance serves every case it was reached for.
|
|
765
766
|
|
|
766
767
|
`--tool`, `--tools`, `--verify` and `--explain` forward as well, and for a
|
|
767
768
|
different reason than builds do. They only read, so running one locally never
|
package/package.json
CHANGED
package/src/engine.js
CHANGED
|
@@ -386,7 +386,6 @@ export async function setup(options) {
|
|
|
386
386
|
runtime.engine.commander?.version(packageInfo.version)
|
|
387
387
|
.option('-i --working-folder <folder>', 'set mikser working folder', './')
|
|
388
388
|
.option('-c --config <file>', 'set mikser mikser.config.js location', './mikser.config.js')
|
|
389
|
-
.option('--no-attach', 'start a private engine instead of forwarding to the one already running here')
|
|
390
389
|
.option('-m --mode <mode>', 'set mikser runtime mode', 'development')
|
|
391
390
|
.option('-r --clear', 'clear current state before execution', false)
|
|
392
391
|
.option('-o --output-folder <folder>', 'set mikser output folder relative to working folder', 'out')
|
package/src/instance.js
CHANGED
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
// new to learn and no watermark to reason about — which matters, because a
|
|
20
20
|
// design that needs discipline from the caller is the one that gets violated.
|
|
21
21
|
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
22
|
+
// There is no opt-out. A flag for "run a second engine here anyway" only ever
|
|
23
|
+
// enabled the accident this file exists to prevent — two engines sharing one
|
|
24
|
+
// catalogue and one output tree with no lock between them — and no caller had
|
|
25
|
+
// a reason to want it that a stopped instance would not serve better. An
|
|
26
|
+
// option whose only use is the wrong one is not an escape hatch, it is a trap
|
|
27
|
+
// with a name.
|
|
26
28
|
|
|
27
29
|
import net from 'node:net'
|
|
28
30
|
import { createHash } from 'node:crypto'
|
|
@@ -280,7 +282,7 @@ function refuseConfig(socket, request, wrongConfig) {
|
|
|
280
282
|
type: 'refused',
|
|
281
283
|
reason: `this instance is running ${wrongConfig}, and you asked for ${path.resolve(request.config)}.`,
|
|
282
284
|
detail: 'Answering would use the wrong config — the accident this refusal exists to prevent. '
|
|
283
|
-
+ 'Stop that instance
|
|
285
|
+
+ 'Stop that instance and run this again.',
|
|
284
286
|
})
|
|
285
287
|
}
|
|
286
288
|
|
|
@@ -341,7 +343,6 @@ async function serveBuild(socket, request, logger) {
|
|
|
341
343
|
export function serveInstance() {
|
|
342
344
|
onLoaded(async () => {
|
|
343
345
|
if (!runtime.options.watch && !runtime.options.server) return
|
|
344
|
-
if (runtime.options.attach === false) return
|
|
345
346
|
const logger = runtime.engine?.logger
|
|
346
347
|
const endpoint = socketPath(runtime.options.workingFolder)
|
|
347
348
|
|
|
@@ -402,53 +403,7 @@ export function serveInstance() {
|
|
|
402
403
|
|
|
403
404
|
// Say so when a private engine is starting in a folder someone else holds.
|
|
404
405
|
//
|
|
405
|
-
// The local counterpart of the rule already written down for deployments —
|
|
406
|
-
// "never run a one-shot mikser command against the deployment" — which existed
|
|
407
|
-
// because there was no alternative. There is one now, so this covers what is
|
|
408
|
-
// left: --no-attach, and the report-only runs that stay local by design.
|
|
409
|
-
//
|
|
410
|
-
// A warning rather than a refusal. --no-attach is how you deliberately check
|
|
411
|
-
// that a cold start works, and refusing it would take away the escape hatch
|
|
412
|
-
// this design depends on having.
|
|
413
|
-
export async function warnIfHeld({ workingFolder, attached }) {
|
|
414
|
-
const endpoint = socketPath(workingFolder)
|
|
415
|
-
if (process.platform !== 'win32' && !existsSync(endpoint)) return false
|
|
416
|
-
|
|
417
|
-
const live = await new Promise((resolve) => {
|
|
418
|
-
const probe = net.connect(endpoint)
|
|
419
|
-
const done = (answer) => { try { probe.destroy() } catch { /* already gone */ } resolve(answer) }
|
|
420
|
-
probe.on('connect', () => done(true))
|
|
421
|
-
probe.on('error', () => done(false))
|
|
422
|
-
setTimeout(() => done(false), 250).unref?.()
|
|
423
|
-
})
|
|
424
|
-
if (!live) return false
|
|
425
|
-
|
|
426
|
-
const logger = runtime.engine?.logger
|
|
427
|
-
const message = attached === false
|
|
428
|
-
? 'Another mikser is already running in this folder, and --no-attach means this one will not talk to '
|
|
429
|
-
+ 'it. Two engines share the catalogue and the output tree with no lock between them; a --clear from '
|
|
430
|
-
+ 'either is what produces a cold rebuild that renders nothing.'
|
|
431
|
-
: 'Another mikser is already running in this folder. This command reads and does not write, so it is '
|
|
432
|
-
+ 'safe — but it may see a catalogue mid-cycle.'
|
|
433
|
-
logger?.warn?.({ code: 'instance-already-running' }, message)
|
|
434
|
-
return true
|
|
435
|
-
}
|
|
436
|
-
|
|
437
406
|
// Registered at setup so both halves are wired from one call.
|
|
438
407
|
export function instanceControl() {
|
|
439
408
|
serveInstance()
|
|
440
|
-
onLoaded(async () => {
|
|
441
|
-
// Only --no-attach reaches this now. Everything else either forwarded
|
|
442
|
-
// (a build, a report) or refused before setup ran (a second server or
|
|
443
|
-
// watcher), so a process that is still here and not attaching is one
|
|
444
|
-
// that deliberately opted out — and that is exactly the case worth
|
|
445
|
-
// saying something about, long-running or not. The earlier gate
|
|
446
|
-
// skipped watch and server, which excluded `--no-attach --server`:
|
|
447
|
-
// the very command that puts two engines on one folder.
|
|
448
|
-
if (runtime.options.attach !== false) return
|
|
449
|
-
await warnIfHeld({
|
|
450
|
-
workingFolder: runtime.options.workingFolder,
|
|
451
|
-
attached: false,
|
|
452
|
-
})
|
|
453
|
-
})
|
|
454
409
|
}
|