801 lines
21 KiB
TypeScript
801 lines
21 KiB
TypeScript
import * as plugins from "./mod.plugins.js";
|
|
import * as helpers from "./helpers.js";
|
|
import { ServiceManager } from "./classes.servicemanager.js";
|
|
import { GlobalRegistry } from "./classes.globalregistry.js";
|
|
import { logger } from "../gitzone.logging.js";
|
|
import type { ICliMode } from "../helpers.climode.js";
|
|
import { getCliMode, printJson } from "../helpers.climode.js";
|
|
import {
|
|
getCliConfigValueFromData,
|
|
readSmartconfigFile,
|
|
setCliConfigValueInData,
|
|
writeSmartconfigFile,
|
|
} from "../helpers.smartconfig.js";
|
|
|
|
export const run = async (argvArg: any) => {
|
|
const mode = await getCliMode(argvArg);
|
|
const isGlobal = argvArg.g || argvArg.global;
|
|
const command = argvArg._[1] || "help";
|
|
|
|
if (mode.help || command === "help") {
|
|
showHelp(mode);
|
|
return;
|
|
}
|
|
|
|
// Handle global commands first
|
|
if (isGlobal) {
|
|
await handleGlobalCommand(command);
|
|
return;
|
|
}
|
|
|
|
const service = argvArg._[2] || "all";
|
|
|
|
switch (command) {
|
|
case "config":
|
|
if (service === "services" || argvArg._[2] === "services") {
|
|
const serviceManager = new ServiceManager();
|
|
await serviceManager.init();
|
|
await handleConfigureServices(serviceManager);
|
|
} else {
|
|
await handleShowConfig(mode);
|
|
}
|
|
break;
|
|
|
|
case "set":
|
|
await handleSetServices(argvArg._[2], mode);
|
|
break;
|
|
|
|
case "enable":
|
|
await handleEnableServices(argvArg._.slice(2), mode);
|
|
break;
|
|
|
|
case "disable":
|
|
await handleDisableServices(argvArg._.slice(2), mode);
|
|
break;
|
|
|
|
case "start":
|
|
case "stop":
|
|
case "restart":
|
|
case "status":
|
|
case "compass":
|
|
case "logs":
|
|
case "remove":
|
|
case "clean":
|
|
case "reconfigure": {
|
|
const serviceManager = new ServiceManager();
|
|
await serviceManager.init();
|
|
|
|
switch (command) {
|
|
case "start":
|
|
await handleStart(serviceManager, service);
|
|
break;
|
|
|
|
case "stop":
|
|
await handleStop(serviceManager, service);
|
|
break;
|
|
|
|
case "restart":
|
|
await handleRestart(serviceManager, service);
|
|
break;
|
|
|
|
case "status":
|
|
await serviceManager.showStatus();
|
|
break;
|
|
|
|
case "compass":
|
|
await serviceManager.showCompassConnection();
|
|
break;
|
|
|
|
case "logs": {
|
|
const lines = parseInt(argvArg._[3]) || 20;
|
|
await serviceManager.showLogs(service, lines);
|
|
break;
|
|
}
|
|
|
|
case "remove":
|
|
await handleRemove(serviceManager);
|
|
break;
|
|
|
|
case "clean":
|
|
await handleClean(serviceManager);
|
|
break;
|
|
|
|
case "reconfigure":
|
|
await serviceManager.reconfigure();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
showHelp(mode);
|
|
break;
|
|
}
|
|
};
|
|
|
|
const allowedServices = ["mongodb", "minio", "elasticsearch"];
|
|
|
|
const normalizeServiceName = (service: string): string => {
|
|
switch (service) {
|
|
case "mongo":
|
|
case "mongodb":
|
|
return "mongodb";
|
|
case "minio":
|
|
case "s3":
|
|
return "minio";
|
|
case "elastic":
|
|
case "elasticsearch":
|
|
case "es":
|
|
return "elasticsearch";
|
|
default:
|
|
return service;
|
|
}
|
|
};
|
|
|
|
async function readServicesConfig(): Promise<{
|
|
enabledServices: string[];
|
|
environment: Record<string, any> | null;
|
|
}> {
|
|
const smartconfigData = await readSmartconfigFile();
|
|
const enabledServices = getCliConfigValueFromData(
|
|
smartconfigData,
|
|
"services",
|
|
);
|
|
let environment: Record<string, any> | null = null;
|
|
const envPath = plugins.path.join(process.cwd(), ".nogit", "env.json");
|
|
if (await plugins.smartfs.file(envPath).exists()) {
|
|
const envContent = (await plugins.smartfs
|
|
.file(envPath)
|
|
.encoding("utf8")
|
|
.read()) as string;
|
|
environment = JSON.parse(envContent);
|
|
}
|
|
|
|
return {
|
|
enabledServices: Array.isArray(enabledServices) ? enabledServices : [],
|
|
environment,
|
|
};
|
|
}
|
|
|
|
async function updateEnabledServices(services: string[]): Promise<void> {
|
|
const smartconfigData = await readSmartconfigFile();
|
|
setCliConfigValueInData(smartconfigData, "services", services);
|
|
await writeSmartconfigFile(smartconfigData);
|
|
}
|
|
|
|
async function handleShowConfig(mode: ICliMode) {
|
|
const configData = await readServicesConfig();
|
|
|
|
if (mode.json) {
|
|
printJson(configData);
|
|
return;
|
|
}
|
|
|
|
helpers.printHeader("Current Services Configuration");
|
|
logger.log(
|
|
"info",
|
|
`Enabled Services: ${configData.enabledServices.length > 0 ? configData.enabledServices.join(", ") : "none configured"}`,
|
|
);
|
|
console.log();
|
|
|
|
if (!configData.environment) {
|
|
logger.log(
|
|
"note",
|
|
"No .nogit/env.json found yet. Start a service once to create runtime defaults.",
|
|
);
|
|
return;
|
|
}
|
|
|
|
const env = configData.environment;
|
|
logger.log("note", "MongoDB:");
|
|
logger.log("info", ` Host: ${env.MONGODB_HOST}:${env.MONGODB_PORT}`);
|
|
logger.log("info", ` Database: ${env.MONGODB_NAME}`);
|
|
logger.log("info", ` User: ${env.MONGODB_USER}`);
|
|
logger.log("info", ` Container: ${env.PROJECT_NAME}-mongodb`);
|
|
logger.log(
|
|
"info",
|
|
` Data: ${plugins.path.join(process.cwd(), ".nogit", "mongodata")}`,
|
|
);
|
|
logger.log("info", ` Connection: ${env.MONGODB_URL}`);
|
|
console.log();
|
|
|
|
logger.log("note", "S3/MinIO:");
|
|
logger.log("info", ` Host: ${env.S3_HOST}`);
|
|
logger.log("info", ` API Port: ${env.S3_PORT}`);
|
|
logger.log("info", ` Console Port: ${env.S3_CONSOLE_PORT}`);
|
|
logger.log("info", ` Bucket: ${env.S3_BUCKET}`);
|
|
logger.log("info", ` Container: ${env.PROJECT_NAME}-minio`);
|
|
logger.log(
|
|
"info",
|
|
` Data: ${plugins.path.join(process.cwd(), ".nogit", "miniodata")}`,
|
|
);
|
|
logger.log("info", ` Endpoint: ${env.S3_ENDPOINT}`);
|
|
console.log();
|
|
|
|
logger.log("note", "Elasticsearch:");
|
|
logger.log(
|
|
"info",
|
|
` Host: ${env.ELASTICSEARCH_HOST}:${env.ELASTICSEARCH_PORT}`,
|
|
);
|
|
logger.log("info", ` User: ${env.ELASTICSEARCH_USER}`);
|
|
logger.log("info", ` Container: ${env.PROJECT_NAME}-elasticsearch`);
|
|
logger.log(
|
|
"info",
|
|
` Data: ${plugins.path.join(process.cwd(), ".nogit", "esdata")}`,
|
|
);
|
|
logger.log("info", ` Connection: ${env.ELASTICSEARCH_URL}`);
|
|
}
|
|
|
|
async function handleSetServices(rawValue: string | undefined, mode: ICliMode) {
|
|
if (!rawValue) {
|
|
throw new Error("Specify a comma-separated list of services");
|
|
}
|
|
|
|
const requestedServices = rawValue
|
|
.split(",")
|
|
.map((service) => normalizeServiceName(service.trim()))
|
|
.filter(Boolean);
|
|
validateRequestedServices(requestedServices);
|
|
await updateEnabledServices(requestedServices);
|
|
|
|
if (mode.json) {
|
|
printJson({ ok: true, action: "set", enabledServices: requestedServices });
|
|
return;
|
|
}
|
|
|
|
logger.log("ok", `Enabled services set to: ${requestedServices.join(", ")}`);
|
|
}
|
|
|
|
async function handleEnableServices(
|
|
requestedServices: string[],
|
|
mode: ICliMode,
|
|
) {
|
|
const normalizedServices = requestedServices.map((service) =>
|
|
normalizeServiceName(service),
|
|
);
|
|
validateRequestedServices(normalizedServices);
|
|
|
|
const configData = await readServicesConfig();
|
|
const nextServices = Array.from(
|
|
new Set([...configData.enabledServices, ...normalizedServices]),
|
|
);
|
|
await updateEnabledServices(nextServices);
|
|
|
|
if (mode.json) {
|
|
printJson({ ok: true, action: "enable", enabledServices: nextServices });
|
|
return;
|
|
}
|
|
|
|
logger.log("ok", `Enabled services: ${nextServices.join(", ")}`);
|
|
}
|
|
|
|
async function handleDisableServices(
|
|
requestedServices: string[],
|
|
mode: ICliMode,
|
|
) {
|
|
const normalizedServices = requestedServices.map((service) =>
|
|
normalizeServiceName(service),
|
|
);
|
|
validateRequestedServices(normalizedServices);
|
|
|
|
const configData = await readServicesConfig();
|
|
const nextServices = configData.enabledServices.filter(
|
|
(service) => !normalizedServices.includes(service),
|
|
);
|
|
await updateEnabledServices(nextServices);
|
|
|
|
if (mode.json) {
|
|
printJson({ ok: true, action: "disable", enabledServices: nextServices });
|
|
return;
|
|
}
|
|
|
|
logger.log("ok", `Enabled services: ${nextServices.join(", ")}`);
|
|
}
|
|
|
|
function validateRequestedServices(services: string[]): void {
|
|
if (services.length === 0) {
|
|
throw new Error("Specify at least one service");
|
|
}
|
|
|
|
const invalidServices = services.filter(
|
|
(service) => !allowedServices.includes(service),
|
|
);
|
|
if (invalidServices.length > 0) {
|
|
throw new Error(`Unknown service(s): ${invalidServices.join(", ")}`);
|
|
}
|
|
}
|
|
|
|
async function handleStart(serviceManager: ServiceManager, service: string) {
|
|
helpers.printHeader("Starting Services");
|
|
|
|
switch (service) {
|
|
case "mongo":
|
|
case "mongodb":
|
|
await serviceManager.startMongoDB();
|
|
break;
|
|
|
|
case "minio":
|
|
case "s3":
|
|
await serviceManager.startMinIO();
|
|
break;
|
|
|
|
case "elasticsearch":
|
|
case "es":
|
|
await serviceManager.startElasticsearch();
|
|
break;
|
|
|
|
case "all":
|
|
case "":
|
|
await serviceManager.startAll();
|
|
break;
|
|
|
|
default:
|
|
logger.log("error", `Unknown service: ${service}`);
|
|
logger.log("note", "Use: mongo, s3, elasticsearch, or all");
|
|
break;
|
|
}
|
|
}
|
|
|
|
async function handleStop(serviceManager: ServiceManager, service: string) {
|
|
helpers.printHeader("Stopping Services");
|
|
|
|
switch (service) {
|
|
case "mongo":
|
|
case "mongodb":
|
|
await serviceManager.stopMongoDB();
|
|
break;
|
|
|
|
case "minio":
|
|
case "s3":
|
|
await serviceManager.stopMinIO();
|
|
break;
|
|
|
|
case "elasticsearch":
|
|
case "es":
|
|
await serviceManager.stopElasticsearch();
|
|
break;
|
|
|
|
case "all":
|
|
case "":
|
|
await serviceManager.stopAll();
|
|
break;
|
|
|
|
default:
|
|
logger.log("error", `Unknown service: ${service}`);
|
|
logger.log("note", "Use: mongo, s3, elasticsearch, or all");
|
|
break;
|
|
}
|
|
}
|
|
|
|
async function handleRestart(serviceManager: ServiceManager, service: string) {
|
|
helpers.printHeader("Restarting Services");
|
|
|
|
switch (service) {
|
|
case "mongo":
|
|
case "mongodb":
|
|
await serviceManager.stopMongoDB();
|
|
await plugins.smartdelay.delayFor(2000);
|
|
await serviceManager.startMongoDB();
|
|
break;
|
|
|
|
case "minio":
|
|
case "s3":
|
|
await serviceManager.stopMinIO();
|
|
await plugins.smartdelay.delayFor(2000);
|
|
await serviceManager.startMinIO();
|
|
break;
|
|
|
|
case "elasticsearch":
|
|
case "es":
|
|
await serviceManager.stopElasticsearch();
|
|
await plugins.smartdelay.delayFor(2000);
|
|
await serviceManager.startElasticsearch();
|
|
break;
|
|
|
|
case "all":
|
|
case "":
|
|
await serviceManager.stopAll();
|
|
await plugins.smartdelay.delayFor(2000);
|
|
await serviceManager.startAll();
|
|
break;
|
|
|
|
default:
|
|
logger.log("error", `Unknown service: ${service}`);
|
|
break;
|
|
}
|
|
}
|
|
|
|
async function handleRemove(serviceManager: ServiceManager) {
|
|
helpers.printHeader("Removing Containers");
|
|
logger.log("note", "⚠️ This will remove containers but preserve data");
|
|
|
|
const shouldContinue =
|
|
await plugins.smartinteract.SmartInteract.getCliConfirmation(
|
|
"Continue?",
|
|
false,
|
|
);
|
|
|
|
if (shouldContinue) {
|
|
await serviceManager.removeContainers();
|
|
} else {
|
|
logger.log("note", "Cancelled");
|
|
}
|
|
}
|
|
|
|
async function handleClean(serviceManager: ServiceManager) {
|
|
helpers.printHeader("Clean All");
|
|
logger.log("error", "⚠️ WARNING: This will remove all containers and data!");
|
|
logger.log("error", "This action cannot be undone!");
|
|
|
|
const smartinteraction = new plugins.smartinteract.SmartInteract();
|
|
const confirmAnswer = await smartinteraction.askQuestion({
|
|
name: "confirm",
|
|
type: "input",
|
|
message: 'Type "yes" to confirm:',
|
|
default: "no",
|
|
});
|
|
|
|
if (confirmAnswer.value === "yes") {
|
|
await serviceManager.removeContainers();
|
|
console.log();
|
|
await serviceManager.cleanData();
|
|
logger.log("ok", "All cleaned ✓");
|
|
} else {
|
|
logger.log("note", "Cancelled");
|
|
}
|
|
}
|
|
|
|
async function handleConfigureServices(serviceManager: ServiceManager) {
|
|
helpers.printHeader("Configure Services");
|
|
await serviceManager.configureServices();
|
|
}
|
|
|
|
export function showHelp(mode?: ICliMode) {
|
|
if (mode?.json) {
|
|
printJson({
|
|
command: "services",
|
|
usage: "gitzone services <command> [options]",
|
|
commands: [
|
|
{
|
|
name: "config",
|
|
description:
|
|
"Show configured services and any existing runtime env.json data",
|
|
},
|
|
{
|
|
name: "set <csv>",
|
|
description: "Set the enabled service list without prompts",
|
|
},
|
|
{
|
|
name: "enable <service...>",
|
|
description: "Enable one or more services without prompts",
|
|
},
|
|
{
|
|
name: "disable <service...>",
|
|
description: "Disable one or more services without prompts",
|
|
},
|
|
{ name: "start [service]", description: "Start services" },
|
|
{ name: "stop [service]", description: "Stop services" },
|
|
{ name: "status", description: "Show service status" },
|
|
],
|
|
examples: [
|
|
"gitzone services config --json",
|
|
"gitzone services set mongodb,minio",
|
|
"gitzone services enable elasticsearch",
|
|
],
|
|
});
|
|
return;
|
|
}
|
|
|
|
helpers.printHeader("GitZone Services Manager");
|
|
|
|
logger.log("ok", "Usage: gitzone services [command] [options]");
|
|
console.log();
|
|
|
|
logger.log("note", "Commands:");
|
|
logger.log(
|
|
"info",
|
|
" start [service] Start services (mongo|s3|elasticsearch|all)",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" stop [service] Stop services (mongo|s3|elasticsearch|all)",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" restart [service] Restart services (mongo|s3|elasticsearch|all)",
|
|
);
|
|
logger.log("info", " status Show service status");
|
|
logger.log("info", " config Show current configuration");
|
|
logger.log(
|
|
"info",
|
|
" config services Configure which services are enabled",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" set <csv> Set enabled services without prompts",
|
|
);
|
|
logger.log("info", " enable <svc...> Enable one or more services");
|
|
logger.log("info", " disable <svc...> Disable one or more services");
|
|
logger.log(
|
|
"info",
|
|
" compass Show MongoDB Compass connection string",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" logs [service] Show logs (mongo|s3|elasticsearch|all) [lines]",
|
|
);
|
|
logger.log("info", " reconfigure Reassign ports and restart services");
|
|
logger.log("info", " remove Remove all containers");
|
|
logger.log("info", " clean Remove all containers and data ⚠️");
|
|
logger.log("info", " help Show this help message");
|
|
console.log();
|
|
|
|
logger.log("note", "Available Services:");
|
|
logger.log("info", " • MongoDB (mongo) - Document database");
|
|
logger.log("info", " • MinIO (s3) - S3-compatible object storage");
|
|
logger.log(
|
|
"info",
|
|
" • Elasticsearch (elasticsearch) - Search and analytics engine",
|
|
);
|
|
console.log();
|
|
|
|
logger.log("note", "Features:");
|
|
logger.log("info", " • Auto-creates .nogit/env.json with smart defaults");
|
|
logger.log(
|
|
"info",
|
|
" • Random ports (20000-30000) for MongoDB/MinIO to avoid conflicts",
|
|
);
|
|
logger.log("info", " • Elasticsearch uses standard port 9200");
|
|
logger.log(
|
|
"info",
|
|
" • Project-specific containers for multi-project support",
|
|
);
|
|
logger.log("info", " • Preserves custom configuration values");
|
|
logger.log("info", " • MongoDB Compass connection support");
|
|
console.log();
|
|
|
|
logger.log("note", "Examples:");
|
|
logger.log(
|
|
"info",
|
|
" gitzone services start # Start all services",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services start mongo # Start only MongoDB",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services start elasticsearch # Start only Elasticsearch",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services stop # Stop all services",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services status # Check service status",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services config # Show configuration",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services config --json # Show configuration as JSON",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services set mongodb,minio # Configure services without prompts",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services compass # Get MongoDB Compass connection",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services logs elasticsearch # Show Elasticsearch logs",
|
|
);
|
|
console.log();
|
|
|
|
logger.log("note", "Global Commands (-g/--global):");
|
|
logger.log("info", " list -g List all registered projects");
|
|
logger.log("info", " status -g Show status across all projects");
|
|
logger.log(
|
|
"info",
|
|
" stop -g Stop all containers across all projects",
|
|
);
|
|
logger.log("info", " cleanup -g Remove stale registry entries");
|
|
console.log();
|
|
|
|
logger.log("note", "Global Examples:");
|
|
logger.log(
|
|
"info",
|
|
" gitzone services list -g # List all registered projects",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services status -g # Show global container status",
|
|
);
|
|
logger.log(
|
|
"info",
|
|
" gitzone services stop -g # Stop all (prompts for confirmation)",
|
|
);
|
|
}
|
|
|
|
// ==================== Global Command Handlers ====================
|
|
|
|
async function handleGlobalCommand(command: string) {
|
|
const globalRegistry = GlobalRegistry.getInstance();
|
|
|
|
switch (command) {
|
|
case "list":
|
|
await handleGlobalList(globalRegistry);
|
|
break;
|
|
|
|
case "status":
|
|
await handleGlobalStatus(globalRegistry);
|
|
break;
|
|
|
|
case "stop":
|
|
await handleGlobalStop(globalRegistry);
|
|
break;
|
|
|
|
case "cleanup":
|
|
await handleGlobalCleanup(globalRegistry);
|
|
break;
|
|
|
|
case "help":
|
|
default:
|
|
showHelp();
|
|
break;
|
|
}
|
|
}
|
|
|
|
async function handleGlobalList(globalRegistry: GlobalRegistry) {
|
|
helpers.printHeader("Registered Projects (Global)");
|
|
|
|
const projects = await globalRegistry.getAllProjects();
|
|
const projectPaths = Object.keys(projects);
|
|
|
|
if (projectPaths.length === 0) {
|
|
logger.log("note", "No projects registered");
|
|
return;
|
|
}
|
|
|
|
for (const path of projectPaths) {
|
|
const project = projects[path];
|
|
const lastActive = new Date(project.lastActive).toLocaleString();
|
|
|
|
console.log();
|
|
logger.log("ok", `📁 ${project.projectName}`);
|
|
logger.log("info", ` Path: ${project.projectPath}`);
|
|
logger.log("info", ` Services: ${project.enabledServices.join(", ")}`);
|
|
logger.log("info", ` Last Active: ${lastActive}`);
|
|
}
|
|
}
|
|
|
|
async function handleGlobalStatus(globalRegistry: GlobalRegistry) {
|
|
helpers.printHeader("Global Service Status");
|
|
|
|
const statuses = await globalRegistry.getGlobalStatus();
|
|
|
|
if (statuses.length === 0) {
|
|
logger.log("note", "No projects registered");
|
|
return;
|
|
}
|
|
|
|
let runningCount = 0;
|
|
let totalContainers = 0;
|
|
|
|
for (const project of statuses) {
|
|
console.log();
|
|
logger.log("ok", `📁 ${project.projectName}`);
|
|
logger.log("info", ` Path: ${project.projectPath}`);
|
|
|
|
if (project.containers.length === 0) {
|
|
logger.log("note", " No containers configured");
|
|
continue;
|
|
}
|
|
|
|
for (const container of project.containers) {
|
|
totalContainers++;
|
|
const statusIcon =
|
|
container.status === "running"
|
|
? "🟢"
|
|
: container.status === "exited"
|
|
? "🟡"
|
|
: "⚪";
|
|
if (container.status === "running") runningCount++;
|
|
logger.log(
|
|
"info",
|
|
` ${statusIcon} ${container.name}: ${container.status}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
console.log();
|
|
logger.log(
|
|
"note",
|
|
`Summary: ${runningCount}/${totalContainers} containers running across ${statuses.length} project(s)`,
|
|
);
|
|
}
|
|
|
|
async function handleGlobalStop(globalRegistry: GlobalRegistry) {
|
|
helpers.printHeader("Stop All Containers (Global)");
|
|
|
|
const statuses = await globalRegistry.getGlobalStatus();
|
|
|
|
// Count running containers
|
|
let runningCount = 0;
|
|
for (const project of statuses) {
|
|
for (const container of project.containers) {
|
|
if (container.status === "running") runningCount++;
|
|
}
|
|
}
|
|
|
|
if (runningCount === 0) {
|
|
logger.log("note", "No running containers found");
|
|
return;
|
|
}
|
|
|
|
logger.log(
|
|
"note",
|
|
`Found ${runningCount} running container(s) across ${statuses.length} project(s)`,
|
|
);
|
|
console.log();
|
|
|
|
// Show what will be stopped
|
|
for (const project of statuses) {
|
|
const runningContainers = project.containers.filter(
|
|
(c) => c.status === "running",
|
|
);
|
|
if (runningContainers.length > 0) {
|
|
logger.log("info", `${project.projectName}:`);
|
|
for (const container of runningContainers) {
|
|
logger.log("info", ` • ${container.name}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log();
|
|
const shouldContinue =
|
|
await plugins.smartinteract.SmartInteract.getCliConfirmation(
|
|
"Stop all containers?",
|
|
false,
|
|
);
|
|
|
|
if (!shouldContinue) {
|
|
logger.log("note", "Cancelled");
|
|
return;
|
|
}
|
|
|
|
logger.log("note", "Stopping all containers...");
|
|
const result = await globalRegistry.stopAll();
|
|
|
|
if (result.stopped.length > 0) {
|
|
logger.log("ok", `Stopped: ${result.stopped.join(", ")}`);
|
|
}
|
|
if (result.failed.length > 0) {
|
|
logger.log("error", `Failed to stop: ${result.failed.join(", ")}`);
|
|
}
|
|
}
|
|
|
|
async function handleGlobalCleanup(globalRegistry: GlobalRegistry) {
|
|
helpers.printHeader("Cleanup Registry (Global)");
|
|
|
|
logger.log("note", "Checking for stale registry entries...");
|
|
const removed = await globalRegistry.cleanup();
|
|
|
|
if (removed.length === 0) {
|
|
logger.log("ok", "No stale entries found");
|
|
return;
|
|
}
|
|
|
|
logger.log(
|
|
"ok",
|
|
`Removed ${removed.length} stale entr${removed.length === 1 ? "y" : "ies"}:`,
|
|
);
|
|
for (const path of removed) {
|
|
logger.log("info", ` • ${path}`);
|
|
}
|
|
}
|