runProcess method

Future<ProcessInfo> runProcess(
  1. String commandName,
  2. List<String> args, {
  3. bool resolveCommandPath = true,
  4. String? workingDirectory,
  5. bool handleSignals = false,
  6. bool redirectOutput = false,
  7. bool catchOutput = false,
  8. String stdoutFilter(
    1. String o
    )?,
  9. String stderrFilter(
    1. String o
    )?,
  10. void onSignal(
    1. ProcessSignal signal
    )?,
})

Runs a Process command and returns it.

  • commandName is the command to be executed to start the Process.
  • args is the arguments to pass to the Process.
  • If resolveCommandPath is true resolves commandName to the local path of the command binary, using executablePath.
  • workingDirectory is the Process working directory. If null will use the current working directory.
  • If handleSignals is true kills the Process if SIGINT or SIGTERM is triggered in the host/current process.
    • onSignal is the hook for when a SIGINT or SIGTERM is redirected.
  • If redirectOutput is true redirects the Process outputs to the host/current stdout and stderr.
  • If catchOutput is true catches the Process outputs to ProcessInfo.outputBuffer and ProcessInfo.errorOutputBuffer.
  • stdoutFilter is a filter for the Process stdout. Useful to remove sensitive data.
  • stderrFilter is a filter for the Process stderr. Useful to remove sensitive data.

Implementation

Future<ProcessInfo> runProcess(String commandName, List<String> args,
    {bool resolveCommandPath = true,
    String? workingDirectory,
    bool handleSignals = false,
    bool redirectOutput = false,
    bool catchOutput = 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) {
    // ignore: unawaited_futures
    process.stdout.transform(outputDecoder).forEach((o) {
      o = stdoutFilterF(o);
      stdout.write(o);
      processInfo.outputBuffer.add(o);
    });
    // ignore: unawaited_futures
    process.stderr.transform(outputDecoder).forEach((o) {
      o = stderrFilterF(o);
      stderr.write(o);
      processInfo.errorOutputBuffer.add(o);
    });
  } else if (catchOutput) {
    // ignore: unawaited_futures
    process.stdout.transform(outputDecoder).forEach((o) {
      o = stdoutFilterF(o);
      processInfo.outputBuffer.add(o);
    });
    // ignore: unawaited_futures
    process.stderr.transform(outputDecoder).forEach((o) {
      o = stderrFilterF(o);
      processInfo.errorOutputBuffer.add(o);
    });
  } else if (redirectOutput) {
    // ignore: unawaited_futures
    process.stdout.transform(outputDecoder).forEach((o) {
      o = stdoutFilterF(o);
      stdout.write(o);
    });
    // ignore: unawaited_futures
    process.stderr.transform(outputDecoder).forEach((o) {
      o = stderrFilterF(o);
      stderr.write(o);
    });
  }

  process.exitCode.then((_) {
    // ignore: unawaited_futures
    listenSigInt?.cancel();
    // ignore: unawaited_futures
    listenSigTerm?.cancel();
  });

  return processInfo;
}