runProcess method

Future<ProcessRunnerResult> runProcess(
  1. List<String> commandLine, {
  2. Directory? workingDirectory,
  3. bool? printOutput,
  4. bool failOk = false,
  5. Stream<List<int>>? stdin,
  6. bool runInShell = false,
  7. ProcessStartMode startMode = ProcessStartMode.normal,
})

Run the command and arguments in commandLine as a sub-process from workingDirectory if set, or the defaultWorkingDirectory if not. Uses Directory.current if defaultWorkingDirectory is not set.

Set failOk if runProcess should not throw an exception when the command completes with a a non-zero exit code.

If printOutput is set, indicates that the command will both write the output to stdout/stderr, as well as return it in the ProcessRunnerResult.stderr, ProcessRunnerResult.stderr members of the result. This overrides the setting of printOutputDefault.

The printOutput argument defaults to the value of printOutputDefault.

Implementation

Future<ProcessRunnerResult> runProcess(
  List<String> commandLine, {
  Directory? workingDirectory,
  bool? printOutput,
  bool failOk = false,
  Stream<List<int>>? stdin,
  bool runInShell = false,
  ProcessStartMode startMode = ProcessStartMode.normal,
}) async {
  workingDirectory ??= defaultWorkingDirectory;
  printOutput ??= printOutputDefault;
  if (printOutput) {
    stderr.write('Running "${commandLine.join(' ')}" in ${workingDirectory.path}.\n');
  }
  final List<int> stdoutOutput = <int>[];
  final List<int> stderrOutput = <int>[];
  final List<int> combinedOutput = <int>[];
  final Completer<void> stdoutComplete = Completer<void>();
  final Completer<void> stderrComplete = Completer<void>();
  final Completer<void> stdinComplete = Completer<void>();

  late Process process;
  Future<int> allComplete() async {
    if (stdin != null) {
      await stdinComplete.future;
      await process.stdin.close();
    }
    await stderrComplete.future;
    await stdoutComplete.future;
    return startMode == ProcessStartMode.normal ? process.exitCode : Future<int>.value(0);
  }

  try {
    process = await processManager.start(
      commandLine,
      workingDirectory: workingDirectory.absolute.path,
      environment: environment,
      runInShell: runInShell,
      mode: startMode,
    );
    if (startMode == ProcessStartMode.normal || startMode == ProcessStartMode.detachedWithStdio) {
      if (stdin != null) {
        stdin.listen((List<int> data) {
          process.stdin.add(data);
        }, onDone: () async => stdinComplete.complete());
      }
      process.stdout.listen(
        (List<int> event) {
          stdoutOutput.addAll(event);
          combinedOutput.addAll(event);
          if (printOutput!) {
            stdout.add(event);
          }
        },
        onDone: () async => stdoutComplete.complete(),
      );
      process.stderr.listen(
        (List<int> event) {
          stderrOutput.addAll(event);
          combinedOutput.addAll(event);
          if (printOutput!) {
            stderr.add(event);
          }
        },
        onDone: () async => stderrComplete.complete(),
      );
    } else {
      // For "detached", we can't wait for anything to complete.
      stdinComplete.complete();
      stdoutComplete.complete();
      stderrComplete.complete();
    }
  } on ProcessException catch (e) {
    final String message = 'Running "${commandLine.join(' ')}" in ${workingDirectory.path} '
        'failed with:\n$e';
    throw ProcessRunnerException(message);
  } on ArgumentError catch (e) {
    final String message = 'Running "${commandLine.join(' ')}" in ${workingDirectory.path} '
        'failed with:\n$e';
    throw ProcessRunnerException(message);
  }

  final int exitCode = await allComplete();
  if (exitCode != 0 && !failOk) {
    final String message =
        'Running "${commandLine.join(' ')}" in ${workingDirectory.path} exited with code $exitCode\n${decoder.decode(combinedOutput)}';
    throw ProcessRunnerException(
      message,
      result: ProcessRunnerResult(
        exitCode,
        stdoutOutput,
        stderrOutput,
        combinedOutput,
        pid: process.pid,
        decoder: decoder,
      ),
    );
  }
  return ProcessRunnerResult(
    exitCode,
    stdoutOutput,
    stderrOutput,
    combinedOutput,
    pid: process.pid,
    decoder: decoder,
  );
}