run method
Future<ZapStepRun>
run(
- MissionStep step, {
- required String workingDirectory,
- required Duration timeout,
override
Implementation
@override
Future<ZapStepRun> run(
MissionStep step, {
required String workingDirectory,
required Duration timeout,
}) async {
final tokens = step.command.trim().split(RegExp(r'\s+'));
final executable = tokens.first;
final args = tokens.skip(1).toList();
final started = DateTime.now();
final process = await Process.start(
executable,
args,
workingDirectory: workingDirectory,
);
final stdoutBuffer = StringBuffer();
final stderrBuffer = StringBuffer();
// Drain both streams to completion — the certified digest covers
// the FULL output, so the last chunks must be decoded before the
// digest is computed, even when the process exits first.
final stdoutDrained = process.stdout
.transform(const Utf8Decoder(allowMalformed: true))
.listen(stdoutBuffer.write)
.asFuture<void>();
final stderrDrained = process.stderr
.transform(const Utf8Decoder(allowMalformed: true))
.listen(stderrBuffer.write)
.asFuture<void>();
var timedOut = false;
int exit;
final done = process.exitCode;
try {
exit = await done.timeout(timeout);
} on TimeoutException {
timedOut = true;
// SIGTERM can be trapped — a step that ignores it would hang the
// sequential serve loop forever. Escalate straight to SIGKILL.
process.kill(ProcessSignal.sigkill);
// Wait out the kill, then normalize to the timeout convention —
// the signal's raw negative code is not part of the contract.
await done;
exit = zapTimeoutExit;
}
await stdoutDrained;
await stderrDrained;
final combined = '${stdoutBuffer.toString()}${stderrBuffer.toString()}';
final output = timedOut
? 'ZAP: step ${step.id} timed out after ${timeout.inSeconds}s '
'and was killed\n$combined'
: combined;
final at = DateTime.now().toUtc();
return ZapStepRun(
stepId: step.id,
phase: step.phase,
command: step.command,
exit: exit,
digest: ZapStepRun.digestOf(utf8.encode(combined)),
at: at.toIso8601String(),
durationMs: at.difference(started).inMilliseconds,
output: output,
);
}