UNPKG

docker-pilot

Version:

A powerful, scalable Docker CLI library for managing containerized applications of any size

404 lines (400 loc) • 17 kB
"use strict"; /** * Compose Command - Enhanced Docker Compose file management * Provides commands for discovering, analyzing, and managing docker-compose files */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ComposeCommand = void 0; const BaseCommand_1 = require("./BaseCommand"); const FileUtils_1 = require("../utils/FileUtils"); const path = __importStar(require("path")); const fs = __importStar(require("fs")); class ComposeCommand extends BaseCommand_1.BaseCommand { constructor(context) { super('compose', 'Enhanced Docker Compose file management', 'Provides commands for discovering, analyzing, and managing docker-compose files', context); this.fileUtils = new FileUtils_1.FileUtils(); this.initializeI18n(); } initializeI18n() { const config = this.context.config; if (config?.language) { this.i18n.setLanguage(config.language); } } async execute(args) { const subcommand = args[0] || 'list'; try { switch (subcommand) { case 'list': case 'ls': return await this.listComposeFiles(args.slice(1)); case 'find': case 'search': return await this.findComposeFiles(args.slice(1)); case 'analyze': case 'info': return await this.analyzeComposeFile(args.slice(1)); case 'validate': return await this.validateComposeFile(args.slice(1)); case 'services': return await this.listServices(args.slice(1)); case 'help': this.showHelp(); return { success: true, output: this.i18n.t('compose.help.displayed'), error: '', executionTime: 0 }; default: return { success: false, output: '', error: this.i18n.t('error.unknown_subcommand', { command: subcommand }), executionTime: 0 }; } } catch (error) { return { success: false, output: '', error: error instanceof Error ? error.message : String(error), executionTime: 0 }; } } async listComposeFiles(args) { const startTime = Date.now(); const searchDir = args[0] || process.cwd(); const includeVariants = args.includes('--variants') || args.includes('-v'); const maxDepth = this.extractDepthOption(args) || 6; try { const foundFiles = await this.fileUtils.findDockerComposeFilesWithInfo(searchDir, { maxDepth, includeVariants, includeEmptyFiles: false }); if (foundFiles.length === 0) { return { success: true, output: this.i18n.t('compose.no_files_found'), error: '', executionTime: Date.now() - startTime }; } let output = this.i18n.t('compose.found_files_summary', { count: foundFiles.length }) + '\n\n'; foundFiles.forEach((file, index) => { const envText = file.environment ? ` (${file.environment})` : ''; const mainFileIndicator = file.isMainFile ? ' šŸŽÆ' : ''; const depthIndicator = file.depth === 0 ? ' šŸ“' : ` šŸ“‚(${file.depth})`; output += `${index + 1}. ${file.relativePath}${envText}${mainFileIndicator}${depthIndicator}\n`; output += ` šŸ“ ${this.fileUtils.formatFileSize(file.size)} | šŸ“… ${file.modified.toLocaleDateString()}\n`; output += ` šŸ› ļø ${file.serviceCount} ${this.i18n.t('compose.services')}: ${file.services.join(', ') || this.i18n.t('menu.no_services')}\n\n`; }); return { success: true, output: output.trim(), error: '', executionTime: Date.now() - startTime }; } catch (error) { return { success: false, output: '', error: this.i18n.t('error.generic', { message: error instanceof Error ? error.message : String(error) }), executionTime: Date.now() - startTime }; } } async findComposeFiles(args) { const startTime = Date.now(); const searchDir = args[0] || process.cwd(); try { const composeFiles = await this.fileUtils.findDockerComposeFiles(searchDir, { maxDepth: 8, includeVariants: true }); if (composeFiles.length === 0) { return { success: true, output: this.i18n.t('compose.no_files_found'), error: '', executionTime: Date.now() - startTime }; } const output = composeFiles.map((file, index) => `${index + 1}. ${path.relative(searchDir, file)}`).join('\n'); return { success: true, output: `${this.i18n.t('compose.found_files_summary', { count: composeFiles.length })}\n\n${output}`, error: '', executionTime: Date.now() - startTime }; } catch (error) { return { success: false, output: '', error: this.i18n.t('error.generic', { message: error instanceof Error ? error.message : String(error) }), executionTime: Date.now() - startTime }; } } async analyzeComposeFile(args) { const startTime = Date.now(); const filePath = args[0]; if (!filePath) { return { success: false, output: '', error: this.i18n.t('error.missing_argument', { argument: 'file_path' }), executionTime: Date.now() - startTime }; } try { if (!(await this.fileUtils.exists(filePath))) { return { success: false, output: '', error: this.i18n.t('compose.file_not_found', { file: filePath }), executionTime: Date.now() - startTime }; } const composeData = await this.fileUtils.readYaml(filePath); const stats = fs.statSync(filePath); let output = `šŸ“„ ${this.i18n.t('compose.file_analysis')}: ${path.basename(filePath)}\n\n`; output += `šŸ“ ${this.i18n.t('compose.file_size')}: ${this.fileUtils.formatFileSize(stats.size)}\n`; output += `šŸ“… ${this.i18n.t('compose.file_modified')}: ${stats.mtime.toLocaleString()}\n\n`; if (composeData.version) { output += `šŸ”§ Version: ${composeData.version}\n`; } if (composeData.services) { const services = Object.keys(composeData.services); output += `šŸ› ļø ${this.i18n.t('compose.services')} (${services.length}): ${services.join(', ')}\n`; // Analyze each service for (const [serviceName, serviceConfig] of Object.entries(composeData.services)) { output += `\nšŸ“¦ ${serviceName}:\n`; const service = serviceConfig; if (service.image) { output += ` šŸ–¼ļø Image: ${service.image}\n`; } if (service.build) { output += ` šŸ”Ø Build: ${typeof service.build === 'string' ? service.build : service.build.context || '.'}\n`; } if (service.ports) { output += ` 🌐 Ports: ${service.ports.join(', ')}\n`; } if (service.volumes) { output += ` šŸ’¾ Volumes: ${service.volumes.length} volume(s)\n`; } if (service.environment) { const envCount = Array.isArray(service.environment) ? service.environment.length : Object.keys(service.environment).length; output += ` šŸ” Environment: ${envCount} variable(s)\n`; } if (service.depends_on) { const dependencies = Array.isArray(service.depends_on) ? service.depends_on : Object.keys(service.depends_on); output += ` šŸ”— Dependencies: ${dependencies.join(', ')}\n`; } } } if (composeData.networks) { const networks = Object.keys(composeData.networks); output += `\n🌐 Networks (${networks.length}): ${networks.join(', ')}\n`; } if (composeData.volumes) { const volumes = Object.keys(composeData.volumes); output += `šŸ’¾ Volumes (${volumes.length}): ${volumes.join(', ')}\n`; } return { success: true, output: output.trim(), error: '', executionTime: Date.now() - startTime }; } catch (error) { return { success: false, output: '', error: this.i18n.t('error.failed_to_analyze', { file: filePath, error: error instanceof Error ? error.message : String(error) }), executionTime: Date.now() - startTime }; } } async validateComposeFile(args) { const startTime = Date.now(); const filePath = args[0]; if (!filePath) { return { success: false, output: '', error: this.i18n.t('error.missing_argument', { argument: 'file_path' }), executionTime: Date.now() - startTime }; } try { // Basic file existence check if (!(await this.fileUtils.exists(filePath))) { return { success: false, output: '', error: this.i18n.t('compose.file_not_found', { file: filePath }), executionTime: Date.now() - startTime }; } // Try to parse YAML const composeData = await this.fileUtils.readYaml(filePath); let output = `āœ… ${this.i18n.t('compose.file_valid')}: ${path.basename(filePath)}\n\n`; // Basic structure validation if (!composeData.services) { output += `āš ļø ${this.i18n.t('compose.no_services_warning')}\n`; } else { const serviceCount = Object.keys(composeData.services).length; output += `šŸ› ļø ${serviceCount} ${this.i18n.t('compose.services')} ${this.i18n.t('compose.found')}\n`; } if (composeData.version) { output += `šŸ”§ Version: ${composeData.version}\n`; } else { output += `āš ļø ${this.i18n.t('compose.no_version_warning')}\n`; } return { success: true, output: output.trim(), error: '', executionTime: Date.now() - startTime }; } catch (error) { return { success: false, output: '', error: this.i18n.t('compose.file_invalid', { file: filePath, error: error instanceof Error ? error.message : String(error) }), executionTime: Date.now() - startTime }; } } async listServices(args) { const startTime = Date.now(); const filePath = args[0] || await this.findDefaultComposeFile(); try { if (!(await this.fileUtils.exists(filePath))) { return { success: false, output: '', error: this.i18n.t('compose.file_not_found', { file: filePath }), executionTime: Date.now() - startTime }; } const composeData = await this.fileUtils.readYaml(filePath); if (!composeData.services) { return { success: true, output: this.i18n.t('compose.no_services_in_file'), error: '', executionTime: Date.now() - startTime }; } const services = Object.keys(composeData.services); const output = `šŸ› ļø ${this.i18n.t('compose.services')} in ${path.basename(filePath)} (${services.length}):\n\n${services.map((service, index) => `${index + 1}. ${service}`).join('\n')}`; return { success: true, output, error: '', executionTime: Date.now() - startTime }; } catch (error) { return { success: false, output: '', error: this.i18n.t('error.generic', { message: error instanceof Error ? error.message : String(error) }), executionTime: Date.now() - startTime }; } } showHelp() { const output = ` ${this.i18n.t('cmd.compose.title')} ${this.i18n.t('cmd.compose.usage')}: docker-pilot compose <subcommand> [options] ${this.i18n.t('cmd.compose.subcommands')}: list, ls ${this.i18n.t('cmd.compose.list_desc')} find, search ${this.i18n.t('cmd.compose.find_desc')} analyze, info ${this.i18n.t('cmd.compose.analyze_desc')} validate ${this.i18n.t('cmd.compose.validate_desc')} services ${this.i18n.t('cmd.compose.services_desc')} help ${this.i18n.t('cmd.compose.help_desc')} ${this.i18n.t('cmd.compose.options')}: --variants, -v ${this.i18n.t('cmd.compose.variants_desc')} --depth <n> ${this.i18n.t('cmd.compose.depth_desc')} ${this.i18n.t('cmd.compose.examples')}: docker-pilot compose list docker-pilot compose find /path/to/project docker-pilot compose analyze docker-compose.yml docker-pilot compose list --variants --depth 4 `.trim(); console.log(output); } extractDepthOption(args) { const depthIndex = args.findIndex(arg => arg === '--depth'); if (depthIndex !== -1 && depthIndex + 1 < args.length) { const depthValue = args[depthIndex + 1]; if (depthValue) { const depth = parseInt(depthValue); return isNaN(depth) ? null : depth; } } return null; } async findDefaultComposeFile() { const possibleFiles = [ 'docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml' ]; for (const file of possibleFiles) { if (await this.fileUtils.exists(file)) { return file; } } return 'docker-compose.yml'; // Default fallback } } exports.ComposeCommand = ComposeCommand; //# sourceMappingURL=ComposeCommand.js.map