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].
Related
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);
}
I want to test a function that calls exit.
Basicly, I have a console application, that asks the user if he is sure that he wants a directory to be overwritten. When the users answers "No", the directory won't be overwritten, and the program should exit.
promptToDeleteRepo() {
bool okToDelete = ...
if(okToDelete) {
deleteRepo();
} else {
exit(0);
}
}
So I want to test that if the user answers "No", that the program really exits. But if I test this, my test runner exits.
In python I seem to be able to do something like:
with pytest.raises(SystemExit):
promptToDeleteRepo();
Is there something like this in Dart?
You can inject a custom exit function during the tests.
import 'dart:io' as io;
typedef ExitFn(int code);
ExitFn exit = io.exit;
promptToDeleteRepo() {
bool okToDelete = ...
if(okToDelete) {
deleteRepo();
} else {
exit(0);
}
}
and in your test :
int exitCodeUsed;
mylib.exit = (int code) {exitCodeUsed = code};
mylib.promptToDeleteRepo();
A better solution whould have to use zones but there doesn't seem to be possible to handle exit. It could be worth to file an issue.
One option that comes to my mind is to run the code you want to test in a new process Process.run() or Process.start() and check the exit code at the end. You can use stdin/stdout to communicate with the process (send keyboard input, read output)
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.");
}
I have a couple questions about how isolate works :
1) What is the difference between call and send and when I should use call over send?
2) Just curiosity, is there any way to chain isolate like we chain Future ?
3)
import 'dart:isolate';
echo() {
port.receive((msg, reply) {
print('I received: $msg');
});
}
main() {
var sendPort = spawnFunction(echo);
sendPort.call('Hello from main');
}
It displays : I received: Hello from main
but when I use send, it prints nothing, why?
Use the call() method on SendPort as a simple way to send a message and receive a reply. The call() method returns a Future for the reply. If you don't bother of the reply and simply want to send a message, use send().
Have a look at dart:isolate - Concurrency with Isolates for more informations.
For 3) it's explained in the above link :
In the standalone VM, the main() function runs in the first isolate (also known as the root isolate). When the root isolate terminates, it terminates the whole VM, regardless of whether other isolates are still running. For more information, see the section called “Keeping the root isolate alive”.
The test below attempts to run the less pager command and return once
the user quits. The problem is that it doesn't wait for user input, it
just lists the entire file and exits. Platform: xubuntu 12.04, Dart
Editor build: 13049.
import 'dart:io';
void main() {
shell('less', ['/etc/mime.types'], (exitCode) => exit(exitCode));
}
void shell(String cmd, List<String> opts, void onExit(int exitCode)) {
var p = Process.start(cmd, opts);
p.stdout.pipe(stdout); // Process output to stdout.
stdin.pipe(p.stdin); // stdin to process input.
p.onExit = (exitCode) {
p.close();
onExit(exitCode);
};
}
The following CoffeeScript function (using nodejs I/O) works:
shell = (cmd, opts, callback) ->
process.stdin.pause()
child = spawn cmd, opts, customFds: [0, 1, 2]
child.on 'exit', (code) ->
process.stdin.resume()
callback code
How can I make this work in Dart?
John has a good example about how to look at user input. But doesn't answer your original question. Unfortunately your question doesn't fit with how Dart operates. The two examples you have, the Dart version and CoffeeScript/Node.js version, do two completely different things.
In your CoffeeScript version, the spawn command is actually creating a new process and then passing execution over to that new process. Basically you're program is not interactively communicating with the process, rather your user is interacting with the spawned process.
In Dart it is different, your program is interacting with the spawned process. It is not passing off execution to the new process. Basically what you are doing is piping the input/output to and from the new process to your program itself. Since your program doesn't have a 'window height' from the terminal, it passes all the information at once. What you're doing in dart is almost equivalent to:
less /etc/mime.types | cat
You can use Process.start() to interactively communicate with processes. But it is your program which is interactively communicating with the process, not the user. Thus you can write a dart program which will launch and automatically play 'zork' or 'adventure' for instance, or log into a remote server by looking at the prompts from process's output.
However, at current there is no way to simply pass execution to the spawned process. If you want to communicate the process output to a user, and then also take user input and send it back to a process it involves an additional layer. And even then, not all programs (such as less) behave the same as they do when launched from a shell environment.
Here's a basic structure for reading console input from the user. This example reads lines of text from the user, and exits on 'q':
import 'dart:io';
import 'dart:isolate';
final StringInputStream textStream = new StringInputStream(stdin);
void main() {
textStream.onLine = checkBuffer;
}
void checkBuffer(){
final line = textStream.readLine();
if (line == null) return;
if (line.trim().toLowerCase() == 'q'){
exit(0);
}
print('You wrote "$line". Now write something else!');
}