getculpa 1.0.7 → 1.0.10
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/README.md +6 -2
- package/assets/culpa-compose.yml +3 -3
- package/assets/uninstall-culpa.ps1 +251 -227
- package/bin/getculpa.js +9 -5
- package/lib/dispatch.mjs +7 -0
- package/lib/docker.mjs +290 -270
- package/lib/doctor.mjs +454 -420
- package/lib/preflight.mjs +322 -274
- package/lib/provision.mjs +47 -5
- package/lib/start.mjs +524 -487
- package/lib/uninstall.d.mts +20 -17
- package/lib/uninstall.mjs +158 -138
- package/package.json +26 -25
- package/scripts/preuninstall.js +82 -0
package/lib/provision.mjs
CHANGED
|
@@ -17,7 +17,8 @@ import { spawnSync as realSpawnSync } from "node:child_process";
|
|
|
17
17
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
18
18
|
import path from "node:path";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
|
-
import { checkDockerEngineReachable, checkDockerPresent, classifyUpgrade, isIncomingComposeOlder } from "./preflight.mjs";
|
|
20
|
+
import { checkDockerEngineReachable, checkDockerPresent, classifyUpgrade, isComposeUpgrade, isIncomingComposeOlder, versionSkew } from "./preflight.mjs";
|
|
21
|
+
import { runningImageVersions } from "./docker.mjs";
|
|
21
22
|
import { resolveAssetPath } from "./assets.mjs";
|
|
22
23
|
import { canonicalAppDir } from "./paths.mjs";
|
|
23
24
|
|
|
@@ -111,9 +112,14 @@ export function stageParityFiles(appDir, env = process.env, platform = process.p
|
|
|
111
112
|
copyFileSync(resolveAssetPath(RELAY_FLY_CONFIG), path.join(appDir, RELAY_FLY_CONFIG));
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
// The live compose is staged
|
|
115
|
-
//
|
|
116
|
-
// never re-pin a running install out from
|
|
115
|
+
// The live compose is staged when absent; when PRESENT it is re-pinned here
|
|
116
|
+
// by the same QW-1 one-direction rule launch uses (T-178, ISS-MAC-7). The
|
|
117
|
+
// earlier rule ("provisioning must never re-pin a running install out from
|
|
118
|
+
// under it") answered a fear that a re-pinned file changes a running stack —
|
|
119
|
+
// it does not: nothing moves until the next `compose up`, which both
|
|
120
|
+
// launchers now run behind QW-3/QW-4 even on a running stack (ISS-V103-7).
|
|
121
|
+
// A refused downgrade never reaches here with a newer shipped file (the
|
|
122
|
+
// re-stage was skipped), and isComposeUpgrade refuses an older one anyway.
|
|
117
123
|
export function stageLiveComposeIfAbsent(appDir) {
|
|
118
124
|
const live = path.join(appDir, "docker-compose.yml");
|
|
119
125
|
if (existsSync(live)) return false;
|
|
@@ -121,6 +127,29 @@ export function stageLiveComposeIfAbsent(appDir) {
|
|
|
121
127
|
return true;
|
|
122
128
|
}
|
|
123
129
|
|
|
130
|
+
export function repinLiveCompose(appDir) {
|
|
131
|
+
const shipped = path.join(appDir, "culpa-compose.yml");
|
|
132
|
+
const live = path.join(appDir, "docker-compose.yml");
|
|
133
|
+
if (!existsSync(shipped) || !existsSync(live)) return false;
|
|
134
|
+
if (!isComposeUpgrade(readFileSync(shipped, "utf8"), readFileSync(live, "utf8"), (m) => console.warn(m))) return false;
|
|
135
|
+
copyFileSync(shipped, live);
|
|
136
|
+
console.log("getculpa: upgrade detected - live compose re-pinned from the shipped culpa-compose.yml (applies at next `getculpa`).");
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// T-178: what the stack is ACTUALLY running, recorded in install-state.json
|
|
141
|
+
// beside the staging facts — imagesStaged says what was pulled, not what runs.
|
|
142
|
+
function probeLiveStack({ appDir, dockerState, dockerSpawnSync }) {
|
|
143
|
+
if (dockerState !== "ready") return { probed: false, running: false, versions: {}, skew: null };
|
|
144
|
+
const versions = runningImageVersions(dockerSpawnSync);
|
|
145
|
+
const read = (name) => {
|
|
146
|
+
const p = path.join(appDir, name);
|
|
147
|
+
return existsSync(p) ? readFileSync(p, "utf8") : "";
|
|
148
|
+
};
|
|
149
|
+
const skew = versionSkew({ shippedText: read("culpa-compose.yml"), liveText: read("docker-compose.yml"), running: versions });
|
|
150
|
+
return { probed: true, running: Object.keys(versions).length > 0, versions, skew };
|
|
151
|
+
}
|
|
152
|
+
|
|
124
153
|
// T-CF29-8 — the name culpa-collector.ps1:35 reads from the app dir, and the
|
|
125
154
|
// same name culpa-setup.iss:52 installs there. NOT the Rust target triple
|
|
126
155
|
// lib/fetch.mjs uses for the release asset (x86_64-pc-windows-msvc): this is
|
|
@@ -260,6 +289,7 @@ export async function provision(opts) {
|
|
|
260
289
|
stageParityFiles(appDir, env, platform);
|
|
261
290
|
}
|
|
262
291
|
stageLiveComposeIfAbsent(appDir);
|
|
292
|
+
if (!refusedDowngrade) repinLiveCompose(appDir);
|
|
263
293
|
|
|
264
294
|
// T-CF29-8: only attempt it when the fetch reported success; the result is
|
|
265
295
|
// what gets recorded, not the intent.
|
|
@@ -282,6 +312,15 @@ export async function provision(opts) {
|
|
|
282
312
|
console.warn(`getculpa: ${why} - image staging deferred to first \`getculpa\`.`);
|
|
283
313
|
}
|
|
284
314
|
|
|
315
|
+
// T-178 (ISS-MAC-7): say plainly what is running and what the next launch
|
|
316
|
+
// will do — a reinstall over a running stack used to look finished.
|
|
317
|
+
const liveStack = probeLiveStack({ appDir, dockerState, dockerSpawnSync });
|
|
318
|
+
if (liveStack.running && liveStack.skew !== null) {
|
|
319
|
+
console.warn(
|
|
320
|
+
`getculpa: Culpa is running on ${liveStack.skew.from}; the next \`getculpa\` will pull ${liveStack.skew.to} and migrate (a database backup is taken first).`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
285
324
|
if (platform === "win32") {
|
|
286
325
|
// CF20-R: the Windows delegate registers the ONE fixed, per-machine HKCU
|
|
287
326
|
// uninstall key (install-culpa.ps1 / culpa-setup.iss's AppId). A second
|
|
@@ -317,6 +356,9 @@ export async function provision(opts) {
|
|
|
317
356
|
dockerState,
|
|
318
357
|
imagesStaged,
|
|
319
358
|
collectorStaged,
|
|
359
|
+
// T-178: the live docker state at provision time (what RUNS), distinct
|
|
360
|
+
// from imagesStaged (what was pulled)
|
|
361
|
+
liveStack,
|
|
320
362
|
platform,
|
|
321
363
|
});
|
|
322
364
|
|
|
@@ -325,5 +367,5 @@ export async function provision(opts) {
|
|
|
325
367
|
// (scripts/install.js) could not see them — which is how a Docker-less
|
|
326
368
|
// install still printed "Culpa installed successfully." Returning them
|
|
327
369
|
// changes no behavior here; it just stops postinstall from having to guess.
|
|
328
|
-
return { classification, previousVersion, dockerState, imagesStaged, collectorStaged };
|
|
370
|
+
return { classification, previousVersion, dockerState, imagesStaged, collectorStaged, liveStack };
|
|
329
371
|
}
|