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 |