How to run exit-independent code in Dart? - dart

I'm willing to execute pub get in background ignoring if the process that started it exited o terminated. Something like this:
// ... pubspec.yaml code changes
executeInBackground("pub get"); //async call, returns a Future
exit(0);
How could I do this without using the Process.runSync() blocking call? (I want the program to end ASAP)

See Process.start doc and its mode parameter.
import 'dart:io';
main() async {
final p = await Process.start(
'pub',
['get'],
runInShell: true,
mode: ProcessStartMode.DETACHED, //all the magic is here
);
print(p.pid);
}

Related

Dart testing Command line program

Suppose I have the following program increment.dart,
import 'dart:io';
void main() {
var input = int.parse(stdin.readLineSync());
print(++input);
}
and I want to test it similar to expect() from test package like,
test('Increment', () {
expect(/*call program with input 0*/ , equals(1));
});
Elaborating my use case:
I use this website to practice by solving the puzzles. They do have an online IDE but it doesn't have any debugging tools and the programs use std io. So what I have to do for debugging my code locally is to replace every stdin.readLineSync() with hardcoded test values and then repeat for every test. I'm looking a way to automate this.(Much like how things work on their site)
Following #jamesdlin's suggestion, I looked up info about Processes and found this example and whipped up the following test:
#TestOn('vm')
import 'dart:convert';
import 'dart:io';
import 'package:test/test.dart';
void main() {
test('Increment 0', () async {
final input = 0;
final path = 'increment.dart';
final process = await Process.start('dart', ['$path']);
// Send input to increment.dart's stdin.
process.stdin.writeln(input);
final lineStream =
process.stdout.transform(Utf8Decoder()).transform(LineSplitter());
// Test output of increment.dart
expect(
lineStream,
emitsInOrder([
// Values match individual events.
'${input + 1}',
// By default, more events are allowed after the matcher finishes
// matching. This asserts instead that the stream emits a done event and
// nothing else.
emitsDone
]));
});
}
Trivia:
#TestOn()
Used to specify a Platform Selector.
Process.start()
Used to run commands from the program itself like, ls -l (code: Process.start('ls', ['-l'])). First argument takes the command to be executed and second argument takes the list of arguments to be passed.
Testing stream

If I want everything to execute, in order, inside a function, do I await each line?

I know for sure my brain isn't totally clear on async/await so I need some clarity. I see a lot of examples where await is used on some lines and not others inside a function marked async. For example, I rarely if ever have seen an example like this (I am using the print statement as an example of something simple/basic.):
myFunction() async {
await functionA();
await print("This really long thing that's going to print out.");
await functionB();
await MyExtraClass.lookupSomethingQuickly();
...
}
So the examples I see it's usually something like this:
myFunction() async {
await functionA();
print("This really long thing that's going to print out.");
await functionB();
MyExtraClass.lookupSomethingQuickly();
...
}
So I am wondering if there's just an assumption that simple things will complete in order or if theoretically, putting await in front of each line is what I should be doing in cases where I absolutely need line 1 to follow line 2 to follow line 3, etc... Like what if I absolutely need that print to finish before functionB() goes off?
Essentially I find myself making a judgment call on every line every time I am writing a function with async/await and I never know if my code is working because of good timing and luck or if there would ever be cases that would throw the execution off.
async / await is to make asynchronuos code easier to write, to read and to reason about. Synchronuos code doesn't need such support.
For async programming in Dart see also https://www.dartlang.org/docs/tutorials/futures/
If you take this code example
import 'dart:async' show Future;
void main() {
doSomethingAsync().then((_) => print('afterwards'));
print('at last');
}
Future doSomethingAsync() {
return new Future.delayed(const Duration(seconds: 1), () {
print('done something');
});
}
Try it in DartPad
which prints
at last
done something
afterwards
If you're not familiar with async execution this might be surprising
This is because code passed to Future.delayed() is executed with a delay of 1 second. The Future instance returned by doSomethingAsync() "completes" when the code in Future.delayed() has been executed.
In this line
doSomethingAsync().then((_) => print('afterwards'));
we call .then(...) on the Future returned by doSomethingAsync() and pass a closure (inline function) to .then(...). ((_) => print('afterwards')).
A feature of Future is that it calls the code passed to then(...) after it was completed (in our case when done something was printed after 1 sec delay).
So the execution goes something like
call doSomethingAsync() which schedules a call to print('done something) for later execution and returns a Future
call print('at last'); which just prints at last
after 1 second delay print('done something') is called
the Future returned from doSomethingAsync() is completed
the Future calls `(_) => print('afterwards')
main() ends.
When we use async / await the code looks like
import 'dart:async' show Future;
Future main() async {
await doSomethingAsync();
print('afterwards');
print('at last');
}
Future doSomethingAsync() {
return new Future.delayed(const Duration(seconds: 1), () {
print('done something');
});
}
Try it in DartPad
When run, the output is
done something
afterwards
at last
we also could use async / await in doSomethingAsync() but now we only focus on main()
Now the execution looks like
call doSomething() and wait for the returned Future to complete
print('done something') is executed and the Future completed
the execution of code after await continues
print('afterwards');
print('at last');
This is probably the behavior you expected.
To your original question. await is only necessary when a call returns a Future and you want the following code only be executed when the Future was completed. If the call doesn't return a Future there is nothing to wait for.
await print('xxx') is still valid code. This is to support functions that sometimes do some async work and return a Future but sometimes the don't have async work to do and execute the code immediately and just return afterwards. In this case there is nothing to wait for.
someTimesAsync() {
if(new DateTime.now().weekday == 1) {
return new Future.delayed(const Duration(seconds: 1), () {
print('done something');
});
} else {
print('done something');
}
}
await someTimesAsync();
works in both cases. If it wouldn't this would be cumbersome.
For more details about async / await see also https://www.dartlang.org/articles/await-async/

What is the best way to stream stdout from a Process, in Dart?

I would like to run a Process, and stream the process's stdout to the console. What is the best (most effective, easiest to understand, least lines of code) way to do this?
For example:
var process = await Process.start(exec, args);
I'd like to see any stdout contents as soon as they are available.
Thanks!
import 'dart:io';
void main() async {
var process = await Process.start(exec, args);
process.stdout.pipe(stdout);
}
Or using then:
import 'dart:io';
void main() {
Process.start(exec, args).then(
(process) => process.stdout.pipe(stdout)
);
}
https://api.dart.dev/dart-async/Stream/pipe.html
Here's one way:
var process = await Process.start(exec, args);
stdout.addStream(process.stdout);
Notice that I add the process.stdout stream to the normal stdout stream, which comes from dart:io.
For completeness, you could use the mode argument in Process.start and pass a ProcessStartMode.inheritStdio
var process = await Process.start(
command,
args,
mode: ProcessStartMode.inheritStdio
);
Be careful though, this will, as the mode's name implies, pass on all stdio from the process (stdin, stdout and stderr) to the default stdout which might cause unexpected results as stuff like sigterms are passed on too.

How to simulate long time process (sleep) in Dart?

I want to stop/sleep executing to simulate long time process, unfortunately I can't find information about it. I've read the following topic (How can I "sleep" a Dart program), but it isn't what I look for.
For example sleep() function from dart:io packages isn't applicable, because this package is not available in a browser.
For example:
import 'dart:html';
main() {
// I want to "sleep"/hang executing during several seconds
// and only then run the rest of function's body
querySelect('#loading').remove();
...other functions and actions...
}
I know that there is Timer class to make callbacks after some time, but still it doesn't prevent the execution of program as a whole.
There is no way to stop execution. You can either use a Timer, Future.delayed, or just use an endless loop which only ends after certain time has passed.
If you want a stop the world sleeping function, you could do it entirely yourself. I will mention that I don't recommend you do this, it's a very bad idea to stop the world, but if you really want it:
void sleep(Duration duration) {
var ms = duration.inMilliseconds;
var start = new DateTime.now().millisecondsSinceEpoch;
while (true) {
var current = new DateTime.now().millisecondsSinceEpoch;
if (current - start >= ms) {
break;
}
}
}
void main() {
print("Begin.");
sleep(new Duration(seconds: 2));
print("End.");
}

Console application - StringDecoder stdin

The following or similar was shown for terminal input, however terminating input with ctl-d is not good. Is there another way to exit from this "loop"?
import "dart:io";
void main() {
stdout.write("Enter Data : ");
new StringDecoder().bind(stdin).listen((String sInput){});
//// Do something with sInput ............
}
You can terminate a dart program by running the exit method when using dart:io
void exit(int status)
Exit the Dart VM process immediately with the given status code.
This does not wait for any asynchronous operations to terminate.
Using exit is therefore very likely to lose data.
From the docs
That code would go inside a check in the event handler in listen
A few options come to mind. First, you could use takeWhile() to set a 'done' condition:
new StringDecoder().bind(stdin)
.takeWhile((s) => s.trim() != 'exit')
.listen((sInput) {
That will use the same onDone handler (if one is set) when the user inputs the EOF character or types exit followed by the enter key. You can have more flexibility by cancelling the subscription with cancel():
void main() {
stdout.write("Enter Data : ");
var sub;
sub = new StringDecoder().bind(stdin).listen((String sInput) {
if (sInput.trim() == 'exit' || sInput.trim() == 'bye')
sub.cancel();
// Do something with sInput ............
});
Cancelling the subscription doesn't close the Stream, so any onDone handler isn't called.
Of course, if you've got nothing left to do, you can always terminate with exit(0) [1].

Resources