runProcess method
Future<ProcessInfo>
runProcess(
- String commandName,
- List<
String> args, { - bool resolveCommandPath = true,
- String? workingDirectory,
- bool handleSignals = false,
- bool redirectOutput = false,
- bool catchOutput = false,
- bool drainOutput = false,
- String stdoutFilter(
- String o
- String stderrFilter(
- String o
- void onSignal(
- ProcessSignal signal
Runs a Process command and returns it.
commandNameis the command to be executed to start the Process.argsis the arguments to pass to the Process.- If
resolveCommandPathistrueresolvescommandNameto the local path of the command binary, using executablePath. workingDirectoryis the Process working directory. Ifnullwill use the current working directory.- If
handleSignalsistruekills the Process ifSIGINTorSIGTERMis triggered in the host/current process.onSignalis the hook for when aSIGINTorSIGTERMis redirected.
- If
redirectOutputistrueredirects the Process outputs to the host/current stdout and stderr. - If
catchOutputistruecatches the Process outputs to ProcessInfo.outputBuffer and ProcessInfo.errorOutputBuffer. stdoutFilteris a filter for the Processstdout. Useful to remove sensitive data.stderrFilteris a filter for the Processstderr. Useful to remove sensitive data.- If
drainOutputistruethe Process outputs are consumed and discarded (when not already consumed byredirectOutputorcatchOutput).
If none of redirectOutput, catchOutput and drainOutput is true,
the Process stdout and stderr are not consumed (so the caller can
read ProcessInfo.process stdout/stderr itself): the caller must
drain them, otherwise a process that writes more than the OS pipe buffer
blocks and never exits. Pass drainOutput: true when the output is not
needed.
Implementation
Future<ProcessInfo> runProcess(
String commandName,
List<String> args, {
bool resolveCommandPath = true,
String? workingDirectory,
bool handleSignals = false,
bool redirectOutput = false,
bool catchOutput = false,
bool drainOutput = false,
String Function(String o)? stdoutFilter,
String Function(String o)? stderrFilter,
void Function(ProcessSignal signal)? onSignal,
}) async {
String? binPath;
if (resolveCommandPath) {
binPath = await executablePath(commandName);
if (binPath == null) {
throw StateError('Error resolving `$commandName` binary!');
}
} else {
binPath = commandName;
}
log(
'INFO',
'Process.start> $binPath $args > workingDirectory: $workingDirectory',
);
var process = await Process.start(
binPath,
args,
workingDirectory: workingDirectory,
);
StreamSubscription<ProcessSignal>? listenSigInt;
StreamSubscription<ProcessSignal>? listenSigTerm;
if (handleSignals) {
listenSigInt = ProcessSignal.sigint.watch().listen((s) {
if (onSignal != null) onSignal(s);
process.kill(ProcessSignal.sigint);
});
listenSigTerm = ProcessSignal.sigterm.watch().listen((s) {
if (onSignal != null) onSignal(s);
process.kill(ProcessSignal.sigterm);
});
}
var processInfo = ProcessInfo(process, binPath, args, workingDirectory);
var outputDecoder = systemEncoding.decoder;
final stdoutFilterF = stdoutFilter ?? (o) => o;
final stderrFilterF = stderrFilter ?? (o) => o;
if (catchOutput || redirectOutput) {
// `ProcessInfo.exitCode` waits for these, so the output is complete
// when it completes.
processInfo._outputDone.add(
process.stdout.transform(outputDecoder).forEach((o) {
o = stdoutFilterF(o);
if (redirectOutput) stdout.write(o);
if (catchOutput) processInfo.outputBuffer.add(o);
}),
);
processInfo._outputDone.add(
process.stderr.transform(outputDecoder).forEach((o) {
o = stderrFilterF(o);
if (redirectOutput) stderr.write(o);
if (catchOutput) processInfo.errorOutputBuffer.add(o);
}),
);
} else if (drainOutput) {
processInfo._outputDone.add(process.stdout.drain<void>());
processInfo._outputDone.add(process.stderr.drain<void>());
}
process.exitCode.then((_) {
// ignore: unawaited_futures
listenSigInt?.cancel();
// ignore: unawaited_futures
listenSigTerm?.cancel();
});
return processInfo;
}