import * as plugins from './tsdocker.plugins.js'; import { logger } from './tsdocker.logging.js'; import type { IDockerContextInfo } from './interfaces/index.js'; const smartshellInstance = new plugins.smartshell.Smartshell({ executor: 'bash' }); export class DockerContext { public contextInfo: IDockerContextInfo | null = null; /** Sets DOCKER_CONTEXT env var for explicit context selection. */ public setContext(contextName: string): void { process.env.DOCKER_CONTEXT = contextName; logger.log('info', `Docker context explicitly set to: ${contextName}`); } /** Detects current Docker context via `docker context inspect` and rootless via `docker info`. */ public async detect(): Promise { let name = 'default'; let endpoint = 'unknown'; const contextResult = await smartshellInstance.execSilent( `docker context inspect --format '{{json .}}'` ); if (contextResult.exitCode === 0 && contextResult.stdout) { try { const parsed = JSON.parse(contextResult.stdout.trim()); const data = Array.isArray(parsed) ? parsed[0] : parsed; name = data.Name || 'default'; endpoint = data.Endpoints?.docker?.Host || 'unknown'; } catch { /* fallback to defaults */ } } let isRootless = false; const infoResult = await smartshellInstance.execSilent( `docker info --format '{{json .SecurityOptions}}'` ); if (infoResult.exitCode === 0 && infoResult.stdout) { isRootless = infoResult.stdout.includes('name=rootless'); } this.contextInfo = { name, endpoint, isRootless, dockerHost: process.env.DOCKER_HOST }; return this.contextInfo; } /** Logs context info prominently. */ public logContextInfo(): void { if (!this.contextInfo) return; const { name, endpoint, isRootless, dockerHost } = this.contextInfo; logger.log('info', '=== DOCKER CONTEXT ==='); logger.log('info', `Context: ${name}`); logger.log('info', `Endpoint: ${endpoint}`); if (dockerHost) logger.log('info', `DOCKER_HOST: ${dockerHost}`); logger.log('info', `Rootless: ${isRootless ? 'yes' : 'no'}`); } /** Emits rootless-specific warnings. */ public logRootlessWarnings(): void { if (!this.contextInfo?.isRootless) return; logger.log('warn', '[rootless] network=host in buildx is namespaced by rootlesskit'); logger.log('warn', '[rootless] Local registry may have localhost vs 127.0.0.1 resolution quirks'); } /** Returns context-aware builder name: tsdocker-builder- */ public getBuilderName(): string { const contextName = this.contextInfo?.name || 'default'; const sanitized = contextName.replace(/[^a-zA-Z0-9_-]/g, '-'); return `tsdocker-builder-${sanitized}`; } }