Future runProc()

in lib/src/utils.dart [29:118]


Future<PanaProcessResult> runProc(
  List<String> arguments, {
  String? workingDirectory,
  Map<String, String>? environment,
  Duration? timeout,
  int? maxOutputBytes,
}) async {
  timeout ??= _timeout;
  maxOutputBytes ??= _maxOutputBytes;

  log.info('Running `${[...arguments].join(' ')}`...');
  var process = await Process.start(arguments.first, arguments.skip(1).toList(),
      workingDirectory: workingDirectory, environment: environment);

  var stdoutLines = <List<int>>[];
  var stderrLines = <List<int>>[];
  var remainingBytes = maxOutputBytes;

  var killed = false;
  var wasTimeout = false;
  var wasOutputExceeded = false;
  String? killMessage;

  void killProc(String message) {
    if (!killed) {
      killMessage = message;
      log.severe('Killing `${arguments.join(' ')}` $killMessage');
      killed = process.kill(ProcessSignal.sigkill);
      log.info('killed `${arguments.join(' ')}` - $killed');
    }
  }

  var timer = Timer(timeout, () {
    wasTimeout = true;
    killProc('Exceeded timeout of $timeout');
  });

  var items = await Future.wait(<Future>[
    process.exitCode,
    process.stdout.forEach((outLine) {
      stdoutLines.add(outLine);
      remainingBytes -= outLine.length;
      if (remainingBytes < 0) {
        wasOutputExceeded = true;
        killProc('Output exceeded $maxOutputBytes bytes.');
      }
    }),
    process.stderr.forEach((errLine) {
      stderrLines.add(errLine);
      remainingBytes -= errLine.length;
      if (remainingBytes < 0) {
        wasOutputExceeded = true;
        killProc('Output exceeded $maxOutputBytes bytes.');
      }
    })
  ]);

  timer.cancel();

  final exitCode = items[0] as int;
  if (killed) {
    return PanaProcessResult(
      process.pid,
      exitCode,
      stdoutLines
          .map(systemEncoding.decode)
          .expand(const LineSplitter().convert)
          .take(_maxOutputLinesWhenKilled)
          .join('\n'),
      [
        if (killMessage != null) killMessage,
        ...stderrLines
            .map(systemEncoding.decode)
            .expand(const LineSplitter().convert)
            .take(_maxOutputLinesWhenKilled),
      ].join('\n'),
      wasTimeout: wasTimeout,
      wasOutputExceeded: wasOutputExceeded,
    );
  }

  return PanaProcessResult(
    process.pid,
    exitCode,
    stdoutLines.map(systemEncoding.decode).join(),
    stderrLines.map(systemEncoding.decode).join(),
    wasTimeout: wasTimeout,
    wasOutputExceeded: wasOutputExceeded,
  );
}