UNPKG

@git.zone/cli

Version:

A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.

261 lines (229 loc) 7.15 kB
import * as plugins from './mod.plugins.js'; import * as helpers from './helpers.js'; import { logger } from '../gitzone.logging.js'; export type ContainerStatus = 'running' | 'stopped' | 'not_exists'; export interface IDockerRunOptions { name: string; image: string; ports?: { [key: string]: string }; volumes?: { [key: string]: string }; environment?: { [key: string]: string }; restart?: string; command?: string; } export class DockerContainer { private smartshell: plugins.smartshell.Smartshell; constructor() { this.smartshell = new plugins.smartshell.Smartshell({ executor: 'bash', }); } /** * Check if Docker is installed and available */ public async checkDocker(): Promise<boolean> { try { const result = await this.smartshell.exec('docker --version'); return result.exitCode === 0; } catch (error) { return false; } } /** * Get container status */ public async getStatus(containerName: string): Promise<ContainerStatus> { try { // Check if running const runningResult = await this.smartshell.exec( `docker ps --format '{{.Names}}' | grep -q "^${containerName}$"` ); if (runningResult.exitCode === 0) { return 'running'; } // Check if exists but stopped const existsResult = await this.smartshell.exec( `docker ps -a --format '{{.Names}}' | grep -q "^${containerName}$"` ); if (existsResult.exitCode === 0) { return 'stopped'; } return 'not_exists'; } catch (error) { return 'not_exists'; } } /** * Start a container */ public async start(containerName: string): Promise<boolean> { try { const result = await this.smartshell.exec(`docker start ${containerName}`); return result.exitCode === 0; } catch (error) { return false; } } /** * Stop a container */ public async stop(containerName: string): Promise<boolean> { try { const result = await this.smartshell.exec(`docker stop ${containerName}`); return result.exitCode === 0; } catch (error) { return false; } } /** * Remove a container */ public async remove(containerName: string, force: boolean = false): Promise<boolean> { try { const forceFlag = force ? '-f' : ''; const result = await this.smartshell.exec(`docker rm ${forceFlag} ${containerName}`); return result.exitCode === 0; } catch (error) { return false; } } /** * Run a new container */ public async run(options: IDockerRunOptions): Promise<boolean> { let command = 'docker run -d'; // Add name command += ` --name ${options.name}`; // Add ports if (options.ports) { for (const [hostPort, containerPort] of Object.entries(options.ports)) { command += ` -p ${hostPort}:${containerPort}`; } } // Add volumes if (options.volumes) { for (const [hostPath, containerPath] of Object.entries(options.volumes)) { command += ` -v "${hostPath}:${containerPath}"`; } } // Add environment variables if (options.environment) { for (const [key, value] of Object.entries(options.environment)) { command += ` -e ${key}="${value}"`; } } // Add restart policy if (options.restart) { command += ` --restart ${options.restart}`; } // Add image command += ` ${options.image}`; // Add command if provided if (options.command) { command += ` ${options.command}`; } try { const result = await this.smartshell.exec(command); return result.exitCode === 0; } catch (error) { logger.log('error', `Failed to run container: ${error.message}`); return false; } } /** * Execute a command in a running container */ public async exec(containerName: string, command: string): Promise<string> { try { const result = await this.smartshell.exec(`docker exec ${containerName} ${command}`); if (result.exitCode === 0) { return result.stdout; } return ''; } catch (error) { return ''; } } /** * Get container logs */ public async logs(containerName: string, lines?: number): Promise<string> { try { const tailFlag = lines ? `--tail ${lines}` : ''; const result = await this.smartshell.exec(`docker logs ${tailFlag} ${containerName}`); return result.stdout; } catch (error) { return `Error getting logs: ${error.message}`; } } /** * Check if a container exists */ public async exists(containerName: string): Promise<boolean> { const status = await this.getStatus(containerName); return status !== 'not_exists'; } /** * Check if a container is running */ public async isRunning(containerName: string): Promise<boolean> { const status = await this.getStatus(containerName); return status === 'running'; } /** * Wait for a container to be ready */ public async waitForReady(containerName: string, maxAttempts: number = 30): Promise<boolean> { for (let i = 0; i < maxAttempts; i++) { if (await this.isRunning(containerName)) { return true; } await plugins.smartdelay.delayFor(1000); } return false; } /** * Get container information */ public async inspect(containerName: string): Promise<any> { try { const result = await this.smartshell.execSilent(`docker inspect ${containerName}`); if (result.exitCode === 0) { return JSON.parse(result.stdout); } return null; } catch (error) { return null; } } /** * Get port mappings for a container */ public async getPortMappings(containerName: string): Promise<{ [key: string]: string } | null> { try { // Use docker inspect without format to get full JSON, then extract PortBindings const result = await this.smartshell.execSilent(`docker inspect ${containerName}`); if (result.exitCode === 0 && result.stdout) { const inspectData = JSON.parse(result.stdout); if (inspectData && inspectData[0] && inspectData[0].HostConfig && inspectData[0].HostConfig.PortBindings) { const portBindings = inspectData[0].HostConfig.PortBindings; const mappings: { [key: string]: string } = {}; // Convert Docker's port binding format to simple host:container mapping for (const [containerPort, hostBindings] of Object.entries(portBindings)) { if (Array.isArray(hostBindings) && hostBindings.length > 0) { const hostPort = (hostBindings[0] as any).HostPort; if (hostPort) { mappings[containerPort.replace('/tcp', '').replace('/udp', '')] = hostPort; } } } return mappings; } } return null; } catch (error) { // Silently fail - container might not exist return null; } } }