Dart :: Process.run() get stdout as stream instead of String, just like Process.start()

Viewed 2505

I want to execute some processes one by one in dart using either Process.run() or Process.start()

And I want to show the verbose log of the process. But the problem is Whenever I am using run it's providing the stdout in a string i.e., at the end of the process completion. But I want to display the logs while the process is being executed.

Cause run is returning us the instance of ProcessResult instead of Process, the returned stdout is String.

Have to use stdout.write(cleanProcess.stdout); in case of run;

OR

Now in case start(), I am getting stdout as Stream which is desired but the only problem is the start returns us to the Process and Doesn't actually await for the Process to complete.

Can use stdout.addStream(buildProcess.stdout); to display stdout as stream


Code that I am trying to execute, and display the verbose.

    print("HighSupply Executor : flutter clean");
    var cleanProcess = await Process.run('flutter', ["clean", "--verbose"],
        workingDirectory: "${flutterFolder.path}");
    stdout.write(cleanProcess.stdout); //only getting stdout in one go. needed as stream.

    print("HighSupply Executor : flutter pub get");
    var pubGetProcess = await Process.run('flutter', //OR can we use start and wait for process to complete
        ["pub", "get", "--verbose"],
        workingDirectory: "${flutterFolder.path}");
    stdout.write(pubGetProcess.stdout);

    print("HighSupply Executor : flutter build apk");
    var buildProcess = await Process.run(
        'flutter', ["build", "apk", "--verbose", generatedParams],
        workingDirectory: "${flutterFolder.path}");
    stdout.write(buildProcess.stdout);

TL;DR

Can I anyhow get stdout as a stream in case Prcocess.run() OR Can we wait for Process to complete before executing another in case of Process.start()

Any help is appreciated.

Edit: 1

As @julemand101 suggested to use exitcode and wait for it to return after the process completion, It works fine with my case, and haven't run into any issue yet but As he mentioned and stated in docs that is not reliable, so we are looking for a better concrete solution for it.

2 Answers

Source: Process

Process.start() is used to interact with the code. The future gives us a Process, after it has finished starting, but the Process is still running when we have the Process.

When the future completes the process is started and your code can interact with the process: writing to stdin, listening to stdout, and so on

Now we can access a Stream of integers as Process.stdout and parse it with a utf8 decoder.

Sample code:

main() async {
  var process = await Process.start('cat', []);
  process.stdout
      .transform(utf8.decoder)
      .forEach(print);
  process.stdin.writeln('Hello, world!');
  process.stdin.writeln('Hello, galaxy!');
  process.stdin.writeln('Hello, universe!');
}

Out of the scope of this answer, we can manipulate the process objects, send interrupts, kill etc. and when the process ends, expect to get a done event on the stream.

I know this answer is too late, but I will leave it here maybe someone will find it helpful;

After playing around with the Process start() and run() methods, I found a way to achieve the required behavior of the original question by awaiting for addStream Future to complete.

void main() async {
  final p = await Process.start('bash', ['-c', 'sleep 3']);
  await stdout.addStream(p.stdout);
  print('the end ');
}
Related