OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Helper functionality to make working with IO easier. | 5 /// Helper functionality to make working with IO easier. |
6 library io; | 6 library io; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 import 'dart:isolate'; | 10 import 'dart:isolate'; |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 var utilDir = path.dirname(scriptPath); | 272 var utilDir = path.dirname(scriptPath); |
273 while (path.basename(utilDir) != 'utils' && | 273 while (path.basename(utilDir) != 'utils' && |
274 path.basename(utilDir) != 'util') { | 274 path.basename(utilDir) != 'util') { |
275 if (path.basename(utilDir) == '') throw 'Could not find path to pub.'; | 275 if (path.basename(utilDir) == '') throw 'Could not find path to pub.'; |
276 utilDir = path.dirname(utilDir); | 276 utilDir = path.dirname(utilDir); |
277 } | 277 } |
278 | 278 |
279 return path.normalize(path.join(utilDir, 'pub', target)); | 279 return path.normalize(path.join(utilDir, 'pub', target)); |
280 } | 280 } |
281 | 281 |
282 // TODO(nweiz): add a ByteSink wrapper to make writing strings to stdout/stderr | |
283 // nicer. | |
284 | |
285 /// A sink that writes to standard output. Errors piped to this stream will be | |
286 /// surfaced to the top-level error handler. | |
287 // TODO: Unrequired wrapper, stdout is now an EventSink<List<int>>. | |
288 final EventSink<List<int>> stdoutSink = _wrapStdio(stdout, "stdout"); | |
289 | |
290 /// A sink that writes to standard error. Errors piped to this stream will be | |
291 /// surfaced to the top-level error handler. | |
292 // TODO: Unrequired wrapper, stdout is now an EventSink<List<int>>. | |
293 final EventSink<List<int>> stderrSink = _wrapStdio(stderr, "stderr"); | |
294 | |
295 /// Wrap the standard output or error [stream] in a [EventSink]. Any errors are | |
296 /// logged, and then the program is terminated. [name] is used for debugging. | |
297 EventSink<List<int>> _wrapStdio(IOSink sink, String name) { | |
298 var pair = consumerToSink(sink); | |
299 pair.last.catchError((e) { | |
300 // This log may or may not work, depending on how the stream failed. Not | |
301 // much we can do about that. | |
302 log.error("Error writing to $name", e); | |
303 exit(exit_codes.IO); | |
304 }); | |
305 return pair.first; | |
306 } | |
307 | |
308 /// A line-by-line stream of standard input. | 282 /// A line-by-line stream of standard input. |
309 final Stream<String> stdinLines = streamToLines( | 283 final Stream<String> stdinLines = streamToLines( |
310 new ByteStream(stdin).toStringStream()); | 284 new ByteStream(stdin).toStringStream()); |
311 | 285 |
312 /// Displays a message and reads a yes/no confirmation from the user. Returns | 286 /// Displays a message and reads a yes/no confirmation from the user. Returns |
313 /// a [Future] that completes to `true` if the user confirms or `false` if they | 287 /// a [Future] that completes to `true` if the user confirms or `false` if they |
314 /// do not. | 288 /// do not. |
315 /// | 289 /// |
316 /// This will automatically append " (y/n)?" to the message, so [message] | 290 /// This will automatically append " (y/n)?" to the message, so [message] |
317 /// should just be a fragment like, "Are you sure you want to proceed". | 291 /// should just be a fragment like, "Are you sure you want to proceed". |
318 Future<bool> confirm(String message) { | 292 Future<bool> confirm(String message) { |
319 log.fine('Showing confirm message: $message'); | 293 log.fine('Showing confirm message: $message'); |
320 stdoutSink.add("$message (y/n)? ".codeUnits); | 294 stdout.write("$message (y/n)? "); |
321 return streamFirst(stdinLines) | 295 return streamFirst(stdinLines) |
322 .then((line) => new RegExp(r"^[yY]").hasMatch(line)); | 296 .then((line) => new RegExp(r"^[yY]").hasMatch(line)); |
323 } | 297 } |
324 | 298 |
325 /// Reads and discards all output from [stream]. Returns a [Future] that | 299 /// Reads and discards all output from [stream]. Returns a [Future] that |
326 /// completes when the stream is closed. | 300 /// completes when the stream is closed. |
327 Future drainStream(Stream stream) { | 301 Future drainStream(Stream stream) { |
328 return stream.fold(null, (x, y) {}); | 302 return stream.fold(null, (x, y) {}); |
329 } | 303 } |
330 | 304 |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 | 538 |
565 if (Platform.operatingSystem == "windows") { | 539 if (Platform.operatingSystem == "windows") { |
566 return _extractTarGzWindows(stream, destination); | 540 return _extractTarGzWindows(stream, destination); |
567 } | 541 } |
568 | 542 |
569 return startProcess("tar", | 543 return startProcess("tar", |
570 ["--extract", "--gunzip", "--directory", destination]).then((process) { | 544 ["--extract", "--gunzip", "--directory", destination]).then((process) { |
571 // Ignore errors on process.std{out,err}. They'll be passed to | 545 // Ignore errors on process.std{out,err}. They'll be passed to |
572 // process.exitCode, and we don't want them being top-levelled by | 546 // process.exitCode, and we don't want them being top-levelled by |
573 // std{out,err}Sink. | 547 // std{out,err}Sink. |
574 store(process.stdout.handleError((_) {}), stdoutSink, closeSink: false); | 548 store(process.stdout.handleError((_) {}), stdout, closeSink: false); |
575 store(process.stderr.handleError((_) {}), stderrSink, closeSink: false); | 549 store(process.stderr.handleError((_) {}), stderr, closeSink: false); |
576 return Future.wait([ | 550 return Future.wait([ |
577 store(stream, process.stdin), | 551 store(stream, process.stdin), |
578 process.exitCode | 552 process.exitCode |
579 ]); | 553 ]); |
580 }).then((results) { | 554 }).then((results) { |
581 var exitCode = results[1]; | 555 var exitCode = results[1]; |
582 if (exitCode != 0) { | 556 if (exitCode != 0) { |
583 throw "Failed to extract .tar.gz stream to $destination (exit code " | 557 throw "Failed to extract .tar.gz stream to $destination (exit code " |
584 "$exitCode)."; | 558 "$exitCode)."; |
585 } | 559 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 const PubProcessResult(this.stdout, this.stderr, this.exitCode); | 705 const PubProcessResult(this.stdout, this.stderr, this.exitCode); |
732 | 706 |
733 bool get success => exitCode == 0; | 707 bool get success => exitCode == 0; |
734 } | 708 } |
735 | 709 |
736 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 710 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
737 Uri _getUri(uri) { | 711 Uri _getUri(uri) { |
738 if (uri is Uri) return uri; | 712 if (uri is Uri) return uri; |
739 return Uri.parse(uri); | 713 return Uri.parse(uri); |
740 } | 714 } |
OLD | NEW |