@enspirit/emb
Version:
A replacement for our Makefile-for-monorepos
86 lines (85 loc) • 2.73 kB
JavaScript
import { spawn } from 'node:child_process';
import * as z from 'zod';
import { AbstractOperation } from '../../../operations/index.js';
/**
* https://docs.docker.com/reference/cli/docker/compose/logs/
*/
export const ComposeLogsOperationInputSchema = z
.object({
services: z
.array(z.string())
.optional()
.describe('The list of services to show logs for (all if omitted)'),
follow: z.boolean().optional().describe('Follow log output'),
timestamps: z.boolean().optional().describe('Show timestamps'),
tail: z
.number()
.optional()
.describe('Number of lines to show from the end'),
})
.optional();
export class ComposeLogsOperation extends AbstractOperation {
out;
/**
* @param out Optional writable stream to capture output. If not provided,
* output is streamed directly to the terminal (stdio: 'inherit').
*/
constructor(out) {
super(ComposeLogsOperationInputSchema);
this.out = out;
}
async _run(input) {
const { monorepo } = this.context;
const cmd = 'docker';
const args = ['compose', 'logs'];
const follow = input?.follow ?? true;
if (follow) {
args.push('-f');
}
if (input?.timestamps) {
args.push('-t');
}
if (input?.tail !== undefined) {
args.push('--tail', String(input.tail));
}
if (input?.services && input.services.length > 0) {
args.push(...input.services);
}
const child = spawn(cmd, args, {
stdio: this.out ? 'pipe' : 'inherit',
cwd: monorepo.rootDir,
});
if (this.out && child.stdout && child.stderr) {
child.stdout.pipe(this.out, { end: false });
child.stderr.pipe(this.out, { end: false });
}
const forward = (sig) => {
try {
child.kill(sig);
}
catch { }
};
const signals = [
'SIGINT',
'SIGTERM',
'SIGHUP',
'SIGQUIT',
];
signals.forEach((sig) => {
process.on(sig, () => forward(sig));
});
return new Promise((resolve, reject) => {
child.on('error', (err) => {
reject(new Error(`Failed to execute docker compose logs: ${err.message}`));
});
child.on('exit', (code) => {
if (code !== null && code !== 0) {
reject(new Error(`docker compose logs exited with code ${code}`));
}
else {
resolve();
}
});
});
}
}