runProcess method
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;
}