433 lines
13 KiB
TypeScript
433 lines
13 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';
|
|
|
|
export const run = async (argvArg: any) => {
|
|
const isGlobal = argvArg.g || argvArg.global;
|
|
const command = argvArg._[1] || 'help';
|
|
|
|
// Handle global commands first
|
|
if (isGlobal) {
|
|
await handleGlobalCommand(command);
|
|
return;
|
|
}
|
|
|
|
// Local project commands
|
|
const serviceManager = new ServiceManager();
|
|
await serviceManager.init();
|
|
|
|
const service = argvArg._[2] || 'all';
|
|
|
|
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 'config':
|
|
if (service === 'services' || argvArg._[2] === 'services') {
|
|
await handleConfigureServices(serviceManager);
|
|
} else {
|
|
await serviceManager.showConfig();
|
|
}
|
|
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;
|
|
|
|
case 'help':
|
|
default:
|
|
showHelp();
|
|
break;
|
|
}
|
|
};
|
|
|
|
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();
|
|
}
|
|
|
|
function showHelp() {
|
|
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', ' 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 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}`);
|
|
}
|
|
} |