UNPKG

bit-ship

Version:

Bit-Ship CLI is tool that analyses your code and generates a custom environment for your needs You can use if to local development, CI/CD or even production.

159 lines (133 loc) 3.73 kB
#!/usr/bin/env node /** * Standalone worker script for monitoring podman container events. * This runs as a detached Node.js process, independent of the CLI. * It spawns `podman events` and writes container state to ~/.bit-ship/containers.json */ import { spawn } from 'child_process' import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs' import { homedir } from 'os' import { join } from 'path' const BIT_SHIP_DIR = join(homedir(), '.bit-ship') const CONTAINERS_FILE = join(BIT_SHIP_DIR, 'containers.json') function ensureDirectoryExists() { if (!existsSync(BIT_SHIP_DIR)) { mkdirSync(BIT_SHIP_DIR, { recursive: true }) } } function readContainersState() { try { if (existsSync(CONTAINERS_FILE)) { const content = readFileSync(CONTAINERS_FILE, 'utf8') return JSON.parse(content) } } catch (_err) { // File doesn't exist or is corrupted, start fresh } return {} } function writeContainersState(state) { ensureDirectoryExists() writeFileSync(CONTAINERS_FILE, JSON.stringify(state, null, 2), 'utf8') } function processEvent(event, state) { const now = Date.now() const eventTime = event.time ? event.time * 1000 : now // Extract container info from different event formats const containerName = event.Name || event.Actor?.Attributes?.name const containerId = event.ID || event.Actor?.ID const image = event.Image || event.Actor?.Attributes?.image const action = event.Status || event.Action if (!containerName || !containerId) { return state } const existing = state[containerName] switch (action) { case 'start': state[containerName] = { id: containerId, image: image || existing?.image || 'unknown', status: 'running', startTime: eventTime, endTime: null, lastUpdated: now } break case 'stop': if (existing) { state[containerName] = { ...existing, status: 'stopped', endTime: eventTime, lastUpdated: now } } break case 'die': if (existing) { state[containerName] = { ...existing, status: 'exited', endTime: eventTime, lastUpdated: now } } break case 'remove': if (existing) { state[containerName] = { ...existing, status: 'removed', endTime: eventTime, lastUpdated: now } } break case 'create': state[containerName] = { id: containerId, image: image || 'unknown', status: 'stopped', startTime: eventTime, endTime: null, lastUpdated: now } break } return state } // Main execution function main() { ensureDirectoryExists() const child = spawn('podman', ['events', '--format', 'json', '--filter', 'type=container'], { shell: true, stdio: ['ignore', 'pipe', 'ignore'] }) let buffer = '' child.stdout?.on('data', (data) => { buffer += data.toString() // Process complete JSON lines const lines = buffer.split('\n') buffer = lines.pop() || '' // Keep incomplete line in buffer for (const line of lines) { if (!line.trim()) continue try { const event = JSON.parse(line) let state = readContainersState() state = processEvent(event, state) writeContainersState(state) } catch (_err) { // Skip malformed JSON lines } } }) child.on('error', (_err) => { // Silently handle errors process.exit(1) }) child.on('close', (_code) => { // podman events exited (machine stopped?), exit worker process.exit(0) }) } main()