import { Either, IEither, type ITraceable, LogLevel, LogMetricTraceSupplier, Metric, TraceUtil, } from '@emprespresso/pengueno'; import { promisify } from 'node:util'; import { exec as execCallback } from 'node:child_process'; const exec = promisify(execCallback); export type Command = string[] | string; export type StdStreams = { stdout: string; stderr: string }; export const CmdMetric = Metric.fromName('Exec').asResult(); export const getStdout = ( c: ITraceable, options: { env?: Record; clearEnv?: boolean } = {}, ): Promise> => c .flatMap(TraceUtil.withFunctionTrace(getStdout)) .flatMap((tCmd) => tCmd.traceScope(() => `Command = ${tCmd.get()}`)) .map((tCmd) => { const cmd = tCmd.get(); const _exec = typeof cmd === 'string' ? cmd : cmd.join(' '); const env = options.clearEnv ? options.env : { ...process.env, ...options.env }; return Either.fromFailableAsync(exec(_exec, { env })); }) .map( TraceUtil.promiseify((tEitherStdStreams) => tEitherStdStreams.get().mapRight(({ stderr, stdout }) => { if (stderr) tEitherStdStreams.trace.traceScope(LogLevel.DEBUG).trace(`StdErr = ${stderr}`); return stdout; }), ), ) .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(CmdMetric))) .get();