@getmonoceros/workbench 1.11.5 → 1.11.7
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 +105 -74
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -3953,23 +3953,63 @@ 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
|
-
child.stderr?.pipe(createSecretMaskStream()).pipe(process.stderr);
|
|
3969
3969
|
child.on("error", reject);
|
|
3970
|
-
child.on(
|
|
3970
|
+
child.on(
|
|
3971
|
+
"exit",
|
|
3972
|
+
(code) => resolve({ exitCode: code ?? 0, stdout, stderr })
|
|
3973
|
+
);
|
|
3971
3974
|
});
|
|
3972
3975
|
};
|
|
3976
|
+
async function findContainerIds(filters, exec = spawnDocker) {
|
|
3977
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3978
|
+
for (const filter of filters) {
|
|
3979
|
+
const result = await exec(["ps", "-aq", "--filter", filter]);
|
|
3980
|
+
if (result.exitCode !== 0) continue;
|
|
3981
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
3982
|
+
const id = line.trim();
|
|
3983
|
+
if (id) ids.add(id);
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
return [...ids];
|
|
3987
|
+
}
|
|
3988
|
+
async function cleanupDockerObjects(opts) {
|
|
3989
|
+
const exec = opts.exec ?? spawnDocker;
|
|
3990
|
+
const tag = opts.logTag ?? "cleanup";
|
|
3991
|
+
opts.logger.info(`[${tag}] tearing down docker project ${opts.projectName}\u2026`);
|
|
3992
|
+
const ids = await findContainerIds(opts.filters, exec);
|
|
3993
|
+
let rmExit = 0;
|
|
3994
|
+
if (ids.length > 0) {
|
|
3995
|
+
opts.logger.info(`[${tag}] removing containers: ${ids.join(" ")}`);
|
|
3996
|
+
const rmResult = await exec(["rm", "-f", ...ids]);
|
|
3997
|
+
rmExit = rmResult.exitCode;
|
|
3998
|
+
if (rmExit !== 0 && rmResult.stderr.trim()) {
|
|
3999
|
+
opts.logger.info(`[${tag}] ${rmResult.stderr.trim()}`);
|
|
4000
|
+
}
|
|
4001
|
+
} else {
|
|
4002
|
+
opts.logger.info(`[${tag}] no containers found`);
|
|
4003
|
+
}
|
|
4004
|
+
if (opts.network) {
|
|
4005
|
+
const netResult = await exec(["network", "rm", opts.network]);
|
|
4006
|
+
if (netResult.exitCode === 0) {
|
|
4007
|
+
opts.logger.info(`[${tag}] network ${opts.network} removed`);
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
opts.logger.info(`[${tag}] docker cleanup done`);
|
|
4011
|
+
return { exitCode: rmExit, removedIds: ids };
|
|
4012
|
+
}
|
|
3973
4013
|
function dockerLocalFolderLabel(p) {
|
|
3974
4014
|
if (process.platform !== "win32") return p;
|
|
3975
4015
|
return p.replace(
|
|
@@ -4017,26 +4057,31 @@ async function runContainerCycle(root, opts) {
|
|
|
4017
4057
|
logger.info(
|
|
4018
4058
|
`Force-removing existing ${projectName} containers (volumes preserved)\u2026`
|
|
4019
4059
|
);
|
|
4020
|
-
const
|
|
4021
|
-
const
|
|
4022
|
-
`
|
|
4023
|
-
`
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4060
|
+
const exec = opts.dockerExec ?? spawnDocker;
|
|
4061
|
+
const filters = [
|
|
4062
|
+
`label=com.docker.compose.project=${projectName}`,
|
|
4063
|
+
`name=^${projectName}-`
|
|
4064
|
+
];
|
|
4065
|
+
const { exitCode: rmExit } = await cleanupDockerObjects({
|
|
4066
|
+
projectName,
|
|
4067
|
+
filters,
|
|
4068
|
+
network: `${projectName}_default`,
|
|
4069
|
+
logger,
|
|
4070
|
+
exec
|
|
4071
|
+
});
|
|
4072
|
+
if (rmExit !== 0) return rmExit;
|
|
4073
|
+
const remaining = await findContainerIds(filters, exec);
|
|
4074
|
+
if (remaining.length > 0) {
|
|
4075
|
+
const warn = logger.warn ?? logger.info;
|
|
4076
|
+
warn(
|
|
4077
|
+
`ERROR: containers under project ${projectName} reappeared after removal.
|
|
4078
|
+
This typically means VS Code's Remote Containers extension is connected
|
|
4079
|
+
to this devcontainer and auto-recreated it. Close the dev container
|
|
4080
|
+
session in VS Code (Cmd+Shift+P \u2192 'Dev Containers: Close Remote Connection')
|
|
4081
|
+
and retry \`monoceros apply\`.`
|
|
4082
|
+
);
|
|
4083
|
+
return 1;
|
|
4084
|
+
}
|
|
4040
4085
|
return runStart({
|
|
4041
4086
|
root,
|
|
4042
4087
|
...opts.devcontainerSpawn ? { spawn: opts.devcontainerSpawn } : {},
|
|
@@ -4609,7 +4654,7 @@ ${sectionLine(label)}
|
|
|
4609
4654
|
}
|
|
4610
4655
|
const exitCode = await runContainerCycle(targetDir, {
|
|
4611
4656
|
hasCompose: needsCompose(createOpts),
|
|
4612
|
-
...opts.
|
|
4657
|
+
...opts.dockerExec !== void 0 ? { dockerExec: opts.dockerExec } : {},
|
|
4613
4658
|
...opts.devcontainerSpawn !== void 0 ? { devcontainerSpawn: opts.devcontainerSpawn } : {},
|
|
4614
4659
|
logger
|
|
4615
4660
|
});
|
|
@@ -4713,7 +4758,7 @@ async function persistPromptedIdentity(prompted, ymlPath, home, logger) {
|
|
|
4713
4758
|
}
|
|
4714
4759
|
|
|
4715
4760
|
// src/version.ts
|
|
4716
|
-
var CLI_VERSION = true ? "1.11.
|
|
4761
|
+
var CLI_VERSION = true ? "1.11.7" : "dev";
|
|
4717
4762
|
|
|
4718
4763
|
// src/commands/_dispatch.ts
|
|
4719
4764
|
import { consola as consola12 } from "consola";
|
|
@@ -6170,39 +6215,20 @@ async function runRemove(opts) {
|
|
|
6170
6215
|
);
|
|
6171
6216
|
}
|
|
6172
6217
|
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);
|
|
6218
|
+
const dockerExec = opts.dockerExec ?? spawnDocker;
|
|
6219
|
+
const { exitCode: dockerExitCode } = await cleanupDockerObjects({
|
|
6220
|
+
projectName,
|
|
6221
|
+
filters: [
|
|
6222
|
+
`label=com.docker.compose.project=${projectName}`,
|
|
6223
|
+
`label=devcontainer.local_folder=${dockerLocalFolderLabel(containerPath)}`,
|
|
6224
|
+
`name=^${projectName}-`,
|
|
6225
|
+
`name=^vsc-${opts.name}-`
|
|
6226
|
+
],
|
|
6227
|
+
network: `${projectName}_default`,
|
|
6228
|
+
logTag: "remove",
|
|
6229
|
+
logger,
|
|
6230
|
+
exec: dockerExec
|
|
6231
|
+
});
|
|
6206
6232
|
let backupPath = null;
|
|
6207
6233
|
if (!opts.noBackup && (hasYml || hasContainer)) {
|
|
6208
6234
|
const ts = (opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -6232,13 +6258,18 @@ async function runRemove(opts) {
|
|
|
6232
6258
|
logger.info(
|
|
6233
6259
|
`[remove] host-side rm hit ${code} on ${prettyPath(containerPath)}; using a throw-away alpine container to clean root-owned files\u2026`
|
|
6234
6260
|
);
|
|
6235
|
-
const exit = await
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6261
|
+
const { exitCode: exit } = await dockerExec([
|
|
6262
|
+
"run",
|
|
6263
|
+
"--rm",
|
|
6264
|
+
"-v",
|
|
6265
|
+
`${containerPath}:/target`,
|
|
6266
|
+
"alpine:3.21",
|
|
6267
|
+
"find",
|
|
6268
|
+
"/target",
|
|
6269
|
+
"-mindepth",
|
|
6270
|
+
"1",
|
|
6271
|
+
"-delete"
|
|
6272
|
+
]);
|
|
6242
6273
|
if (exit !== 0) {
|
|
6243
6274
|
throw new Error(
|
|
6244
6275
|
`docker-based cleanup of ${containerPath} exited ${exit}. Inspect with \`sudo ls -la ${containerPath}\` and clean manually.`
|