Files
Genarrative/scripts/container-compose.mjs

100 lines
3.3 KiB
JavaScript

import {spawn} from 'node:child_process';
import {copyFileSync, existsSync} from 'node:fs';
import path from 'node:path';
const [, , rawCommand = 'help', ...args] = process.argv;
const command = rawCommand.trim();
const printComposeConfig = args.includes('--print');
const passthroughArgs = args.filter((arg) => arg !== '--print');
const projectRoot = process.cwd();
const composeFile = path.join('deploy', 'container', 'docker-compose.loadtest.yml');
const envExamplePath = path.join('deploy', 'container', 'api-server.env.example');
const envPath = path.join('deploy', 'container', 'api-server.env');
const supportedCommands = new Set(['init', 'build', 'up', 'down', 'logs', 'ps', 'config', 'k6']);
if (command === 'help' || !supportedCommands.has(command)) {
printHelp(command !== 'help');
process.exit(command === 'help' ? 0 : 1);
}
if (command === 'init') {
ensureEnvFile();
process.exit(0);
}
if (!existsSync(envPath)) {
ensureEnvFile();
console.error('[container] 请先检查 deploy/container/api-server.env 中的 SpacetimeDB 地址、库名和 token。');
process.exit(1);
}
const composeArgs = buildComposeArgs(command, passthroughArgs);
const child = spawn('docker', composeArgs, {
cwd: projectRoot,
env: process.env,
stdio: 'inherit',
shell: false,
});
child.on('error', (error) => {
console.error(`[container] docker compose 启动失败: ${error.message}`);
console.error('[container] 请确认 Docker Desktop 或 Docker Engine 已安装,并且 docker 在 PATH 中。');
process.exit(1);
});
child.on('exit', (code, signal) => {
if (signal) {
console.error(`[container] docker compose 被信号终止: ${signal}`);
process.exit(1);
}
process.exit(code ?? 0);
});
function buildComposeArgs(selectedCommand, extraArgs) {
const baseArgs = ['compose', '-f', composeFile];
switch (selectedCommand) {
case 'build':
return [...baseArgs, 'build', ...extraArgs];
case 'up':
return [...baseArgs, 'up', '-d', ...extraArgs];
case 'down':
return [...baseArgs, 'down', ...extraArgs];
case 'logs':
return [...baseArgs, 'logs', ...extraArgs];
case 'ps':
return [...baseArgs, 'ps', ...extraArgs];
case 'config':
return [...baseArgs, 'config', ...(printComposeConfig ? [] : ['--quiet']), ...extraArgs];
case 'k6':
return [...baseArgs, '--profile', 'loadtest', 'run', '--rm', 'k6', ...extraArgs];
default:
throw new Error(`unsupported command: ${selectedCommand}`);
}
}
function ensureEnvFile() {
if (existsSync(envPath)) {
console.log(`[container] 已存在 ${envPath}`);
return;
}
copyFileSync(envExamplePath, envPath);
console.log(`[container] 已从 ${envExamplePath} 生成 ${envPath}`);
}
function printHelp(isError) {
const output = isError ? console.error : console.log;
output(`Usage: npm run container:<command> -- [docker compose args]
Commands:
container:init 生成 deploy/container/api-server.env
container:build 构建 api-server 容器镜像
container:up 后台启动 api-server + nginx + otelcol
container:down 停止并清理容器
container:logs 查看容器日志
container:ps 查看容器状态
container:config 校验 compose 配置,传 -- --print 可展开完整配置
container:k6 在 compose 网络内运行 k6
`);
}