runProcess method

Future<int> runProcess(
  1. List<String> arguments
)

Runs the publisher executable with arguments and streams its output.

Returns the process exit code, or 127 when the executable is not installed. Both output streams are always drained: leaving stderr unread lets a chatty tool fill the OS pipe buffer and deadlock.

Implementation

Future<int> runProcess(List<String> arguments) async {
  final Process process;
  try {
    process = await Process.start(
      publisher,
      arguments,
      runInShell: true,
      includeParentEnvironment: true,
    );
    JobArguments.trackProcess(process);
  } on ProcessException catch (e) {
    logger.logError(
      "Unable to start `$publisher`: ${e.message}. "
      "Make sure the tool is installed and available in your PATH.",
    );
    return 127;
  }

  // Stream stdout and stderr with appropriate logging levels
  final drained = Future.wait([
    process.stdout.transform(utf8.decoder).forEach(logger.logDebug),
    process.stderr.transform(utf8.decoder).forEach(logger.logErrorVerbose),
  ]);

  // Uploads are the longest silent stretch of a release: an IPA going to App
  // Store Connect can take minutes with nothing at all on screen.
  final exitCode = await Spinner.run(
    'uploading with $publisher',
    () async {
      final code = await process.exitCode;
      await drained;
      return code;
    },
  );
  return exitCode;
}