| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 // out files in hidden directories. | 274 // out files in hidden directories. |
| 275 if (recursive) { | 275 if (recursive) { |
| 276 children.add(doList(new Directory(file), listedDirectories)); | 276 children.add(doList(new Directory(file), listedDirectories)); |
| 277 } | 277 } |
| 278 }; | 278 }; |
| 279 lister.onFile = (file) { | 279 lister.onFile = (file) { |
| 280 if (!includeHiddenFiles && basename(file).startsWith('.')) return; | 280 if (!includeHiddenFiles && basename(file).startsWith('.')) return; |
| 281 contents.add(join(dir, basename(file))); | 281 contents.add(join(dir, basename(file))); |
| 282 }; | 282 }; |
| 283 | 283 |
| 284 return completer.future.chain((contents) { | 284 return completer.future.then((contents) { |
| 285 return Futures.wait(children).transform((childContents) { | 285 return Futures.wait(children).then((childContents) { |
| 286 contents.addAll(flatten(childContents)); | 286 contents.addAll(flatten(childContents)); |
| 287 return contents; | 287 return contents; |
| 288 }); | 288 }); |
| 289 }); | 289 }); |
| 290 } | 290 } |
| 291 | 291 |
| 292 return doList(_getDirectory(dir), new Set<String>()); | 292 return doList(_getDirectory(dir), new Set<String>()); |
| 293 } | 293 } |
| 294 | 294 |
| 295 /// Asynchronously determines if [dir], which can be a [String] directory path | 295 /// Asynchronously determines if [dir], which can be a [String] directory path |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 /// If that future completes with an error, it will slepp and then [callback] | 339 /// If that future completes with an error, it will slepp and then [callback] |
| 340 /// will be invoked again to retry the operation. It will try a few times before | 340 /// will be invoked again to retry the operation. It will try a few times before |
| 341 /// giving up. | 341 /// giving up. |
| 342 Future _attemptRetryable(Future callback()) { | 342 Future _attemptRetryable(Future callback()) { |
| 343 // Only do lame retry logic on Windows. | 343 // Only do lame retry logic on Windows. |
| 344 if (Platform.operatingSystem != 'windows') return callback(); | 344 if (Platform.operatingSystem != 'windows') return callback(); |
| 345 | 345 |
| 346 var attempts = 0; | 346 var attempts = 0; |
| 347 makeAttempt(_) { | 347 makeAttempt(_) { |
| 348 attempts++; | 348 attempts++; |
| 349 return callback().transformException((e) { | 349 return callback().catchError((e) { |
| 350 if (attempts >= 10) { | 350 if (attempts >= 10) { |
| 351 throw 'Could not complete operation. Gave up after $attempts attempts.'; | 351 throw 'Could not complete operation. Gave up after $attempts attempts.'; |
| 352 } | 352 } |
| 353 | 353 |
| 354 // Wait a bit and try again. | 354 // Wait a bit and try again. |
| 355 log.fine("Operation failed, retrying (attempt $attempts)."); | 355 log.fine("Operation failed, retrying (attempt $attempts)."); |
| 356 return sleep(500).chain(makeAttempt); | 356 return sleep(500).then(makeAttempt); |
| 357 }); | 357 }); |
| 358 } | 358 } |
| 359 | 359 |
| 360 return makeAttempt(null); | 360 return makeAttempt(null); |
| 361 } | 361 } |
| 362 | 362 |
| 363 /// Creates a new symlink that creates an alias from [from] to [to], both of | 363 /// Creates a new symlink that creates an alias from [from] to [to], both of |
| 364 /// which can be a [String], [File], or [Directory]. Returns a [Future] which | 364 /// which can be a [String], [File], or [Directory]. Returns a [Future] which |
| 365 /// completes to the symlink file (i.e. [to]). | 365 /// completes to the symlink file (i.e. [to]). |
| 366 Future<File> createSymlink(from, to) { | 366 Future<File> createSymlink(from, to) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 | 441 |
| 442 /// Displays a message and reads a yes/no confirmation from the user. Returns | 442 /// Displays a message and reads a yes/no confirmation from the user. Returns |
| 443 /// a [Future] that completes to `true` if the user confirms or `false` if they | 443 /// a [Future] that completes to `true` if the user confirms or `false` if they |
| 444 /// do not. | 444 /// do not. |
| 445 /// | 445 /// |
| 446 /// This will automatically append " (y/n)?" to the message, so [message] | 446 /// This will automatically append " (y/n)?" to the message, so [message] |
| 447 /// should just be a fragment like, "Are you sure you want to proceed". | 447 /// should just be a fragment like, "Are you sure you want to proceed". |
| 448 Future<bool> confirm(String message) { | 448 Future<bool> confirm(String message) { |
| 449 log.fine('Showing confirm message: $message'); | 449 log.fine('Showing confirm message: $message'); |
| 450 stdout.writeString("$message (y/n)? "); | 450 stdout.writeString("$message (y/n)? "); |
| 451 return readLine().transform((line) => new RegExp(r"^[yY]").hasMatch(line)); | 451 return readLine().then((line) => new RegExp(r"^[yY]").hasMatch(line)); |
| 452 } | 452 } |
| 453 | 453 |
| 454 /// Returns a single line read from a [StringInputStream]. By default, reads | 454 /// Returns a single line read from a [StringInputStream]. By default, reads |
| 455 /// from stdin. | 455 /// from stdin. |
| 456 /// | 456 /// |
| 457 /// A [StringInputStream] passed to this should have no callbacks registered. | 457 /// A [StringInputStream] passed to this should have no callbacks registered. |
| 458 Future<String> readLine([StringInputStream stream]) { | 458 Future<String> readLine([StringInputStream stream]) { |
| 459 if (stream == null) stream = _stringStdin; | 459 if (stream == null) stream = _stringStdin; |
| 460 if (stream.closed) return new Future.immediate(''); | 460 if (stream.closed) return new Future.immediate(''); |
| 461 void removeCallbacks() { | 461 void removeCallbacks() { |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 | 691 |
| 692 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] | 692 /// Creates a temporary directory and passes its path to [fn]. Once the [Future] |
| 693 /// returned by [fn] completes, the temporary directory and all its contents | 693 /// returned by [fn] completes, the temporary directory and all its contents |
| 694 /// will be deleted. | 694 /// will be deleted. |
| 695 Future withTempDir(Future fn(String path)) { | 695 Future withTempDir(Future fn(String path)) { |
| 696 var tempDir; | 696 var tempDir; |
| 697 var future = createTempDir().then((dir) { | 697 var future = createTempDir().then((dir) { |
| 698 tempDir = dir; | 698 tempDir = dir; |
| 699 return fn(tempDir.path); | 699 return fn(tempDir.path); |
| 700 }); | 700 }); |
| 701 future.catchError((_) {}).then(_) { | 701 future.catchError((_) {}).then((_) { |
| 702 log.fine('Cleaning up temp directory ${tempDir.path}.'); | 702 log.fine('Cleaning up temp directory ${tempDir.path}.'); |
| 703 deleteDir(tempDir); | 703 deleteDir(tempDir); |
| 704 }); | 704 }); |
| 705 return future; | 705 return future; |
| 706 } | 706 } |
| 707 | 707 |
| 708 /// Tests whether or not the git command-line app is available for use. | 708 /// Tests whether or not the git command-line app is available for use. |
| 709 Future<bool> get isGitInstalled { | 709 Future<bool> get isGitInstalled { |
| 710 if (_isGitInstalledCache != null) { | 710 if (_isGitInstalledCache != null) { |
| 711 // TODO(rnystrom): The sleep is to pump the message queue. Can use | 711 // TODO(rnystrom): The sleep is to pump the message queue. Can use |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 905 | 905 |
| 906 // Note: This line of code gets munged by create_sdk.py to be the correct | 906 // Note: This line of code gets munged by create_sdk.py to be the correct |
| 907 // relative path to 7zip in the SDK. | 907 // relative path to 7zip in the SDK. |
| 908 var pathTo7zip = '../../third_party/7zip/7za.exe'; | 908 var pathTo7zip = '../../third_party/7zip/7za.exe'; |
| 909 var command = relativeToPub(pathTo7zip); | 909 var command = relativeToPub(pathTo7zip); |
| 910 | 910 |
| 911 // We're passing 'baseDir' both as '-w' and setting it as the working | 911 // We're passing 'baseDir' both as '-w' and setting it as the working |
| 912 // directory explicitly here intentionally. The former ensures that the | 912 // directory explicitly here intentionally. The former ensures that the |
| 913 // files added to the archive have the correct relative path in the archive. | 913 // files added to the archive have the correct relative path in the archive. |
| 914 // The latter enables relative paths in the "-i" args to be resolved. | 914 // The latter enables relative paths in the "-i" args to be resolved. |
| 915 return runProcess(command, args, workingDir: baseDir).chain((_) { | 915 return runProcess(command, args, workingDir: baseDir).then((_) { |
| 916 // GZIP it. 7zip doesn't support doing both as a single operation. Send | 916 // GZIP it. 7zip doesn't support doing both as a single operation. Send |
| 917 // the output to stdout. | 917 // the output to stdout. |
| 918 args = ["a", "unused", "-tgzip", "-so", tarFile]; | 918 args = ["a", "unused", "-tgzip", "-so", tarFile]; |
| 919 return startProcess(command, args); | 919 return startProcess(command, args); |
| 920 }).chain((process) { | 920 }).then((process) { |
| 921 // Drain and discard 7zip's stderr. 7zip writes its normal output to | 921 // Drain and discard 7zip's stderr. 7zip writes its normal output to |
| 922 // stderr. We don't want to show that since it's meaningless. | 922 // stderr. We don't want to show that since it's meaningless. |
| 923 // TODO(rnystrom): Should log this and display it if an actual error | 923 // TODO(rnystrom): Should log this and display it if an actual error |
| 924 // occurs. | 924 // occurs. |
| 925 consumeInputStream(process.stderr); | 925 consumeInputStream(process.stderr); |
| 926 return pipeInputToInput(process.stdout, stream); | 926 return pipeInputToInput(process.stdout, stream); |
| 927 }); | 927 }); |
| 928 }); | 928 }); |
| 929 return stream; | 929 return stream; |
| 930 } | 930 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 Directory _getDirectory(entry) { | 964 Directory _getDirectory(entry) { |
| 965 if (entry is Directory) return entry; | 965 if (entry is Directory) return entry; |
| 966 return new Directory(entry); | 966 return new Directory(entry); |
| 967 } | 967 } |
| 968 | 968 |
| 969 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. | 969 /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. |
| 970 Uri _getUri(uri) { | 970 Uri _getUri(uri) { |
| 971 if (uri is Uri) return uri; | 971 if (uri is Uri) return uri; |
| 972 return new Uri.fromString(uri); | 972 return new Uri.fromString(uri); |
| 973 } | 973 } |
| OLD | NEW |