@git.zone/tsdocker 1.14.0 → 1.15.1
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_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dockerfile.d.ts +12 -5
- package/dist_ts/classes.dockerfile.js +45 -48
- package/dist_ts/classes.registrycopy.d.ts +70 -0
- package/dist_ts/classes.registrycopy.js +359 -0
- package/dist_ts/classes.tsdockermanager.d.ts +2 -1
- package/dist_ts/classes.tsdockermanager.js +28 -18
- package/dist_ts/tsdocker.cli.js +144 -18
- package/dist_ts/tsdocker.plugins.d.ts +2 -1
- package/dist_ts/tsdocker.plugins.js +3 -2
- package/package.json +2 -1
- package/readme.hints.md +12 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dockerfile.ts +54 -56
- package/ts/classes.registrycopy.ts +511 -0
- package/ts/classes.tsdockermanager.ts +27 -18
- package/ts/tsdocker.cli.ts +190 -16
- package/ts/tsdocker.plugins.ts +2 -0
package/ts/tsdocker.cli.ts
CHANGED
|
@@ -7,6 +7,7 @@ import * as DockerModule from './tsdocker.docker.js';
|
|
|
7
7
|
|
|
8
8
|
import { logger, ora } from './tsdocker.logging.js';
|
|
9
9
|
import { TsDockerManager } from './classes.tsdockermanager.js';
|
|
10
|
+
import { DockerContext } from './classes.dockercontext.js';
|
|
10
11
|
import type { IBuildCommandOptions } from './interfaces/index.js';
|
|
11
12
|
import { commitinfo } from './00_commitinfo_data.js';
|
|
12
13
|
|
|
@@ -236,27 +237,200 @@ export let run = () => {
|
|
|
236
237
|
});
|
|
237
238
|
|
|
238
239
|
tsdockerCli.addCommand('clean').subscribe(async argvArg => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
|
|
240
|
+
try {
|
|
241
|
+
const autoYes = !!argvArg.y;
|
|
242
|
+
const includeAll = !!argvArg.all;
|
|
243
|
+
|
|
244
|
+
const smartshellInstance = new plugins.smartshell.Smartshell({ executor: 'bash' });
|
|
245
|
+
const interact = new plugins.smartinteract.SmartInteract();
|
|
246
|
+
|
|
247
|
+
// --- Docker context detection ---
|
|
248
|
+
ora.text('detecting docker context...');
|
|
249
|
+
const dockerContext = new DockerContext();
|
|
250
|
+
if (argvArg.context) {
|
|
251
|
+
dockerContext.setContext(argvArg.context as string);
|
|
252
|
+
}
|
|
253
|
+
await dockerContext.detect();
|
|
254
|
+
ora.stop();
|
|
255
|
+
dockerContext.logContextInfo();
|
|
246
256
|
|
|
247
|
-
|
|
248
|
-
|
|
257
|
+
// --- Helper: parse docker output into resource list ---
|
|
258
|
+
interface IDockerResource {
|
|
259
|
+
id: string;
|
|
260
|
+
display: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const listResources = async (command: string): Promise<IDockerResource[]> => {
|
|
264
|
+
const result = await smartshellInstance.execSilent(command);
|
|
265
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) {
|
|
266
|
+
return [];
|
|
267
|
+
}
|
|
268
|
+
return result.stdout.trim().split('\n').filter(Boolean).map((line) => {
|
|
269
|
+
const parts = line.split('\t');
|
|
270
|
+
return {
|
|
271
|
+
id: parts[0],
|
|
272
|
+
display: parts.join(' | '),
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
};
|
|
249
276
|
|
|
250
|
-
|
|
251
|
-
|
|
277
|
+
// --- Helper: checkbox selection ---
|
|
278
|
+
const selectResources = async (
|
|
279
|
+
name: string,
|
|
280
|
+
message: string,
|
|
281
|
+
resources: IDockerResource[],
|
|
282
|
+
): Promise<string[]> => {
|
|
283
|
+
if (autoYes) {
|
|
284
|
+
return resources.map((r) => r.id);
|
|
285
|
+
}
|
|
286
|
+
const answer = await interact.askQuestion({
|
|
287
|
+
name,
|
|
288
|
+
type: 'checkbox',
|
|
289
|
+
message,
|
|
290
|
+
default: [],
|
|
291
|
+
choices: resources.map((r) => ({ name: r.display, value: r.id })),
|
|
292
|
+
});
|
|
293
|
+
return answer.value as string[];
|
|
294
|
+
};
|
|
252
295
|
|
|
253
|
-
|
|
254
|
-
|
|
296
|
+
// --- Helper: confirm action ---
|
|
297
|
+
const confirmAction = async (
|
|
298
|
+
name: string,
|
|
299
|
+
message: string,
|
|
300
|
+
): Promise<boolean> => {
|
|
301
|
+
if (autoYes) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
const answer = await interact.askQuestion({
|
|
305
|
+
name,
|
|
306
|
+
type: 'confirm',
|
|
307
|
+
message,
|
|
308
|
+
default: false,
|
|
309
|
+
});
|
|
310
|
+
return answer.value as boolean;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// === RUNNING CONTAINERS ===
|
|
314
|
+
const runningContainers = await listResources(
|
|
315
|
+
`docker ps --format '{{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}'`
|
|
316
|
+
);
|
|
317
|
+
if (runningContainers.length > 0) {
|
|
318
|
+
logger.log('info', `Found ${runningContainers.length} running container(s)`);
|
|
319
|
+
const selectedIds = await selectResources(
|
|
320
|
+
'runningContainers',
|
|
321
|
+
'Select running containers to kill:',
|
|
322
|
+
runningContainers,
|
|
323
|
+
);
|
|
324
|
+
if (selectedIds.length > 0) {
|
|
325
|
+
logger.log('info', `Killing ${selectedIds.length} container(s)...`);
|
|
326
|
+
await smartshellInstance.exec(`docker kill ${selectedIds.join(' ')}`);
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
logger.log('info', 'No running containers found');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// === STOPPED CONTAINERS ===
|
|
333
|
+
const stoppedContainers = await listResources(
|
|
334
|
+
`docker ps -a --filter status=exited --filter status=created --format '{{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}'`
|
|
335
|
+
);
|
|
336
|
+
if (stoppedContainers.length > 0) {
|
|
337
|
+
logger.log('info', `Found ${stoppedContainers.length} stopped container(s)`);
|
|
338
|
+
const selectedIds = await selectResources(
|
|
339
|
+
'stoppedContainers',
|
|
340
|
+
'Select stopped containers to remove:',
|
|
341
|
+
stoppedContainers,
|
|
342
|
+
);
|
|
343
|
+
if (selectedIds.length > 0) {
|
|
344
|
+
logger.log('info', `Removing ${selectedIds.length} container(s)...`);
|
|
345
|
+
await smartshellInstance.exec(`docker rm ${selectedIds.join(' ')}`);
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
logger.log('info', 'No stopped containers found');
|
|
349
|
+
}
|
|
255
350
|
|
|
256
|
-
|
|
257
|
-
|
|
351
|
+
// === DANGLING IMAGES ===
|
|
352
|
+
const danglingImages = await listResources(
|
|
353
|
+
`docker images -f dangling=true --format '{{.ID}}\t{{.Repository}}:{{.Tag}}\t{{.Size}}'`
|
|
354
|
+
);
|
|
355
|
+
if (danglingImages.length > 0) {
|
|
356
|
+
const confirmed = await confirmAction(
|
|
357
|
+
'removeDanglingImages',
|
|
358
|
+
`Remove ${danglingImages.length} dangling image(s)?`,
|
|
359
|
+
);
|
|
360
|
+
if (confirmed) {
|
|
361
|
+
logger.log('info', `Removing ${danglingImages.length} dangling image(s)...`);
|
|
362
|
+
const ids = danglingImages.map((r) => r.id).join(' ');
|
|
363
|
+
await smartshellInstance.exec(`docker rmi ${ids}`);
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
logger.log('info', 'No dangling images found');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// === ALL IMAGES (only with --all) ===
|
|
370
|
+
if (includeAll) {
|
|
371
|
+
const allImages = await listResources(
|
|
372
|
+
`docker images --format '{{.ID}}\t{{.Repository}}:{{.Tag}}\t{{.Size}}'`
|
|
373
|
+
);
|
|
374
|
+
if (allImages.length > 0) {
|
|
375
|
+
logger.log('info', `Found ${allImages.length} image(s) total`);
|
|
376
|
+
const selectedIds = await selectResources(
|
|
377
|
+
'allImages',
|
|
378
|
+
'Select images to remove:',
|
|
379
|
+
allImages,
|
|
380
|
+
);
|
|
381
|
+
if (selectedIds.length > 0) {
|
|
382
|
+
logger.log('info', `Removing ${selectedIds.length} image(s)...`);
|
|
383
|
+
await smartshellInstance.exec(`docker rmi -f ${selectedIds.join(' ')}`);
|
|
384
|
+
}
|
|
385
|
+
} else {
|
|
386
|
+
logger.log('info', 'No images found');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// === DANGLING VOLUMES ===
|
|
391
|
+
const danglingVolumes = await listResources(
|
|
392
|
+
`docker volume ls -f dangling=true --format '{{.Name}}\t{{.Driver}}'`
|
|
393
|
+
);
|
|
394
|
+
if (danglingVolumes.length > 0) {
|
|
395
|
+
const confirmed = await confirmAction(
|
|
396
|
+
'removeDanglingVolumes',
|
|
397
|
+
`Remove ${danglingVolumes.length} dangling volume(s)?`,
|
|
398
|
+
);
|
|
399
|
+
if (confirmed) {
|
|
400
|
+
logger.log('info', `Removing ${danglingVolumes.length} dangling volume(s)...`);
|
|
401
|
+
const names = danglingVolumes.map((r) => r.id).join(' ');
|
|
402
|
+
await smartshellInstance.exec(`docker volume rm ${names}`);
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
logger.log('info', 'No dangling volumes found');
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// === ALL VOLUMES (only with --all) ===
|
|
409
|
+
if (includeAll) {
|
|
410
|
+
const allVolumes = await listResources(
|
|
411
|
+
`docker volume ls --format '{{.Name}}\t{{.Driver}}'`
|
|
412
|
+
);
|
|
413
|
+
if (allVolumes.length > 0) {
|
|
414
|
+
logger.log('info', `Found ${allVolumes.length} volume(s) total`);
|
|
415
|
+
const selectedIds = await selectResources(
|
|
416
|
+
'allVolumes',
|
|
417
|
+
'Select volumes to remove:',
|
|
418
|
+
allVolumes,
|
|
419
|
+
);
|
|
420
|
+
if (selectedIds.length > 0) {
|
|
421
|
+
logger.log('info', `Removing ${selectedIds.length} volume(s)...`);
|
|
422
|
+
await smartshellInstance.exec(`docker volume rm ${selectedIds.join(' ')}`);
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
logger.log('info', 'No volumes found');
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
logger.log('success', 'Docker cleanup completed!');
|
|
430
|
+
} catch (err) {
|
|
431
|
+
logger.log('error', `Clean failed: ${(err as Error).message}`);
|
|
432
|
+
process.exit(1);
|
|
258
433
|
}
|
|
259
|
-
ora.finishSuccess('docker environment now is clean!');
|
|
260
434
|
});
|
|
261
435
|
|
|
262
436
|
tsdockerCli.addCommand('vscode').subscribe(async argvArg => {
|
package/ts/tsdocker.plugins.ts
CHANGED
|
@@ -11,6 +11,7 @@ import * as smartlog from '@push.rocks/smartlog';
|
|
|
11
11
|
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
|
|
12
12
|
import * as smartlogSouceOra from '@push.rocks/smartlog-source-ora';
|
|
13
13
|
import * as smartopen from '@push.rocks/smartopen';
|
|
14
|
+
import * as smartinteract from '@push.rocks/smartinteract';
|
|
14
15
|
import * as smartshell from '@push.rocks/smartshell';
|
|
15
16
|
import * as smartstring from '@push.rocks/smartstring';
|
|
16
17
|
|
|
@@ -25,6 +26,7 @@ export {
|
|
|
25
26
|
smartpromise,
|
|
26
27
|
qenv,
|
|
27
28
|
smartcli,
|
|
29
|
+
smartinteract,
|
|
28
30
|
smartlog,
|
|
29
31
|
smartlogDestinationLocal,
|
|
30
32
|
smartlogSouceOra,
|