Index: utils/pub/io.dart |
diff --git a/utils/pub/io.dart b/utils/pub/io.dart |
index 8b53575ac7c1fe08d53985ffb65f95955f59b9b2..cc8902c3ac46feaa997bc2d02e5f585bd01517fc 100644 |
--- a/utils/pub/io.dart |
+++ b/utils/pub/io.dart |
@@ -5,6 +5,7 @@ |
/// Helper functionality to make working with IO easier. |
library io; |
+import 'dart:async'; |
import 'dart:io'; |
import 'dart:isolate'; |
import 'dart:json'; |
@@ -26,7 +27,7 @@ final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); |
/// [File] objects. |
String join(part1, [part2, part3, part4, part5, part6, part7, part8]) { |
var parts = [part1, part2, part3, part4, part5, part6, part7, part8] |
- .map((part) => part == null ? null : _getPath(part)); |
+ .mappedBy((part) => part == null ? null : _getPath(part)).toList(); |
return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], |
parts[6], parts[7]); |
@@ -58,7 +59,7 @@ String relativeTo(target, base) => path.relative(target, from: base); |
/// completes with the result. |
Future<bool> exists(path) { |
path = _getPath(path); |
- return Futures.wait([fileExists(path), dirExists(path)]).transform((results) { |
+ return Futures.wait([fileExists(path), dirExists(path)]).then((results) { |
return results[0] || results[1]; |
}); |
} |
@@ -103,9 +104,9 @@ Future<File> writeTextFile(file, String contents, {dontLogContents: false}) { |
log.fine("Contents:\n$contents"); |
} |
- return file.open(FileMode.WRITE).chain((opened) { |
- return opened.writeString(contents).chain((ignore) { |
- return opened.close().transform((_) { |
+ return file.open(FileMode.WRITE).then((opened) { |
+ return opened.writeString(contents).then((ignore) { |
+ return opened.close().then((_) { |
log.fine("Wrote text file $path."); |
return file; |
}); |
@@ -177,29 +178,25 @@ Future<Directory> ensureDir(path) { |
log.fine("Ensuring directory $path exists."); |
if (path == '.') return new Future.immediate(new Directory('.')); |
- return dirExists(path).chain((exists) { |
+ return dirExists(path).then((exists) { |
if (exists) { |
log.fine("Directory $path already exists."); |
return new Future.immediate(new Directory(path)); |
} |
- return ensureDir(dirname(path)).chain((_) { |
- var completer = new Completer<Directory>(); |
- var future = createDir(path); |
- future.handleException((error) { |
- if (error is! DirectoryIOException) return false; |
- // Error 17 means the directory already exists (or 183 on Windows). |
- if (error.osError.errorCode != 17 && |
- error.osError.errorCode != 183) { |
+ return ensureDir(dirname(path)).then((_) { |
+ return createDir(path) |
+ .catchError((error) { |
+ if (error is! DirectoryIOException) return false; |
+ // Error 17 means the directory already exists (or 183 on Windows). |
+ if (error.osError.errorCode != 17 && |
+ error.osError.errorCode != 183) { |
log.fine("Got 'already exists' error when creating directory."); |
return false; |
} |
- completer.complete(_getDirectory(path)); |
- return true; |
- }); |
- future.then(completer.complete); |
- return completer.future; |
+ return _getDirectory(path); |
+ }); |
}); |
}); |
} |
@@ -310,10 +307,10 @@ Future<bool> dirExists(dir) { |
/// new empty directory will be created. Returns a [Future] that completes when |
/// the new clean directory is created. |
Future<Directory> cleanDir(dir) { |
- return dirExists(dir).chain((exists) { |
+ return dirExists(dir).then((exists) { |
if (exists) { |
// Delete it first. |
- return deleteDir(dir).chain((_) => createDir(dir)); |
+ return deleteDir(dir).then((_) => createDir(dir)); |
} else { |
// Just create it. |
return createDir(dir); |
@@ -327,7 +324,7 @@ Future<Directory> renameDir(from, String to) { |
from = _getDirectory(from); |
log.io("Renaming directory ${from.path} to $to."); |
- return _attemptRetryable(() => from.rename(to)).transform((dir) { |
+ return _attemptRetryable(() => from.rename(to)).then((dir) { |
log.fine("Renamed directory ${from.path} to $to."); |
return dir; |
}); |
@@ -385,7 +382,7 @@ Future<File> createSymlink(from, to) { |
args = ['/j', to, from]; |
} |
- return runProcess(command, args).transform((result) { |
+ return runProcess(command, args).then((result) { |
// TODO(rnystrom): Check exit code and output? |
return new File(to); |
}); |
@@ -400,7 +397,7 @@ Future<File> createPackageSymlink(String name, from, to, |
{bool isSelfLink: false}) { |
// See if the package has a "lib" directory. |
from = join(from, 'lib'); |
- return dirExists(from).chain((exists) { |
+ return dirExists(from).then((exists) { |
log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'."); |
if (exists) return createSymlink(from, to); |
@@ -582,7 +579,7 @@ InputStream wrapInputStream(InputStream source) { |
Future<PubProcessResult> runProcess(String executable, List<String> args, |
{workingDir, Map<String, String> environment}) { |
return _doProcess(Process.run, executable, args, workingDir, environment) |
- .transform((result) { |
+ .then((result) { |
// TODO(rnystrom): Remove this and change to returning one string. |
List<String> toLines(String output) { |
var lines = output.split(NEWLINE_PATTERN); |
@@ -608,7 +605,7 @@ Future<PubProcessResult> runProcess(String executable, List<String> args, |
Future<Process> startProcess(String executable, List<String> args, |
{workingDir, Map<String, String> environment}) => |
_doProcess(Process.start, executable, args, workingDir, environment) |
- .transform((process) => new _WrappedProcess(process)); |
+ .then((process) => new _WrappedProcess(process)); |
/// A wrapper around [Process] that buffers the stdout and stderr to avoid |
/// running into issue 7218. |
@@ -671,23 +668,24 @@ Future _doProcess(Function fn, String executable, List<String> args, workingDir, |
/// Note that timing out will not cancel the asynchronous operation behind |
/// [input]. |
Future timeout(Future input, int milliseconds, String description) { |
+ bool completed = false; |
var completer = new Completer(); |
var timer = new Timer(milliseconds, (_) { |
- if (completer.future.isComplete) return; |
- completer.completeException(new TimeoutException( |
+ completer = true; |
+ completer.completeError(new TimeoutException( |
'Timed out while $description.')); |
}); |
- input.handleException((e) { |
- if (completer.future.isComplete) return false; |
- timer.cancel(); |
- completer.completeException(e, input.stackTrace); |
- return true; |
- }); |
- input.then((value) { |
- if (completer.future.isComplete) return; |
- timer.cancel(); |
- completer.complete(value); |
- }); |
+ input |
+ .then((value) { |
+ if (completed) return; |
+ timer.cancel(); |
+ completer.complete(value); |
+ }) |
+ .catchError((e) { |
+ if (completed) return; |
+ timer.cancel(); |
+ completer.completeError(e.error, e.stackTrace); |
+ }); |
return completer.future; |
} |
@@ -696,11 +694,11 @@ Future timeout(Future input, int milliseconds, String description) { |
/// will be deleted. |
Future withTempDir(Future fn(String path)) { |
var tempDir; |
- var future = createTempDir().chain((dir) { |
+ var future = createTempDir().then((dir) { |
tempDir = dir; |
return fn(tempDir.path); |
}); |
- future.onComplete((_) { |
+ future.catchError((_) {}).then(_) { |
log.fine('Cleaning up temp directory ${tempDir.path}.'); |
deleteDir(tempDir); |
}); |
@@ -712,16 +710,16 @@ Future<bool> get isGitInstalled { |
if (_isGitInstalledCache != null) { |
// TODO(rnystrom): The sleep is to pump the message queue. Can use |
// Future.immediate() when #3356 is fixed. |
- return sleep(0).transform((_) => _isGitInstalledCache); |
+ return sleep(0).then((_) => _isGitInstalledCache); |
} |
- return _gitCommand.transform((git) => git != null); |
+ return _gitCommand.then((git) => git != null); |
} |
/// Run a git process with [args] from [workingDir]. |
Future<PubProcessResult> runGit(List<String> args, |
{String workingDir, Map<String, String> environment}) { |
- return _gitCommand.chain((git) => runProcess(git, args, |
+ return _gitCommand.then((git) => runProcess(git, args, |
workingDir: workingDir, environment: environment)); |
} |
@@ -730,18 +728,18 @@ Future<PubProcessResult> runGit(List<String> args, |
Future<String> get _gitCommand { |
// TODO(nweiz): Just use Future.immediate once issue 3356 is fixed. |
if (_gitCommandCache != null) { |
- return sleep(0).transform((_) => _gitCommandCache); |
+ return sleep(0).then((_) => _gitCommandCache); |
} |
- return _tryGitCommand("git").chain((success) { |
+ return _tryGitCommand("git").then((success) { |
if (success) return new Future.immediate("git"); |
// Git is sometimes installed on Windows as `git.cmd` |
- return _tryGitCommand("git.cmd").transform((success) { |
+ return _tryGitCommand("git.cmd").then((success) { |
if (success) return "git.cmd"; |
return null; |
}); |
- }).transform((command) { |
+ }).then((command) { |
_gitCommandCache = command; |
return command; |
}); |
@@ -758,12 +756,9 @@ Future<bool> _tryGitCommand(String command) { |
var regex = new RegExp("^git version"); |
completer.complete(results.stdout.length == 1 && |
regex.hasMatch(results.stdout[0])); |
- }); |
- |
- future.handleException((err) { |
+ }).catchError((err) { |
// If the process failed, they probably don't have it. |
completer.complete(false); |
- return true; |
}); |
return completer.future; |
@@ -788,13 +783,11 @@ Future<bool> extractTarGz(InputStream stream, destination) { |
stream.pipe(process.stdin); |
process.stdout.pipe(stdout, close: false); |
process.stderr.pipe(stderr, close: false); |
- }); |
- processFuture.handleException((error) { |
- completer.completeException(error, processFuture.stackTrace); |
- return true; |
+ }).catchError((e) { |
+ completer.completeError(e.error, e.stackTrace); |
}); |
- return completer.future.transform((exitCode) { |
+ return completer.future.then((exitCode) { |
log.fine("Extracted .tar.gz stream to $destination. Exit code $exitCode."); |
// TODO(rnystrom): Does anything check this result value? If not, it should |
// throw on a bad exit code. |
@@ -818,17 +811,17 @@ Future<bool> _extractTarGzWindows(InputStream stream, String destination) { |
var tempDir; |
// TODO(rnystrom): Use withTempDir(). |
- return createTempDir().chain((temp) { |
+ return createTempDir().then((temp) { |
// Write the archive to a temp file. |
tempDir = temp; |
return createFileFromStream(stream, join(tempDir, 'data.tar.gz')); |
- }).chain((_) { |
+ }).then((_) { |
// 7zip can't unarchive from gzip -> tar -> destination all in one step |
// first we un-gzip it to a tar file. |
// Note: Setting the working directory instead of passing in a full file |
// path because 7zip says "A full path is not allowed here." |
return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir); |
- }).chain((result) { |
+ }).then((result) { |
if (result.exitCode != 0) { |
throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n' |
'${Strings.join(result.stdout, "\n")}\n' |
@@ -836,7 +829,7 @@ Future<bool> _extractTarGzWindows(InputStream stream, String destination) { |
} |
// Find the tar file we just created since we don't know its name. |
return listDir(tempDir); |
- }).chain((files) { |
+ }).then((files) { |
var tarFile; |
for (var file in files) { |
if (path.extension(file) == '.tar') { |
@@ -849,7 +842,7 @@ Future<bool> _extractTarGzWindows(InputStream stream, String destination) { |
// Untar the archive into the destination directory. |
return runProcess(command, ['x', tarFile], workingDir: destination); |
- }).chain((result) { |
+ }).then((result) { |
if (result.exitCode != 0) { |
throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n' |
'${Strings.join(result.stdout, "\n")}\n' |
@@ -859,7 +852,7 @@ Future<bool> _extractTarGzWindows(InputStream stream, String destination) { |
log.fine('Clean up 7zip temp directory ${tempDir.path}.'); |
// TODO(rnystrom): Should also delete this if anything fails. |
return deleteDir(tempDir); |
- }).transform((_) => true); |
+ }).then((_) => true); |
} |
/// Create a .tar.gz archive from a list of entries. Each entry can be a |
@@ -878,17 +871,17 @@ InputStream createTarGz(List contents, {baseDir}) { |
if (baseDir == null) baseDir = path.current; |
baseDir = getFullPath(baseDir); |
- contents = contents.map((entry) { |
+ contents = contents.mappedBy((entry) { |
entry = getFullPath(entry); |
if (!isBeneath(entry, baseDir)) { |
throw 'Entry $entry is not inside $baseDir.'; |
} |
return relativeTo(entry, baseDir); |
- }); |
+ }).toList(); |
if (Platform.operatingSystem != "windows") { |
var args = ["--create", "--gzip", "--directory", baseDir]; |
- args.addAll(contents.map(_getPath)); |
+ args.addAll(contents.mappedBy(_getPath)); |
// TODO(nweiz): It's possible that enough command-line arguments will make |
// the process choke, so at some point we should save the arguments to a |
// file and pass them in via --files-from for tar and -i@filename for 7zip. |
@@ -908,7 +901,7 @@ InputStream createTarGz(List contents, {baseDir}) { |
// Create the tar file. |
var tarFile = join(tempDir, "intermediate.tar"); |
var args = ["a", "-w$baseDir", tarFile]; |
- args.addAll(contents.map((entry) => '-i!"$entry"')); |
+ args.addAll(contents.mappedBy((entry) => '-i!"$entry"')); |
// Note: This line of code gets munged by create_sdk.py to be the correct |
// relative path to 7zip in the SDK. |