Index: src/site/docs/tutorials/cmdline/index.markdown |
diff --git a/src/site/docs/tutorials/cmdline/index.markdown b/src/site/docs/tutorials/cmdline/index.markdown |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5ce5c711da52cbc9adc94d3d6290e040f290fbcd |
--- /dev/null |
+++ b/src/site/docs/tutorials/cmdline/index.markdown |
@@ -0,0 +1,769 @@ |
+--- |
+layout: default |
+title: "Write Command-Line Apps" |
+description: "Basics for command-line apps" |
+has-permalinks: true |
+tutorial: |
+ id: dart-io |
+next: fetchdata/ |
+next-title: "Fetch Data Dynamically" |
+prev: futures/ |
+prev-title: "Use Future-Based APIs" |
+--- |
+ |
+{% capture whats_the_point %} |
sethladd
2014/01/03 00:57:28
Global: I'd like to see some advice for when to us
sethladd
2014/01/03 00:57:28
Global: I couldn't find it, can you link to the pr
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
There's only one place where synchronous is used a
|
+ |
+* Server-side applications need to do input and output. |
sethladd
2014/01/03 00:57:28
the tutorial says "command-line" but here you say
mem
2014/01/03 17:38:02
Done.
|
+* The dart:io library provides I/O functionality. |
+* The args package helps define and parse command-line arguments. |
+* Most input and output requires the use of Streams. |
+* Streams provide a series of asynchronous data events. |
+* To handle asynchronous data, you need to use Futures. |
+ |
+{% endcapture %} |
+ |
+{% capture sample_links %} |
+ |
+<p> This tutorial features these examples:</p> |
+* helloworld42 |
+* dcat |
+* dgrep |
+ |
+<p> |
+Don't have the source code? |
sethladd
2014/01/03 00:57:28
the source for the examples above?
mem
2014/01/03 17:38:02
this is consistent with all of the other tutorials
|
+<a href="https://github.com/dart-lang/dart-tutorials-samples/archive/master.zip"> |
+ Download it. |
+</a> |
+ |
+{% endcapture %} |
+ |
+{% capture content %} |
+ |
+<div class="tute-target-title"> |
+<h1>{{page.title}}</h1> |
+<h3>An introduction to standalone apps</h3> |
sethladd
2014/01/03 00:57:28
and here we use standalone (instead of command-lin
mem
2014/01/03 17:38:02
we use standalone here otherwise we use the exact
|
+</div> |
+ |
+<div id="under-construction" markdown="1"> |
+<h3> <i class="icon-wrench"> </i> Under construction </h3> |
+ |
+This is a draft under construction. |
+Your kindly worded |
+<a |
+ href="http://code.google.com/p/dart/issues/entry?template=Tutorial%20feedback" |
+ target="_blank"> |
+comments and suggestions |
+</a> |
+are appreciated. |
+Thank you for your patience. |
+</div> |
+ |
+This tutorial looks at a few small command-line applications. |
sethladd
2014/01/03 00:57:28
opinion: this tutorial teaches you how to build co
mem
2014/01/03 17:38:02
Done.
|
+These programs use resources that most command-line applications need, |
+including the standard output, error, and input streams, |
+command-line arguments, files and directories, and more. |
+ |
+* [Run an app with the standalone Dart VM](#run-the-first-app) |
+* [Check out the dcat example](#dcat-code) |
+* [Parsing command-line arguments](#cmd-line-args) |
+* [Reading and writing with stdin, stdout, and stderr](#std-in-out-err) |
+* [Getting info about a file](#filesystementity) |
+* [Reading a file](#reading-a-file) |
+* [Writing a file](#writing-a-file) |
+* [Getting environment information](#env-var) |
+* [Setting exit codes](#exit-codes) |
+* [Check out the code for another example](#dgrep-code) |
+* [Summary](#summary) |
+* [Other resources](#other-resources) |
+* [What next?](#what-next) |
+ |
+## Run an app with the standalone Dart VM {#run-the-first-app} |
sethladd
2014/01/03 00:57:28
other headers are "-ing" like "reading" or "writin
mem
2014/01/03 17:38:02
Done.
|
+ |
+To run a command-line app, you need the Dart VM (`dart`), |
+which comes with the Dart Editor (in the Dart download) |
sethladd
2014/01/03 00:57:28
use a link for "Dart download" ?
mem
2014/01/03 17:38:02
Done.
|
+or in the [Dart SDK](/tools/sdk/) download. |
+If you install the Dart download in a directory called `~/myDartDownload`, |
+you can find `dart` |
+in `~/myDartDownload/dart-sdk/bin`. |
+ |
+<div markdown="1"> |
+ |
+ |
+ |
+</div> |
+ |
+By putting this directory in your PATH |
+you can refer to the `dart` command and other commands, |
+such as the dart analyzer, by name. |
+ |
+Let's run a small program. |
+ |
+<ol> |
+<li markdown="1"> |
+Create a file called `helloworld42.dart` that contains this code: |
+ |
+{% prettify dart %} |
+void main() { |
+ int fortyTwo = 'Hello, World'; // Type mismatch. |
sethladd
2014/01/03 00:57:28
I think teaching the optional types here, and how
mem
2014/01/03 17:38:02
Done.
|
+ print(fortyTwo); |
+} |
+{% endprettify %} |
+</li> |
+ |
+<li markdown="1"> |
+In the directory that contains the file you just created, |
+run the program with the command as shown by the highlighted text. |
+ |
+{% prettify bash %} |
+% [[highlight]]dart helloworld42.dart[[/highlight]] |
+Hello, World! |
+% |
+{% endprettify %} |
+ |
+The program runs cleanly in spite |
+of the type mismatch in the source code. |
+Types are optional in Dart and by default the Dart VM |
+does not do type-checking. |
+</li> |
+ |
+<li markdown="1"> |
+Run the `helloworld42.dart` program using the `--checked` flag: |
+ |
+{% prettify bash %} |
+% [[highlight]]dart --checked helloworld42.dart[[/highlight]] |
+Unhandled exception: |
+type 'String' is not a subtype of type 'int' of 'fortyTwo'. |
+... |
+% |
+{% endprettify %} |
+ |
+The program fails because the program assigns a string to an integer. |
+ |
+The `--checked` option enables |
+assertion and type checks (checked mode). |
+Checked mode is useful during development for finding errors |
+related to types and for testing `assert` statements. |
+We recommend running your programs in checked mode during prototyping |
+and development, and turning it off for production. |
+ |
+Note that the flags and options passed to the Dart VM go before the name |
+of the Dart file to run. |
+</li> |
+</ol> |
+ |
+## Check out the dcat example {#dcat-code} |
sethladd
2014/01/03 00:57:28
Can you make it more clear that you'll go into mor
mem
2014/01/03 17:38:02
Done.
|
+ |
+Take a quick look at the code for a small sample called `dcat`, |
+which is a simplified implementation of the Unix cat utility. |
sethladd
2014/01/03 00:57:28
explain what the Unix cat utility is. 80% of our u
mem
2014/01/03 17:38:02
Done.
|
+This program uses various classes, functions, and properties |
+available to command-line apps. |
+Hover over the highlighted code below for explanations. |
+ |
+<pre class="prettyprint lang-dart"> |
+import 'dart:async'; |
+import 'dart:convert'; |
+import 'dart:io'; |
+ |
+import 'package:args/args.dart'; |
+ |
+const LINE_NUMBER = 'line-number'; |
+var NEWLINE = '\n'; |
+ |
+ArgResults argResults; |
+ |
+void main(<a href="#" class="dart-popover" data-toggle="popover" title="Command-line arguments" data-html="true" data-trigger="hover focus" data-content="Command-line arguments are passed in by the system when the program starts.">List<String> arguments</a>) { |
+ exitCode = 0; // Presume success. |
sethladd
2014/01/03 00:57:28
I'm left wondering where exitCode came from?
mem
2014/01/03 17:38:02
Done.
|
+ final parser = new ArgParser() |
+ ..addFlag(LINE_NUMBER, negatable: false, abbr: 'n'); |
+ |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Arguments parser" data-html="true" data-trigger="hover focus" data-content="The ArgParser class provides help with parsing command-line arguments.">argResults = parser.parse(arguments);</a> |
+ List<String> paths = argResults.rest; |
+ |
+ dcat(paths, argResults[LINE_NUMBER]); |
+} |
+ |
+Future dcat(List<String> paths, bool showLineNumbers) { |
+ if (paths.isEmpty) { |
+ // No files provided as arguments. Read from stdin and print each line. |
+ return <a href="#" class="dart-popover" data-toggle="popover" title="Standard I/O streams" data-html="true" data-trigger="hover focus" data-content="This code reads from the standard input stream and pipes the data to the standard output stream.">stdin.pipe(stdout);</a> |
+ } else { |
+ return Future.forEach(paths, (path) { |
+ int lineNumber = 1; |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Open a file for reading" data-html="true" data-trigger="hover focus" data-content="Use the File class to represent a file on the native file system.">Stream<List<int>> stream = new File(path).openRead();</a> |
+ return stream |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Data converters" data-html="true" data-trigger="hover focus" data-content="Convert data as it becomes available on a stream.">.transform(UTF8.decoder)</a> |
+ .transform(const LineSplitter()) |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Get data from a stream" data-html="true" data-trigger="hover focus" data-content="Listen to a stream to get data when it becomes available.">.listen((line)</a> { |
+ if (showLineNumbers) { |
+ stdout.write('${lineNumber++} '); |
+ } |
+ stdout.writeln(line); |
+ }).asFuture().catchError((_) => _handleError(path)); |
+ }); |
+ } |
+} |
+ |
+_handleError(String path) { |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Test a path" data-html="true" data-trigger="hover focus" data-content="You can get information about the file system on which your program is running.">FileSystemEntity.isDirectory(path)</a>.then((isDir) { |
+ if (isDir) { |
+ print('error: $path is a directory'); |
+ } else { |
+ print('error: $path not found'); |
+ } |
+ }); |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Exit code" data-html="true" data-trigger="hover focus" data-content="A well-behaved command-line app sets an exit code to indicate whether the program was successful.">exitCode = 2;</a> |
+} |
+ |
+</pre> |
+ |
+## Parsing command-line arguments {#cmd-line-args} |
+ |
+The |
+<a href="https://api.dartlang.org/args.html" target="_blank">args</a> |
+package provides |
sethladd
2014/01/03 00:57:28
Are they going to know what a package is?
mem
2014/01/03 17:38:02
Done.
|
+parser support for transforming raw command-line arguments |
+into a set of options, flags, and additional values. |
+Import the library as follows: |
+ |
+{% prettify dart %} |
+import 'package:args/args.dart'; |
+{% endprettify %} |
+ |
+The args library contains two classes: |
+ |
+| Library | Description | |
+|---|---| |
+| <a href="https://api.dartlang.org/args/ArgParser" target="_blank">ArgParser</a> | A class that parses command-line arguments | |
+| <a href="https://api.dartlang.org/args/ArgResults" target="_blank">ArgResults</a> | The result of parsing command-line arguments using ArgParser. | |
+{: .table } |
+ |
+Let's take a look at the `dcat` sample, |
+which uses ArgParser and ArgResults to parse and store its command-line arguments. |
+ |
+<ol> |
+<li markdown="1"> |
+Copy the sample file from the github repo: |
+<a href="https://github.com/dart-lang/dart-tutorials-samples/blob/master/bin/dcat.dart">dcat.dart</a>. |
+</li> |
+ |
+<li markdown="1"> |
+Run the program from the command line as shown by the highlighted text. |
+ |
+{% prettify bash %} |
+$ [[highlight]]dart dcat.dart -n quotes.txt[[/highlight]] |
+1 Be yourself. Everyone else is taken. -Oscar Wilde |
+2 Don't cry because it's over, smile because it happened. -Dr. Seuss |
+3 You only live once, but if you do it right, once is enough. -Mae West |
+... |
+{% endprettify %} |
+ |
+The program displays the contents of the source code file and |
+preceeds each line with a line number. |
+</li> |
+ |
+</ol> |
+ |
+The following diagram shows how the `dcat` command line used above |
+is parsed into the `ArgResults` object. |
+ |
+ |
+ |
+You can access flags and options by name, |
+treating the ArgResults object like a Map. |
+You can access other values with properties such as `rest`. |
+ |
+Here's the code from `dcat` that deals with command-line arguments: |
+ |
+<pre class="prettyprint lang-dart"> |
+ |
+... |
+<a href="#" class="dart-popover" data-toggle="popover" title="Parsed arguments" data-html="true" data-trigger="hover focus" data-content="This object contains parsed options and flags.">ArgResults argResults;</a> |
+ |
+void main(<a href="#" class="dart-popover" data-toggle="popover" title="Command-line arguments" data-html="true" data-trigger="hover focus" data-content="The system passes command-line arguments into the program in a list of strings.">List<String> arguments</a>) { |
+ final parser = new ArgParser() |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Define a valid flag" data-html="true" data-trigger="hover focus" data-content="Add a flag definition to the command-line argument parser. This code defines the flag -n, which when used displays line numbers.">..addFlag(LINE_NUMBER, negatable: false, abbr: 'n')</a>; |
+ |
+ argResults = parser.<a href="#" class="dart-popover" data-toggle="popover" title="Parse the arguments" data-html="true" data-trigger="hover focus" data-content="Parse the arguments that were passed into the main() function. The parser stops parsing if it finds an undefined option or flag.">parse(arguments)</a>; |
+ List<String> paths = <a href="#" class="dart-popover" data-toggle="popover" title="Remaining arguments" data-html="true" data-trigger="hover focus" data-content="To get the arguments that remain after parsing all of the valid options and flags, use the rest property.">argResults.rest</a>; |
+ |
+ dcat(paths, <a href="#" class="dart-popover" data-toggle="popover" title="Refer to options and flags by name" data-html="true" data-trigger="hover focus" data-content="You can refer to an option or flag by name treating the ArgResults object like a Map.">argResults[LINE_NUMBER])</a>; |
+} |
+... |
+</pre> |
+ |
+The |
+<a href="https://api.dartlang.org/args.html" target="_blank">API docs</a> |
+for the args library |
+provide detailed information |
+to help you use ArgsParser and ArgResults classes. |
+ |
+## Reading and writing with stdin, stdout, and stderr {#std-in-out-err} |
+ |
+Like other languages, |
+Dart has standard output, standard error, and standard input streams. |
+The standard I/O streams are defined at the top level of the dart:io library, |
+which you import as follows: |
+ |
+{% prettify dart %} |
+import 'dart:io'; |
+{% endprettify %} |
+ |
+Only command-line applications, not web applications, |
+can use the dart:io library. |
+ |
+Standard output and standard error are |
+<a href="https://api.dartlang.org/dart_io/IOSink.html" target="_blank">IOSink</a>s |
+rather than streams, but can be bound to a stream. |
sethladd
2014/01/03 00:57:28
what is a stream?
mem
2014/01/03 17:38:02
Done.
|
+Standard input is a |
+<a href="https://api.dartlang.org/dart_async/Stream.html" target="_blank">Stream</a>. |
+That is, the |
+<a href="https://api.dartlang.org/dart_io/Stdin.html" target="_blank">Stdin</a> class |
+is a subclass of the Stream class. |
+ |
+| Stream | Description | |
+|---|---| |
+| <a href="https://api.dartlang.org/dart_io.html#stdout" target="_blank">stdout</a> | The standard output | |
+| <a href="https://api.dartlang.org/dart_io.html#stderr" target="_blank">stderr</a> | The standard error | |
+| <a href="https://api.dartlang.org/dart_io.html#stdin" target="_blank">stdin</a> | The standard input | |
+{: .table } |
+ |
+### stdout |
sethladd
2014/01/03 00:57:28
maybe add an aside about print(), and when to use
mem
2014/01/03 17:38:02
Done.
|
+ |
+Here's the code from the `dcat` program that writes the line number to the `stdout` |
+(if the -n flag is set) followed by the line from the file. |
+ |
+{% prettify dart %} |
+if (showLineNumbers) { |
+ [[highlight]]stdout.write('${lineNumber++} ');[[/highlight]] |
+} |
+ |
+[[highlight]]stdout.writeln(line);[[/highlight]] |
+{% endprettify %} |
+ |
+The `write()` and `writeln()` methods take an object of any type, |
+convert it to a string, and print it. The `writeln()` method |
+also prints a newline character. |
+`dcat` uses the `write()` method to print the line number so the |
+line number and the text appear on the same line. |
+ |
+You can also use the `writeAll()` method to print a list of objects, |
+or use `addStream()` to asynchronously print all of the elements from a stream. |
+ |
+### stderr |
+ |
+Use `stderr` to write error messages to the console. |
+The standard error stream has the same methods as `stdout`, |
+and you use it in the same way. |
+Although both `stdout` and `stderr` print to the console |
+their output is separate |
+and can be redirected or piped at the command line |
+or programmatically to different destinations. |
+ |
+This code from `dcat` prints an error message if the user |
+tries to list a directory or if the file is not found. |
+ |
+{% prettify dart %} |
+if (isDir) { |
+ [[highlight]]stderr.writeln('error: $path is a directory');[[/highlight]] |
+} else { |
+ [[highlight]]stderr.writeln('error: $path not found');[[/highlight]] |
+} |
+{% endprettify %} |
+ |
+### stdin |
sethladd
2014/01/03 00:57:28
I think it would be nice to bring these sub-sectio
mem
2014/01/03 17:38:02
Done.
|
+ |
+The standard input stream typically |
+reads data synchronously from the keyboard, |
+although it can read asynchronously |
+and it can get input piped in from the standard |
+output of another program. |
+ |
+Here's a small program that reads a single line from `stdin`: |
+ |
+{% prettify dart %} |
+import 'dart:io'; |
+ |
+void main() { |
+ stdout.writeln('Type something'); |
+ String input = stdin.readLineSync(); |
+ stdout.writeln('You typed: $input'); |
+} |
+{% endprettify %} |
+ |
+The `readLineSync()` method reads text from the standard input stream, |
+blocking until the user types in text and presses return. |
+This little program prints out the typed text. |
+ |
+In the `dcat` program, |
+if the user does not provide a filename on the command line, |
+the program instead reads synchronously from stdin |
+using the `pipe()` method. |
+ |
+{% prettify dart %} |
+return [[highlight]]stdin[[/highlight]].pipe(stdout); |
+{% endprettify %} |
+ |
+In this case, |
+the user types in lines of text and the program copies them to stdout. |
+The user signals the end of input by typing <ctl-d>. |
+ |
+{% prettify bash %} |
+$ [[highlight]]dart dcat.dart[[/highlight]] |
+[[highlight]]The quick brown fox jumped over the lazy dog.[[/highlight]] |
+The quick brown fox jumped over the lazy dog. |
+... |
+{% endprettify %} |
+ |
+## Getting info about a file {#filesystementity} |
+ |
+The |
+<a href="https://api.dartlang.org/dart_io/FileSystemEntity.html" target="_blank">FileSystemEntity</a> |
+class in the dart:io library provides |
+properties and static methods that help you inspect and manipulate the file system. |
+ |
+For example, if you have a path, |
+you can determine whether the path is a file, a directory, a link, or not found |
+by using the `type()` method from the `FileSystemEntity` class. |
+Because the `type()` method accesses the file system, |
+it performs the check asynchronously within a Future. |
+ |
+The following code from |
+the `dcat` example uses `FileSystemEntity` to determine if the path provided |
+on the command line is a directory. |
+The Future returns a boolean that indicates |
+if the path is a directory or not. |
+ |
+{% prettify dart %} |
+[[highlight]]FileSystemEntity.isDirectory(path)[[/highlight]].then((isDir) { |
+ if (isDir) { |
+ stderr.writeln('error: $path is a directory'); |
+ } else { |
+ stderr.writeln('error: $path not found'); |
+ } |
+ exit(2); |
+}); |
+{% endprettify %} |
+ |
+Other interesting methods in the `FileSystemEntity` class |
+include `isFile()`, `exists()`, `stat()`, `delete()`, |
+and `rename()`, |
+all of which also use a Future to return a value. |
+ |
+FileSystemEntity is the superclass for the File, Directory, and Link classes. |
+ |
+## Reading a file {#reading-a-file} |
+ |
+`dcat` opens each file listed on the command line |
+with the `openRead()` method, |
+which returns a stream. |
+The `listen()` method registers a callback function that runs |
+when data becomes available on the stream. |
+The callback function writes that data to stdout. |
+ |
+{% prettify dart %} |
+return Future.forEach(paths, (path) { |
+ int lineNumber = 1; |
+ Stream<List<int>> stream = new File(path).openRead(); |
+ |
+ return stream |
+ ... |
+ [[highlight]].listen((line) { |
+ if (showLineNumbers) { |
+ stdout.write('${lineNumber++} '); |
+ } |
+ stdout.writeln(line); |
+ })[[/highlight]].asFuture() |
+ .then((_) { exitCode = 1; }) |
+ .catchError((_) => _handleError(path)); |
+}); |
+{% endprettify %} |
+ |
+This code uses two decoders that transform the data before the |
+`listen()` callback function runs. |
+The UTF8 decoder converts the data into Dart strings. |
+`LineSplitter` splits the data at newlines. |
+ |
+{% prettify dart %} |
+return Future.forEach(paths, (path) { |
+ int lineNumber = 1; |
+ Stream<List<int>> stream = new File(path).openRead(); |
+ |
+ return stream |
+ [[highlight]].transform(UTF8.decoder) |
+ .transform(const LineSplitter())[[/highlight]] |
+ .listen((line) { |
+ if (showLineNumbers) { |
+ stdout.write('${lineNumber++} '); |
+ } |
+ stdout.writeln(line); |
+ }).asFuture() |
+ .then((_) { exitCode = 1; }) |
+ .catchError((_) => _handleError(path)); |
+}); |
+{% endprettify %} |
+ |
+The dart:convert library contains these and other data converters, including |
+one for JSON. |
+To use these converters you need to import the dart:convert library: |
+ |
+{% prettify dart %} |
+import 'dart:convert'; |
+{% endprettify %} |
+ |
+## Writing a file {#writing-a-file} |
+ |
+The easiest way to write text to a file is to |
+create a |
+<a href="https://api.dartlang.org/dart_io/File.html" target="_blank">File</a> |
+object and use the `writeAsString()` method: |
+ |
+{% prettify dart %} |
+File quotesFile = new File('quotes.txt'); |
+String stronger = 'That which does not kill us makes us stronger. -Nietzsche'; |
+ |
+quotesFile.writeAsString(stronger, mode: FileMode.APPEND) |
+ .then((_) { print('Data written.'); }); |
+{% endprettify %} |
+ |
+The `writeAsString()` method writes the data asynchronously via a Future. |
+It opens the file before writing and closes the file when done. |
+To append data to an existing file, you can use the optional |
+parameter `mode` and set its value to `FileMode.APPEND`. |
+Otherwise, the mode is `FileMode.WRITE` and the previous contents of the file, |
+if any, are overwritten. |
+ |
+If you want to write more data, you can open the file for writing. |
+The `openWrite()` method returns an IOSink (the same type as stdin and stderr). |
+You can continue to write to the file until done, |
+at which time, you must close the file. |
+The `close()` method is asynchronous and returns a Future. |
+ |
+{% prettify dart %} |
+IOSink quotes = new File('quotes.txt').openWrite(mode: FileMode.APPEND); |
+ |
+quotes.write('A woman is like a tea bag; '); |
+quotes.write("you never know how strong it is until it's in hot water."); |
+quotes.writeln(" -Eleanor Roosevelt"); |
+quotes.close().then((_) { print('done'); } ); |
+{% endprettify %} |
+ |
+## Getting environment information {#env-var} |
+ |
+Use the |
+<a href="https://api.dartlang.org/dart_io/Platform.html" target="_blank">Platform</a> |
+class |
+to get information about the machine and OS that the program is running on. |
+Note: Use the Platform class from the dart:io library, |
+not from the dart:html library. |
+ |
+The `environment` property returns a Map that contains all |
+the environment variables currently set. |
+ |
+{% prettify dart %} |
+Map environmentVars = Platform.environment; |
+ |
+print('PWD = ${environmentVars["PWD"]}'); |
+print('LOGNAME = ${environmentVars["LOGNAME"]}'); |
+print('PATH = ${environmentVars["PATH"]}'); |
+ |
+environmentVars['MEANINGOFLIFE'] = 42; // Not persistent. |
+ |
+print('MEANINGOFLIFE = ${environmentVars["MEANINGOFLIFE"]}'); |
+{% endprettify %} |
+ |
+As you can see from the code, you can change values |
+in the Map. However, these do not persist. If you refer to |
sethladd
2014/01/03 00:57:28
persist is a bit overloaded. I think this is a bug
mem
2014/01/03 17:38:02
Done.
|
+`Platform.environment` again, your changes will not be there. |
+ |
+`Platform` provides other useful properties that give |
+information about the machine, OS, and currently |
+running program. |
+For example: |
+ |
+* `Platform.isMacOS()` |
+* `Platform.numberOfProcessors` |
+* Platform.script.path |
+ |
+## Setting exit codes {#exit-codes} |
+ |
+The dart:io library defines a top-level property, |
+`exitCode`, that you can change to set the exit code for |
sethladd
2014/01/03 00:57:28
define what an exit code is
mem
2014/01/03 17:38:02
Done.
|
+the current invocation of the Dart VM. |
+ |
+The `dcat` example sets the program's exit code |
+in two different places. |
+First, at the very beginning of `main()`, |
+the program sets the exit code to 0. |
+ |
+{% prettify dart %} |
+... |
+void main(List<String> arguments) { |
+ exitCode = 0; // Presume success. |
sethladd
2014/01/03 00:57:28
weird that it sets it to zero at the beginning.
mem
2014/01/03 17:38:02
Done.
|
+ ... |
+} |
+... |
+{% endprettify %} |
+ |
+The last assignment to `exitCode` provides the final exit code for the program. |
+So, if the `dcat` program does not set the exit code again, |
+it exits with a code of 0, which indicates success. |
+ |
+Second, the program sets the error code |
+in the `_handleError()` function. |
+ |
+{% prettify dart %} |
+_handleError(String path) { |
+ FileSystemEntity.isDirectory(path).then((isDir) { |
+ if (isDir) { |
+ stderr.writeln('error: $path is a directory'); |
+ } else { |
+ stderr.writeln('error: $path not found'); |
+ } |
+ [[highlight]]exitCode = 2;[[/highlight]] |
+ }); |
+} |
+{% endprettify %} |
+ |
+An exit code of 2 indicates that the program encountered an error. |
+ |
+An alternative to using `exitCode` is to use the top-level `exit()` function, |
+which sets the exit code and quits the program immediately. |
+For example, the `_handleError()` function could call `exit(2) |
sethladd
2014/01/03 00:57:28
missing a closing `
mem
2014/01/03 17:38:02
Done.
|
+instead of setting `exitCode` to 2. |
+Generally speaking, you are better off using the `exitCode` property, |
sethladd
2014/01/03 00:57:28
make this bolder, more obvious. Do we have a "Mary
mem
2014/01/03 17:38:02
Done.
|
+which sets the exit code but allows the program to continue through to its |
+natural completion. |
+ |
+Although you can use any number for an exit code, |
+by convention, the codes in the table below have the following meanings: |
+ |
+| Code | Meaning | |
+|---|---| |
+| 0 | Success | |
+| 1 | Warnings | |
+| 2 | Errors | |
+{: .table } |
+ |
+### Another example: dgrep {#dgrep-code} |
sethladd
2014/01/03 00:57:28
I think this is the wrong header level? Too low.
sethladd
2014/01/03 00:57:28
Consider dropping this section. It doesn't provide
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
Done.
|
+ |
+Here's the code for `dgrep`, a simplified version of the Unix utility grep |
sethladd
2014/01/03 00:57:28
Again, what is grep?
mem
2014/01/03 17:38:02
Done.
mem
2014/01/03 17:38:02
Done.
|
+called `dgrep`. |
+This program makes use of some additional APIs that don't |
sethladd
2014/01/03 00:57:28
instead of "additional APIs", how about enumeratin
mem
2014/01/03 17:38:02
Done.
|
+appear in the `dcat` example. |
+ |
+<pre class="prettyprint lang-dart"> |
+import 'dart:io'; |
+import 'package:args/args.dart'; |
+ |
+const USAGE = 'usage: dart dgrep.dart [-rnS] patterns file_or_directory'; |
+const RECURSIVE = 'recursive'; |
+const LINE_NUMBER = 'line-number'; |
+const FOLLOW_LINKS = 'follow-links'; |
+ |
+ArgResults argResults; |
+ |
+void main(List<String> arguments) { |
+ final parser = new ArgParser() |
+ ..addFlag(RECURSIVE, negatable: false, abbr: 'r') |
+ ..addFlag(LINE_NUMBER, negatable: false, abbr: 'n') |
+ ..addFlag(FOLLOW_LINKS, negatable: false, abbr: 'S'); |
+ |
+ argResults = parser.parse(arguments); |
+ |
+ if (argResults.rest.length < 2) { |
+ print(USAGE); |
+ exit(1); |
+ } |
+ |
+ final searchPath = <a href="#" class="dart-popover" data-toggle="popover" title="The rest property is a List." data-html="true" data-trigger="hover focus" data-content="ArgResults.rest is a list. Use the last property to get the last command-line argument.">argResults.rest.last;</a> |
sethladd
2014/01/03 00:57:28
not that interesting, consider dropping (it's not
mem
2014/01/03 17:38:02
Done.
|
+ final searchTerms = argResults.rest.sublist(0, argResults.rest.length - 1); |
+ |
+ FileSystemEntity.isDirectory(searchPath).then((isDir) { |
+ if (isDir) { |
+ final startingDir = <a href="#" class="dart-popover" data-toggle="popover" title="Create a Directory" data-html="true" data-trigger="hover focus" data-content="Create a new Directory object at the specified path.">new Directory(searchPath);</a> |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Recursive directory search" data-html="true" data-trigger="hover focus" data-content="List a directory's subdirectories recursively and process each file within.">startingDir.list(recursive: argResults[RECURSIVE], |
+ followLinks: argResults[FOLLOW_LINKS]).listen((entity)</a> { |
+ if (entity is File) { |
+ searchFile(entity, searchTerms); |
+ } |
+ }); |
+ } else { |
+ searchFile(<a href="#" class="dart-popover" data-toggle="popover" title="Create a File" data-html="true" data-trigger="hover focus" data-content="Create a new file at the specified path.">new File(searchPath)</a>, searchTerms); |
sethladd
2014/01/03 00:57:28
This doesn't actually create a new file. I don't t
mem
2014/01/03 17:38:02
Done.
|
+ } |
+ }); |
+} |
+ |
+ |
+void printMatch(File file, List lines, int i) { |
+ StringBuffer sb = new StringBuffer(); |
+ if (argResults[RECURSIVE]) sb.write('${file.path}:'); |
+ if (argResults[LINE_NUMBER]) sb.write('${i + 1}:'); |
+ sb.write(lines[i]); |
+ print(sb.toString()); |
+} |
+ |
+searchFile(File file, searchTerms) { |
+ <a href="#" class="dart-popover" data-toggle="popover" title="Read a file as lines" data-html="true" data-trigger="hover focus" data-content="Read a file as a list of strings that contains each line separately.">file.readAsLines()</a>.then((lines) { |
+ for (var i = 0; i < lines.length; i++) { |
+ bool found = false; |
+ for (var j = 0; j < searchTerms.length && !found; j++) { |
+ if (lines[i].contains(searchTerms[j])) { |
+ printMatch(file, lines, i); |
+ found = true; |
+ } |
+ } |
+ } |
+ }).catchError(print); |
+} |
+ |
+</pre> |
+ |
+## Summary {#summary} |
+ |
+This tutorial described some basic API found in these classes from the dart:io library: |
+ |
+| API | Description | |
+|---|---| |
+| <a href="https://api.dartlang.org/dart_io/IOSink.html" target="_blank">IOSink</a> | Helper class for objects that consume data from streams. | |
+| <a href="https://api.dartlang.org/dart_io/File.html" target="_blank">File</a> | Represents a file on the native file system | |
+| <a href="https://api.dartlang.org/dart_io/Directory.html" target="_blank">Directory</a> | Represents a directory on the native file system | |
+| <a href="https://api.dartlang.org/dart_io/FileSystemEntity.html" target="_blank">FileSystemEntity</a> | Superclass for File and Directory | |
+| <a href="https://api.dartlang.org/dart_io/Platform.html" target="_blank">Platform</a> | Provides information about the machine and operating system | |
+| <a href="https://api.dartlang.org/dart_io.html#stdout" target="_blank">stdout</a> | The standard output | |
+| <a href="https://api.dartlang.org/dart_io.html#stderr" target="_blank">stderr</a> | The standard error | |
+| <a href="https://api.dartlang.org/dart_io.html#stdin" target="_blank">stdin</a> | The standard input | |
+| <a href="https://api.dartlang.org/dart_io.html#exitCode" target="_blank">exitCode</a> | Sets the exit code | |
+| <a href="https://api.dartlang.org/dart_io.html#exit" target="_blank">exit()</a> | Sets the exit code and quits | |
+{: .table } |
+ |
+In addition, this tutorial covers two classes that help with command-line arguments: |
+ |
+| Class | Description | |
+|---|---| |
+| <a href="https://api.dartlang.org/args/ArgParser" target="_blank">ArgParser</a> | A class that transforms a list of raw arguments and into a set of options, flags, and remaining values. | |
+| <a href="https://api.dartlang.org/args/ArgResults" target="_blank">ArgResults</a> | The result of parsing raw command line arguments using ArgParser. | |
+{: .table } |
+ |
+## Other resources {#other-resources} |
+ |
+See the |
+[Dartiverse Search walkthrough](/docs/dart-up-and-running/contents/ch05.html) |
+for an example of another kind of command-line app: an HTTP server. |
+ |
+Refer to the API docs for <a href="https://api.dartlang.org/dart_io.html" target="_blank">dart:io</a>, |
+<a href="https://api.dartlang.org/dart_async.html" target="_blank">dart:async</a>, |
+<a href="https://api.dartlang.org/dart_convert.html" target="_blank">dart:convert</a>, |
+and the |
+<a href="https://api.dartlang.org/dart_args.html" target="_blank">args</a> |
+package for more classes, functions, and properties. |
+ |
+## What next? {#what-next} |
+ |
+The [Get Input from a Form](/docs/tutorials/forms/) tutorial |
+features a client-server. |
+The code for the server, which uses CORS headers and handles |
+POST requests, is explained in detail. |
+ |
+{% endcapture %} |
+ |
+{% include tutorial.html %} |