| 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 |