runWithOutput method

Future<RunResult> runWithOutput(
  1. List<String> cmd, {
  2. required ProcessManager processManager,
  3. required LoggerService logger,
  4. Duration? timeout,
  5. bool showStderr = false,
})

Implementation

Future<RunResult> runWithOutput(
  List<String> cmd, {
  required ProcessManager processManager,
  required LoggerService logger,
  Duration? timeout,
  bool showStderr = false,
}) async {
  while (true) {
    final Process process = await start(cmd);

    final StringBuffer stdoutBuffer = StringBuffer();
    final StringBuffer stderrBuffer = StringBuffer();
    final Future<void> stdoutFuture =
        process.stdout.transform<String>(const Utf8Decoder()).listen(
      (event) {
        stdoutBuffer.write(event);
        logger.info(event);
      },
    ).asFuture<void>();

    final Future<void> stderrFuture =
        process.stderr.transform<String>(const Utf8Decoder()).listen((event) {
      stderrBuffer.write(event);

      if (showStderr) logger.info(event);
    }).asFuture<void>();

    int? exitCode;
    exitCode = timeout == null
        ? await process.exitCode.then<int?>((int x) => x)
        : await process.exitCode.then<int?>((int x) => x).timeout(timeout,
            onTimeout: () {
            // The process timed out. Kill it.
            processManager.killPid(process.pid);
            return null;
          });

    String stdoutString;
    String stderrString;
    try {
      Future<void> stdioFuture =
          Future.wait<void>(<Future<void>>[stdoutFuture, stderrFuture]);
      if (exitCode == null) {
        // If we had to kill the process for a timeout, only wait a short time
        // for the stdio streams to drain in case killing the process didn't
        // work.
        stdioFuture = stdioFuture.timeout(const Duration(seconds: 1));
      }
      await stdioFuture;
    } on Exception catch (e, s) {
      logger.info(
          'Exception while running process with output | waiting for stdio streams: $e, $s: $e\n$s');

      // Ignore errors on the process' stdout and stderr streams. Just capture
      // whatever we got, and use the exit code
    }
    stdoutString = stdoutBuffer.toString();
    stderrString = stderrBuffer.toString();

    final ProcessResult result = ProcessResult(
        process.pid, exitCode ?? -1, stdoutString, stderrString);
    final RunResult runResult = RunResult(result, cmd);

    // If the process did not timeout. We are done.
    if (exitCode != null) {
      logger.detail(runResult.toString());

      return runResult;
    }
  }
}