@getmonoceros/workbench 1.11.5 → 1.11.6
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/bin.js +102 -73
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -3953,23 +3953,61 @@ var spawnDockerCompose = (args, cwd) => {
|
|
|
3953
3953
|
child.on("exit", (code) => resolve(code ?? 0));
|
|
3954
3954
|
});
|
|
3955
3955
|
};
|
|
3956
|
-
var
|
|
3956
|
+
var spawnDocker = (args) => {
|
|
3957
3957
|
return new Promise((resolve, reject) => {
|
|
3958
|
-
const child = spawn5("
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3958
|
+
const child = spawn5("docker", args, {
|
|
3959
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3960
|
+
});
|
|
3961
|
+
let stdout = "";
|
|
3962
|
+
let stderr = "";
|
|
3963
|
+
child.stdout?.on("data", (chunk) => {
|
|
3964
|
+
stdout += chunk.toString("utf8");
|
|
3965
|
+
});
|
|
3966
|
+
child.stderr?.on("data", (chunk) => {
|
|
3967
|
+
stderr += chunk.toString("utf8");
|
|
3966
3968
|
});
|
|
3967
|
-
child.stdout?.pipe(createSecretMaskStream()).pipe(process.stdout);
|
|
3968
3969
|
child.stderr?.pipe(createSecretMaskStream()).pipe(process.stderr);
|
|
3969
3970
|
child.on("error", reject);
|
|
3970
|
-
child.on(
|
|
3971
|
+
child.on(
|
|
3972
|
+
"exit",
|
|
3973
|
+
(code) => resolve({ exitCode: code ?? 0, stdout, stderr })
|
|
3974
|
+
);
|
|
3971
3975
|
});
|
|
3972
3976
|
};
|
|
3977
|
+
async function findContainerIds(filters, exec = spawnDocker) {
|
|
3978
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3979
|
+
for (const filter of filters) {
|
|
3980
|
+
const result = await exec(["ps", "-aq", "--filter", filter]);
|
|
3981
|
+
if (result.exitCode !== 0) continue;
|
|
3982
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
3983
|
+
const id = line.trim();
|
|
3984
|
+
if (id) ids.add(id);
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
return [...ids];
|
|
3988
|
+
}
|
|
3989
|
+
async function cleanupDockerObjects(opts) {
|
|
3990
|
+
const exec = opts.exec ?? spawnDocker;
|
|
3991
|
+
const tag = opts.logTag ?? "cleanup";
|
|
3992
|
+
opts.logger.info(`[${tag}] tearing down docker project ${opts.projectName}\u2026`);
|
|
3993
|
+
const ids = await findContainerIds(opts.filters, exec);
|
|
3994
|
+
let rmExit = 0;
|
|
3995
|
+
if (ids.length > 0) {
|
|
3996
|
+
opts.logger.info(`[${tag}] removing containers: ${ids.join(" ")}`);
|
|
3997
|
+
const rmResult = await exec(["rm", "-f", ...ids]);
|
|
3998
|
+
rmExit = rmResult.exitCode;
|
|
3999
|
+
} else {
|
|
4000
|
+
opts.logger.info(`[${tag}] no containers found`);
|
|
4001
|
+
}
|
|
4002
|
+
if (opts.network) {
|
|
4003
|
+
const netResult = await exec(["network", "rm", opts.network]);
|
|
4004
|
+
if (netResult.exitCode === 0) {
|
|
4005
|
+
opts.logger.info(`[${tag}] network ${opts.network} removed`);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
opts.logger.info(`[${tag}] docker cleanup done`);
|
|
4009
|
+
return { exitCode: rmExit, removedIds: ids };
|
|
4010
|
+
}
|
|
3973
4011
|
function dockerLocalFolderLabel(p) {
|
|
3974
4012
|
if (process.platform !== "win32") return p;
|
|
3975
4013
|
return p.replace(
|
|
@@ -4017,26 +4055,31 @@ async function runContainerCycle(root, opts) {
|
|
|
4017
4055
|
logger.info(
|
|
4018
4056
|
`Force-removing existing ${projectName} containers (volumes preserved)\u2026`
|
|
4019
4057
|
);
|
|
4020
|
-
const
|
|
4021
|
-
const
|
|
4022
|
-
`
|
|
4023
|
-
`
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4058
|
+
const exec = opts.dockerExec ?? spawnDocker;
|
|
4059
|
+
const filters = [
|
|
4060
|
+
`label=com.docker.compose.project=${projectName}`,
|
|
4061
|
+
`name=^${projectName}-`
|
|
4062
|
+
];
|
|
4063
|
+
const { exitCode: rmExit } = await cleanupDockerObjects({
|
|
4064
|
+
projectName,
|
|
4065
|
+
filters,
|
|
4066
|
+
network: `${projectName}_default`,
|
|
4067
|
+
logger,
|
|
4068
|
+
exec
|
|
4069
|
+
});
|
|
4070
|
+
if (rmExit !== 0) return rmExit;
|
|
4071
|
+
const remaining = await findContainerIds(filters, exec);
|
|
4072
|
+
if (remaining.length > 0) {
|
|
4073
|
+
const warn = logger.warn ?? logger.info;
|
|
4074
|
+
warn(
|
|
4075
|
+
`ERROR: containers under project ${projectName} reappeared after removal.
|
|
4076
|
+
This typically means VS Code's Remote Containers extension is connected
|
|
4077
|
+
to this devcontainer and auto-recreated it. Close the dev container
|
|
4078
|
+
session in VS Code (Cmd+Shift+P \u2192 'Dev Containers: Close Remote Connection')
|
|
4079
|
+
and retry \`monoceros apply\`.`
|
|
4080
|
+
);
|
|
4081
|
+
return 1;
|
|
4082
|
+
}
|
|
4040
4083
|
return runStart({
|
|
4041
4084
|
root,
|
|
4042
4085
|
...opts.devcontainerSpawn ? { spawn: opts.devcontainerSpawn } : {},
|
|
@@ -4609,7 +4652,7 @@ ${sectionLine(label)}
|
|
|
4609
4652
|
}
|
|
4610
4653
|
const exitCode = await runContainerCycle(targetDir, {
|
|
4611
4654
|
hasCompose: needsCompose(createOpts),
|
|
4612
|
-
...opts.
|
|
4655
|
+
...opts.dockerExec !== void 0 ? { dockerExec: opts.dockerExec } : {},
|
|
4613
4656
|
...opts.devcontainerSpawn !== void 0 ? { devcontainerSpawn: opts.devcontainerSpawn } : {},
|
|
4614
4657
|
logger
|
|
4615
4658
|
});
|
|
@@ -4713,7 +4756,7 @@ async function persistPromptedIdentity(prompted, ymlPath, home, logger) {
|
|
|
4713
4756
|
}
|
|
4714
4757
|
|
|
4715
4758
|
// src/version.ts
|
|
4716
|
-
var CLI_VERSION = true ? "1.11.
|
|
4759
|
+
var CLI_VERSION = true ? "1.11.6" : "dev";
|
|
4717
4760
|
|
|
4718
4761
|
// src/commands/_dispatch.ts
|
|
4719
4762
|
import { consola as consola12 } from "consola";
|
|
@@ -6170,39 +6213,20 @@ async function runRemove(opts) {
|
|
|
6170
6213
|
);
|
|
6171
6214
|
}
|
|
6172
6215
|
const projectName = composeProjectName(containerPath);
|
|
6173
|
-
const
|
|
6174
|
-
const
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
// `path.join`-built `C:\…`). Docker label filters are strict
|
|
6188
|
-
// byte-equality, so the case difference was leaving containers
|
|
6189
|
-
// alive on `monoceros remove`.
|
|
6190
|
-
`by_dc_label=$(docker ps -aq --filter "label=devcontainer.local_folder=${dockerLocalFolderLabel(containerPath)}" 2>/dev/null || true)`,
|
|
6191
|
-
// Container-name prefix fallback (catches half-broken state).
|
|
6192
|
-
`by_compose_name=$(docker ps -aq --filter "name=^${projectName}-" 2>/dev/null || true)`,
|
|
6193
|
-
// Image-mode devcontainer-cli name fallback (only kicks in when
|
|
6194
|
-
// the cli used a deterministic name — modern versions don't).
|
|
6195
|
-
`by_image_name=$(docker ps -aq --filter "name=^vsc-${opts.name}-" 2>/dev/null || true)`,
|
|
6196
|
-
`to_remove=$(printf "%s\\n%s\\n%s\\n%s\\n" "$by_label" "$by_dc_label" "$by_compose_name" "$by_image_name" | sort -u | grep -v "^$" || true)`,
|
|
6197
|
-
// Unquoted `$to_remove` so bash word-splitting joins the
|
|
6198
|
-
// newline-separated IDs with single spaces on echo. A `tr "\n" " "`
|
|
6199
|
-
// pipe here used to do the same job but tripped MSYS2's arg
|
|
6200
|
-
// translation on Git Bash for Windows ("tr: extra operand").
|
|
6201
|
-
`if [ -n "$to_remove" ]; then echo "[remove] removing containers:" $to_remove; docker rm -f $to_remove >/dev/null || true; else echo "[remove] no containers found"; fi`,
|
|
6202
|
-
`docker network rm ${projectName}_default 2>/dev/null && echo "[remove] network ${projectName}_default removed" || true`,
|
|
6203
|
-
`echo "[remove] docker cleanup done"`
|
|
6204
|
-
].join("; ");
|
|
6205
|
-
const dockerExitCode = await dockerSpawn(["-c", script], home);
|
|
6216
|
+
const dockerExec = opts.dockerExec ?? spawnDocker;
|
|
6217
|
+
const { exitCode: dockerExitCode } = await cleanupDockerObjects({
|
|
6218
|
+
projectName,
|
|
6219
|
+
filters: [
|
|
6220
|
+
`label=com.docker.compose.project=${projectName}`,
|
|
6221
|
+
`label=devcontainer.local_folder=${dockerLocalFolderLabel(containerPath)}`,
|
|
6222
|
+
`name=^${projectName}-`,
|
|
6223
|
+
`name=^vsc-${opts.name}-`
|
|
6224
|
+
],
|
|
6225
|
+
network: `${projectName}_default`,
|
|
6226
|
+
logTag: "remove",
|
|
6227
|
+
logger,
|
|
6228
|
+
exec: dockerExec
|
|
6229
|
+
});
|
|
6206
6230
|
let backupPath = null;
|
|
6207
6231
|
if (!opts.noBackup && (hasYml || hasContainer)) {
|
|
6208
6232
|
const ts = (opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -6232,13 +6256,18 @@ async function runRemove(opts) {
|
|
|
6232
6256
|
logger.info(
|
|
6233
6257
|
`[remove] host-side rm hit ${code} on ${prettyPath(containerPath)}; using a throw-away alpine container to clean root-owned files\u2026`
|
|
6234
6258
|
);
|
|
6235
|
-
const exit = await
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6259
|
+
const { exitCode: exit } = await dockerExec([
|
|
6260
|
+
"run",
|
|
6261
|
+
"--rm",
|
|
6262
|
+
"-v",
|
|
6263
|
+
`${containerPath}:/target`,
|
|
6264
|
+
"alpine:3.21",
|
|
6265
|
+
"find",
|
|
6266
|
+
"/target",
|
|
6267
|
+
"-mindepth",
|
|
6268
|
+
"1",
|
|
6269
|
+
"-delete"
|
|
6270
|
+
]);
|
|
6242
6271
|
if (exit !== 0) {
|
|
6243
6272
|
throw new Error(
|
|
6244
6273
|
`docker-based cleanup of ${containerPath} exited ${exit}. Inspect with \`sudo ls -la ${containerPath}\` and clean manually.`
|