From bd5f259b3b60a5fc58b70025c8c6867dd40fa586 Mon Sep 17 00:00:00 2001 From: "floitsch@google.com" <floitsch@google.com> Date: Mon, 7 Jan 2013 11:23:16 +0000 Subject: [PATCH] Big merge from experimental to bleeding edge. Review URL: https://codereview.chromium.org//11783009 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge@16687 260f80e4-7a28-3924-810f-c04153c831b5 --- lib/src/command_install.dart | 4 +- lib/src/command_lish.dart | 16 +-- lib/src/command_update.dart | 3 +- lib/src/curl_client.dart | 9 +- lib/src/entrypoint.dart | 75 +++++++------- lib/src/git.dart | 38 +++---- lib/src/git_source.dart | 31 +++--- lib/src/hosted_source.dart | 21 ++-- lib/src/io.dart | 127 ++++++++++++------------ lib/src/lock_file.dart | 4 +- lib/src/log.dart | 2 +- lib/src/oauth2.dart | 8 +- lib/src/package.dart | 5 +- lib/src/pub.dart | 36 +++---- lib/src/pubspec.dart | 4 +- lib/src/sdk_source.dart | 15 +-- lib/src/source.dart | 11 ++- lib/src/system_cache.dart | 5 +- lib/src/utils.dart | 37 ++++--- lib/src/validator.dart | 11 ++- lib/src/validator/directory.dart | 4 +- lib/src/validator/lib.dart | 4 +- lib/src/validator/license.dart | 4 +- lib/src/validator/name.dart | 2 +- lib/src/version.dart | 14 +-- lib/src/version_solver.dart | 36 +++---- lib/src/yaml/composer.dart | 10 +- lib/src/yaml/model.dart | 10 +- lib/src/yaml/parser.dart | 2 +- lib/src/yaml/visitor.dart | 3 +- lib/src/yaml/yaml.dart | 5 +- lib/src/yaml/yaml_map.dart | 8 +- test/curl_client_test.dart | 30 +++--- test/oauth2_test.dart | 6 +- test/pub_lish_test.dart | 4 +- test/test_pub.dart | 163 +++++++++++++++---------------- test/version_solver_test.dart | 7 +- test/yaml_test.dart | 6 +- 38 files changed, 394 insertions(+), 386 deletions(-) diff --git a/lib/src/command_install.dart b/lib/src/command_install.dart index 22637554..001ba21c 100644 --- a/lib/src/command_install.dart +++ b/lib/src/command_install.dart @@ -4,6 +4,8 @@ library command_install; +import 'dart:async'; + import 'entrypoint.dart'; import 'log.dart' as log; import 'pub.dart'; @@ -14,7 +16,7 @@ class InstallCommand extends PubCommand { String get usage => "pub install"; Future onRun() { - return entrypoint.installDependencies().transform((_) { + return entrypoint.installDependencies().then((_) { log.message("Dependencies installed!"); }); } diff --git a/lib/src/command_lish.dart b/lib/src/command_lish.dart index 5afe32ff..01136fda 100644 --- a/lib/src/command_lish.dart +++ b/lib/src/command_lish.dart @@ -63,12 +63,12 @@ class LishCommand extends PubCommand { request.files.add(new http.MultipartFile.fromBytes( 'file', packageBytes, filename: 'package.tar.gz')); return client.send(request); - }).chain(http.Response.fromStream).transform((response) { + }).chain(http.Response.fromStream).then((response) { var location = response.headers['location']; if (location == null) throw new PubHttpException(response); return location; - }).chain((location) => client.get(location)) - .transform(handleJsonSuccess); + }).then((location) => client.get(location)) + .then(handleJsonSuccess); }).transformException((e) { if (e is! PubHttpException) throw e; var url = e.response.request.url; @@ -126,8 +126,8 @@ class LishCommand extends PubCommand { } return listDir(rootDir, recursive: true).chain((entries) { - return Futures.wait(entries.map((entry) { - return fileExists(entry).transform((isFile) { + return Futures.wait(entries.mappedBy((entry) { + return fileExists(entry).then((isFile) { // Skip directories. if (!isFile) return null; @@ -140,13 +140,13 @@ class LishCommand extends PubCommand { }); })); }); - }).transform((files) => files.filter((file) { + }).then((files) => files.where((file) { if (file == null || _BLACKLISTED_FILES.contains(basename(file))) { return false; } return !splitPath(file).some(_BLACKLISTED_DIRECTORIES.contains); - })); + }).toList()); } /// Returns the value associated with [key] in [map]. Throws a user-friendly @@ -176,7 +176,7 @@ class LishCommand extends PubCommand { message = "Package has ${warnings.length} warning$s. Upload anyway"; } - return confirm(message).transform((confirmed) { + return confirm(message).then((confirmed) { if (!confirmed) throw "Package upload canceled."; }); }); diff --git a/lib/src/command_update.dart b/lib/src/command_update.dart index 1dda303e..4757049c 100644 --- a/lib/src/command_update.dart +++ b/lib/src/command_update.dart @@ -4,6 +4,7 @@ library command_update; +import 'dart:async'; import 'entrypoint.dart'; import 'log.dart' as log; import 'pub.dart'; @@ -22,6 +23,6 @@ class UpdateCommand extends PubCommand { } else { future = entrypoint.updateDependencies(commandOptions.rest); } - return future.transform((_) => log.message("Dependencies updated!")); + return future.then((_) => log.message("Dependencies updated!")); } } diff --git a/lib/src/curl_client.dart b/lib/src/curl_client.dart index 6922b828..7361b09a 100644 --- a/lib/src/curl_client.dart +++ b/lib/src/curl_client.dart @@ -4,6 +4,7 @@ library curl_client; +import 'dart:async'; import 'dart:io'; import '../../pkg/http/lib/http.dart' as http; @@ -39,7 +40,7 @@ class CurlClient extends http.BaseClient { var arguments = _argumentsForRequest(request, headerFile); log.process(executable, arguments); var process; - return startProcess(executable, arguments).chain((process_) { + return startProcess(executable, arguments).then((process_) { process = process_; if (requestStream.closed) { process.stdin.close(); @@ -48,8 +49,8 @@ class CurlClient extends http.BaseClient { } return _waitForHeaders(process, expectBody: request.method != "HEAD"); - }).chain((_) => new File(headerFile).readAsLines()) - .transform((lines) => _buildResponse(request, process, lines)); + }).then((_) => new File(headerFile).readAsLines()) + .then((lines) => _buildResponse(request, process, lines)); }); } @@ -126,7 +127,7 @@ class CurlClient extends http.BaseClient { } chainToCompleter(consumeInputStream(process.stderr) - .transform((stderrBytes) { + .then((stderrBytes) { var message = new String.fromCharCodes(stderrBytes); log.fine('Got error reading headers from curl: $message'); if (exitCode == 47) { diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart index b52a139e..457d480f 100644 --- a/lib/src/entrypoint.dart +++ b/lib/src/entrypoint.dart @@ -4,6 +4,7 @@ library entrypoint; +import 'dart:async'; import 'io.dart'; import 'lock_file.dart'; import 'log.dart' as log; @@ -46,7 +47,7 @@ class Entrypoint { /// Loads the entrypoint from a package at [rootDir]. static Future<Entrypoint> load(String rootDir, SystemCache cache) { - return Package.load(null, rootDir, cache.sources).transform((package) => + return Package.load(null, rootDir, cache.sources).then((package) => new Entrypoint(package, cache)); } @@ -70,26 +71,26 @@ class Entrypoint { if (pendingOrCompleted != null) return pendingOrCompleted; var packageDir = join(path, id.name); - var future = ensureDir(dirname(packageDir)).chain((_) { + var future = ensureDir(dirname(packageDir)).then((_) { return exists(packageDir); - }).chain((exists) { + }).then((exists) { if (!exists) return new Future.immediate(null); // TODO(nweiz): figure out when to actually delete the directory, and when // we can just re-use the existing symlink. log.fine("Deleting package directory for ${id.name} before install."); return deleteDir(packageDir); - }).chain((_) { + }).then((_) { if (id.source.shouldCache) { - return cache.install(id).chain( + return cache.install(id).then( (pkg) => createPackageSymlink(id.name, pkg.dir, packageDir)); } else { - return id.source.install(id, packageDir).transform((found) { + return id.source.install(id, packageDir).then((found) { if (found) return null; // TODO(nweiz): More robust error-handling. throw 'Package ${id.name} not found in source "${id.source.name}".'; }); } - }).chain((_) => id.resolved); + }).then((_) => id.resolved); _installs[id] = future; @@ -101,8 +102,8 @@ class Entrypoint { /// completes when all dependencies are installed. Future installDependencies() { return loadLockFile() - .chain((lockFile) => resolveVersions(cache.sources, root, lockFile)) - .chain(_installDependencies); + .then((lockFile) => resolveVersions(cache.sources, root, lockFile)) + .then(_installDependencies); } /// Installs the latest available versions of all dependencies of the [root] @@ -110,33 +111,33 @@ class Entrypoint { /// [Future] that completes when all dependencies are installed. Future updateAllDependencies() { return resolveVersions(cache.sources, root, new LockFile.empty()) - .chain(_installDependencies); + .then(_installDependencies); } /// Installs the latest available versions of [dependencies], while leaving /// other dependencies as specified by the [LockFile] if possible. Returns a /// [Future] that completes when all dependencies are installed. Future updateDependencies(List<String> dependencies) { - return loadLockFile().chain((lockFile) { + return loadLockFile().then((lockFile) { var versionSolver = new VersionSolver(cache.sources, root, lockFile); for (var dependency in dependencies) { versionSolver.useLatestVersion(dependency); } return versionSolver.solve(); - }).chain(_installDependencies); + }).then(_installDependencies); } /// Removes the old packages directory, installs all dependencies listed in /// [packageVersions], and writes a [LockFile]. Future _installDependencies(List<PackageId> packageVersions) { - return cleanDir(path).chain((_) { - return Futures.wait(packageVersions.map((id) { + return cleanDir(path).then((_) { + return Futures.wait(packageVersions.mappedBy((id) { if (id.source is RootSource) return new Future.immediate(id); return install(id); })); - }).chain(_saveLockFile) - .chain(_installSelfReference) - .chain(_linkSecondaryPackageDirs); + }).then(_saveLockFile) + .then(_installSelfReference) + .then(_linkSecondaryPackageDirs); } /// Loads the list of concrete package versions from the `pubspec.lock`, if it @@ -145,13 +146,13 @@ class Entrypoint { var lockFilePath = join(root.dir, 'pubspec.lock'); log.fine("Loading lockfile."); - return fileExists(lockFilePath).chain((exists) { + return fileExists(lockFilePath).then((exists) { if (!exists) { log.fine("No lock file at $lockFilePath, creating empty one."); return new Future<LockFile>.immediate(new LockFile.empty()); } - return readTextFile(lockFilePath).transform((text) => + return readTextFile(lockFilePath).then((text) => new LockFile.parse(text, cache.sources)); }); } @@ -172,10 +173,10 @@ class Entrypoint { /// allow a package to import its own files using `package:`. Future _installSelfReference(_) { var linkPath = join(path, root.name); - return exists(linkPath).chain((exists) { + return exists(linkPath).then((exists) { // Create the symlink if it doesn't exist. if (exists) return new Future.immediate(null); - return ensureDir(path).chain( + return ensureDir(path).then( (_) => createPackageSymlink(root.name, root.dir, linkPath, isSelfLink: true)); }); @@ -190,25 +191,25 @@ class Entrypoint { var testDir = join(root.dir, 'test'); var toolDir = join(root.dir, 'tool'); var webDir = join(root.dir, 'web'); - return dirExists(binDir).chain((exists) { + return dirExists(binDir).then((exists) { if (!exists) return new Future.immediate(null); return _linkSecondaryPackageDir(binDir); - }).chain((_) => _linkSecondaryPackageDirsRecursively(exampleDir)) - .chain((_) => _linkSecondaryPackageDirsRecursively(testDir)) - .chain((_) => _linkSecondaryPackageDirsRecursively(toolDir)) - .chain((_) => _linkSecondaryPackageDirsRecursively(webDir)); + }).then((_) => _linkSecondaryPackageDirsRecursively(exampleDir)) + .then((_) => _linkSecondaryPackageDirsRecursively(testDir)) + .then((_) => _linkSecondaryPackageDirsRecursively(toolDir)) + .then((_) => _linkSecondaryPackageDirsRecursively(webDir)); } /// Creates a symlink to the `packages` directory in [dir] and all its /// subdirectories. Future _linkSecondaryPackageDirsRecursively(String dir) { - return dirExists(dir).chain((exists) { + return dirExists(dir).then((exists) { if (!exists) return new Future.immediate(null); return _linkSecondaryPackageDir(dir) - .chain((_) => _listDirWithoutPackages(dir)) - .chain((files) { - return Futures.wait(files.map((file) { - return dirExists(file).chain((isDir) { + .then((_) => _listDirWithoutPackages(dir)) + .then((files) { + return Futures.wait(files.mappedBy((file) { + return dirExists(file).then((isDir) { if (!isDir) return new Future.immediate(null); return _linkSecondaryPackageDir(file); }); @@ -221,25 +222,25 @@ class Entrypoint { /// Recursively lists the contents of [dir], excluding hidden `.DS_Store` /// files and `package` files. Future<List<String>> _listDirWithoutPackages(dir) { - return listDir(dir).chain((files) { - return Futures.wait(files.map((file) { + return listDir(dir).then((files) { + return Futures.wait(files.mappedBy((file) { if (basename(file) == 'packages') return new Future.immediate([]); - return dirExists(file).chain((isDir) { + return dirExists(file).then((isDir) { if (!isDir) return new Future.immediate([]); return _listDirWithoutPackages(file); - }).transform((subfiles) { + }).then((subfiles) { var fileAndSubfiles = [file]; fileAndSubfiles.addAll(subfiles); return fileAndSubfiles; }); })); - }).transform(flatten); + }).then(flatten); } /// Creates a symlink to the `packages` directory in [dir] if none exists. Future _linkSecondaryPackageDir(String dir) { var to = join(dir, 'packages'); - return exists(to).chain((exists) { + return exists(to).then((exists) { if (exists) return new Future.immediate(null); return createSymlink(path, to); }); diff --git a/lib/src/git.dart b/lib/src/git.dart index b216735f..df2e8565 100644 --- a/lib/src/git.dart +++ b/lib/src/git.dart @@ -5,6 +5,7 @@ /// Helper functionality for invoking Git. library git; +import 'dart:async'; import 'io.dart'; import 'log.dart' as log; import 'utils.dart'; @@ -14,18 +15,18 @@ Future<bool> get isInstalled { 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]. Returns the stdout as a /// list of strings if it succeeded. Completes to an exception if it failed. Future<List<String>> run(List<String> args, {String workingDir}) { - return _gitCommand.chain((git) { + return _gitCommand.then((git) { return runProcess(git, args, workingDir: workingDir); - }).transform((result) { + }).then((result) { if (!result.success) throw new Exception( 'Git error. Command: git ${Strings.join(args, " ")}\n' '${Strings.join(result.stderr, "\n")}'); @@ -44,18 +45,18 @@ String _gitCommandCache; 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) { log.fine('Determined git command $command.'); _gitCommandCache = command; return command; @@ -69,17 +70,16 @@ Future<bool> _tryGitCommand(String command) { // If "git --version" prints something familiar, git is working. var future = runProcess(command, ["--version"]); - future.then((results) { - var regex = new RegExp("^git version"); - completer.complete(results.stdout.length == 1 && - regex.hasMatch(results.stdout[0])); - }); - - future.handleException((err) { - // If the process failed, they probably don't have it. - completer.complete(false); - return true; - }); + future + .then((results) { + var regex = new RegExp("^git version"); + completer.complete(results.stdout.length == 1 && + regex.hasMatch(results.stdout[0])); + }) + .catchError((err) { + // If the process failed, they probably don't have it. + completer.complete(false); + }); return completer.future; } diff --git a/lib/src/git_source.dart b/lib/src/git_source.dart index e54b6cf1..0a3e2b97 100644 --- a/lib/src/git_source.dart +++ b/lib/src/git_source.dart @@ -4,6 +4,7 @@ library git_source; +import 'dart:async'; import 'git.dart' as git; import 'io.dart'; import 'package.dart'; @@ -34,7 +35,7 @@ class GitSource extends Source { Future<Package> installToSystemCache(PackageId id) { var revisionCachePath; - return git.isInstalled.chain((installed) { + return git.isInstalled.then((installed) { if (!installed) { throw new Exception( "Cannot install '${id.name}' from Git (${_getUrl(id)}).\n" @@ -42,19 +43,19 @@ class GitSource extends Source { } return ensureDir(join(systemCacheRoot, 'cache')); - }).chain((_) => _ensureRepoCache(id)) - .chain((_) => _revisionCachePath(id)) - .chain((path) { + }).then((_) => _ensureRepoCache(id)) + .then((_) => _revisionCachePath(id)) + .then((path) { revisionCachePath = path; return exists(revisionCachePath); - }).chain((exists) { + }).then((exists) { if (exists) return new Future.immediate(null); return _clone(_repoCachePath(id), revisionCachePath, mirror: false); - }).chain((_) { + }).then((_) { var ref = _getEffectiveRef(id); if (ref == 'HEAD') return new Future.immediate(null); return _checkOut(revisionCachePath, ref); - }).chain((_) { + }).then((_) { return Package.load(id.name, revisionCachePath, systemCache.sources); }); } @@ -91,7 +92,7 @@ class GitSource extends Source { /// Attaches a specific commit to [id] to disambiguate it. Future<PackageId> resolveId(PackageId id) { - return _revisionAt(id).transform((revision) { + return _revisionAt(id).then((revision) { var description = {'url': _getUrl(id), 'ref': _getRef(id)}; description['resolved-ref'] = revision; return new PackageId(id.name, this, id.version, description); @@ -104,22 +105,22 @@ class GitSource extends Source { /// fails. Future _ensureRepoCache(PackageId id) { var path = _repoCachePath(id); - return exists(path).chain((exists) { + return exists(path).then((exists) { if (!exists) return _clone(_getUrl(id), path, mirror: true); - return git.run(["fetch"], workingDir: path).transform((result) => null); + return git.run(["fetch"], workingDir: path).then((result) => null); }); } /// Returns a future that completes to the revision hash of [id]. Future<String> _revisionAt(PackageId id) { return git.run(["rev-parse", _getEffectiveRef(id)], - workingDir: _repoCachePath(id)).transform((result) => result[0]); + workingDir: _repoCachePath(id)).then((result) => result[0]); } /// Returns the path to the revision-specific cache of [id]. Future<String> _revisionCachePath(PackageId id) { - return _revisionAt(id).transform((rev) { + return _revisionAt(id).then((rev) { var revisionCacheName = '${id.name}-$rev'; return join(systemCacheRoot, revisionCacheName); }); @@ -134,16 +135,16 @@ class GitSource extends Source { Future _clone(String from, String to, {bool mirror: false}) { // Git on Windows does not seem to automatically create the destination // directory. - return ensureDir(to).chain((_) { + return ensureDir(to).then((_) { var args = ["clone", from, to]; if (mirror) args.insertRange(1, 1, "--mirror"); return git.run(args); - }).transform((result) => null); + }).then((result) => null); } /// Checks out the reference [ref] in [repoPath]. Future _checkOut(String repoPath, String ref) { - return git.run(["checkout", ref], workingDir: repoPath).transform( + return git.run(["checkout", ref], workingDir: repoPath).then( (result) => null); } diff --git a/lib/src/hosted_source.dart b/lib/src/hosted_source.dart index 4b515aca..45867e5f 100644 --- a/lib/src/hosted_source.dart +++ b/lib/src/hosted_source.dart @@ -4,8 +4,9 @@ library hosted_source; +import 'dart:async'; import 'dart:io' as io; -import 'dart:json'; +import 'dart:json' as json; import 'dart:uri'; // TODO(nweiz): Make this import better. @@ -35,9 +36,11 @@ class HostedSource extends Source { var parsed = _parseDescription(description); var fullUrl = "${parsed.last}/packages/${parsed.first}.json"; - return httpClient.read(fullUrl).transform((body) { - var doc = JSON.parse(body); - return doc['versions'].map((version) => new Version.parse(version)); + return httpClient.read(fullUrl).then((body) { + var doc = json.parse(body); + return doc['versions'] + .mappedBy((version) => new Version.parse(version)) + .toList(); }).transformException((ex) { _throwFriendlyError(ex, parsed.first, parsed.last); }); @@ -50,7 +53,7 @@ class HostedSource extends Source { var fullUrl = "${parsed.last}/packages/${parsed.first}/versions/" "${id.version}.yaml"; - return httpClient.read(fullUrl).transform((yaml) { + return httpClient.read(fullUrl).then((yaml) { return new Pubspec.parse(yaml, systemCache.sources); }).transformException((ex) { _throwFriendlyError(ex, id, parsed.last); @@ -71,18 +74,18 @@ class HostedSource extends Source { var tempDir; return Futures.wait([ httpClient.send(new http.Request("GET", new Uri.fromString(fullUrl))) - .transform((response) => response.stream), + .then((response) => response.stream), systemCache.createTempDir() - ]).chain((args) { + ]).then((args) { tempDir = args[1]; return timeout(extractTarGz(args[0], tempDir), HTTP_TIMEOUT, 'fetching URL "$fullUrl"'); - }).chain((_) { + }).then((_) { // Now that the install has succeeded, move it to the real location in // the cache. This ensures that we don't leave half-busted ghost // directories in the user's pub cache if an install fails. return renameDir(tempDir, destPath); - }).transform((_) => true); + }).then((_) => true); } /// The system cache directory for the hosted source contains subdirectories diff --git a/lib/src/io.dart b/lib/src/io.dart index 8b53575a..cc8902c3 100644 --- a/lib/src/io.dart +++ b/lib/src/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. diff --git a/lib/src/lock_file.dart b/lib/src/lock_file.dart index 80036b84..1e975852 100644 --- a/lib/src/lock_file.dart +++ b/lib/src/lock_file.dart @@ -4,7 +4,7 @@ library lock_file; -import 'dart:json'; +import 'dart:json' as json; import 'package.dart'; import 'source_registry.dart'; import 'utils.dart'; @@ -85,6 +85,6 @@ class LockFile { // TODO(nweiz): Serialize using the YAML library once it supports // serialization. For now, we use JSON, since it's a subset of YAML anyway. - return JSON.stringify({'packages': packagesObj}); + return json.stringify({'packages': packagesObj}); } } diff --git a/lib/src/log.dart b/lib/src/log.dart index 029f72cf..683c4a26 100644 --- a/lib/src/log.dart +++ b/lib/src/log.dart @@ -97,7 +97,7 @@ Future ioAsync(String startMessage, Future operation, io(startMessage); } - return operation.transform((result) { + return operation.then((result) { if (endMessage == null) { io("End $startMessage."); } else { diff --git a/lib/src/oauth2.dart b/lib/src/oauth2.dart index 378614b3..786ff35e 100644 --- a/lib/src/oauth2.dart +++ b/lib/src/oauth2.dart @@ -108,7 +108,7 @@ Future<Client> _getClient(SystemCache cache) { return new Future.immediate(new Client( _identifier, _secret, credentials, httpClient: curlClient)); }).chain((client) { - return _saveCredentials(cache, client.credentials).transform((_) => client); + return _saveCredentials(cache, client.credentials).then((_) => client); }); } @@ -130,7 +130,7 @@ Future<Credentials> _loadCredentials(SystemCache cache) { return new Future.immediate(null); } - return readTextFile(_credentialsFile(cache)).transform((credentialsJson) { + return readTextFile(_credentialsFile(cache)).then((credentialsJson) { var credentials = new Credentials.fromJson(credentialsJson); if (credentials.isExpired && !credentials.canRefresh) { log.error("Pub's authorization to upload packages has expired and " @@ -194,7 +194,7 @@ Future<Client> _authorize() { response.headers.set('location', 'http://pub.dartlang.org/authorized'); response.outputStream.close(); return grant.handleAuthorizationResponse(queryToMap(queryString)); - }).transform((client) { + }).then((client) { server.close(); return client; }), completer); @@ -210,7 +210,7 @@ Future<Client> _authorize() { 'Then click "Allow access".\n\n' 'Waiting for your authorization...'); - return completer.future.transform((client) { + return completer.future.then((client) { log.message('Successfully authorized.\n'); return client; }); diff --git a/lib/src/package.dart b/lib/src/package.dart index 69b54834..70f469c0 100644 --- a/lib/src/package.dart +++ b/lib/src/package.dart @@ -4,6 +4,7 @@ library package; +import 'dart:async'; import 'io.dart'; import 'pubspec.dart'; import 'source.dart'; @@ -19,10 +20,10 @@ class Package { SourceRegistry sources) { var pubspecPath = join(packageDir, 'pubspec.yaml'); - return fileExists(pubspecPath).chain((exists) { + return fileExists(pubspecPath).then((exists) { if (!exists) throw new PubspecNotFoundException(name); return readTextFile(pubspecPath); - }).transform((contents) { + }).then((contents) { try { var pubspec = new Pubspec.parse(contents, sources); diff --git a/lib/src/pub.dart b/lib/src/pub.dart index 6fcecd95..1a8642e7 100644 --- a/lib/src/pub.dart +++ b/lib/src/pub.dart @@ -5,6 +5,7 @@ /// The main entrypoint for the pub command line application. library pub; +import 'dart:async'; import '../../pkg/args/lib/args.dart'; import '../../pkg/path/lib/path.dart' as path; import 'dart:io'; @@ -244,7 +245,7 @@ abstract class PubCommand { future = Entrypoint.load(path.current, cache); } - future = future.chain((entrypoint) { + future = future.then((entrypoint) { this.entrypoint = entrypoint; try { var commandFuture = onRun(); @@ -257,23 +258,24 @@ abstract class PubCommand { } }); - future = future.chain((_) => cache_.deleteTempDir()); - future.handleException((e) { - if (e is PubspecNotFoundException && e.name == null) { - e = 'Could not find a file named "pubspec.yaml" in the directory ' - '${path.current}.'; - } else if (e is PubspecHasNoNameException && e.name == null) { - e = 'pubspec.yaml is missing the required "name" field (e.g. "name: ' - '${basename(path.current)}").'; - } - - handleError(e, future.stackTrace); - }); - - // Explicitly exit on success to ensure that any dangling dart:io handles - // don't cause the process to never terminate. - future.then((_) => exit(0)); + future + .then((_) => cache_.deleteTempDir()) + .catchError((error) { + var e = error.error; + if (e is PubspecNotFoundException && e.name == null) { + e = 'Could not find a file named "pubspec.yaml" in the directory ' + '${path.current}.'; + } else if (e is PubspecHasNoNameException && e.name == null) { + e = 'pubspec.yaml is missing the required "name" field (e.g. "name: ' + '${basename(path.current)}").'; + } + + handleError(e, error.stackTrace); + }) + // Explicitly exit on success to ensure that any dangling dart:io handles + // don't cause the process to never terminate. + .then((_) => exit(0)); } /// Override this to perform the specific command. Return a future that diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart index 8a1931dc..078b7e05 100644 --- a/lib/src/pubspec.dart +++ b/lib/src/pubspec.dart @@ -133,7 +133,7 @@ List<PackageRef> _parseDependencies(SourceRegistry sources, yaml) { // Allow an empty dependencies key. if (yaml == null) return dependencies; - if (yaml is! Map || yaml.keys.some((e) => e is! String)) { + if (yaml is! Map || yaml.keys.any((e) => e is! String)) { throw new FormatException( 'The pubspec dependencies should be a map of package names, but ' 'was ${yaml}.'); @@ -154,7 +154,7 @@ List<PackageRef> _parseDependencies(SourceRegistry sources, yaml) { versionConstraint = new VersionConstraint.parse(spec.remove('version')); } - var sourceNames = spec.keys; + var sourceNames = spec.keys.toList(); if (sourceNames.length > 1) { throw new FormatException( 'Dependency $name may only have one source: $sourceNames.'); diff --git a/lib/src/sdk_source.dart b/lib/src/sdk_source.dart index 654043a2..13ffa252 100644 --- a/lib/src/sdk_source.dart +++ b/lib/src/sdk_source.dart @@ -4,6 +4,7 @@ library sdk_source; +import 'dart:async'; import 'io.dart'; import 'package.dart'; import 'pubspec.dart'; @@ -30,14 +31,14 @@ class SdkSource extends Source { /// inferred from the revision number of the SDK itself. Future<Pubspec> describe(PackageId id) { var version; - return readTextFile(join(rootDir, "revision")).chain((revision) { + return readTextFile(join(rootDir, "revision")).then((revision) { version = new Version.parse("0.0.0-r.${revision.trim()}"); // Read the pubspec for the package's dependencies. return _getPackagePath(id); - }).chain((packageDir) { + }).then((packageDir) { // TODO(rnystrom): What if packageDir is null? return Package.load(id.name, packageDir, systemCache.sources); - }).transform((package) { + }).then((package) { // Ignore the pubspec's version, and use the SDK's. return new Pubspec(id.name, version, package.pubspec.dependencies); }); @@ -46,10 +47,10 @@ class SdkSource extends Source { /// Since all the SDK files are already available locally, installation just /// involves symlinking the SDK library into the packages directory. Future<bool> install(PackageId id, String destPath) { - return _getPackagePath(id).chain((path) { + return _getPackagePath(id).then((path) { if (path == null) return new Future<bool>.immediate(false); - return createPackageSymlink(id.name, path, destPath).transform( + return createPackageSymlink(id.name, path, destPath).then( (_) => true); }); } @@ -60,14 +61,14 @@ class SdkSource extends Source { Future<String> _getPackagePath(PackageId id) { // Look in "pkg" first. var pkgPath = join(rootDir, "pkg", id.description); - return exists(pkgPath).chain((found) { + return exists(pkgPath).then((found) { if (found) return new Future<String>.immediate(pkgPath); // Not in "pkg", so try "lib". // TODO(rnystrom): Get rid of this when all SDK packages are moved from // "lib" to "pkg". var libPath = join(rootDir, "lib", id.description); - return exists(libPath).transform((found) => found ? libPath : null); + return exists(libPath).then((found) => found ? libPath : null); }); } } diff --git a/lib/src/source.dart b/lib/src/source.dart index 637cdd69..211f0dba 100644 --- a/lib/src/source.dart +++ b/lib/src/source.dart @@ -4,6 +4,7 @@ library source; +import 'dart:async'; import 'io.dart'; import 'package.dart'; import 'pubspec.dart'; @@ -64,7 +65,7 @@ abstract class Source { /// uses [describe] to get that version. Future<List<Version>> getVersions(String name, description) { return describe(new PackageId(name, this, Version.none, description)) - .transform((pubspec) => [pubspec.version]); + .then((pubspec) => [pubspec.version]); } /// Loads the (possibly remote) pubspec for the package version identified by @@ -76,7 +77,7 @@ abstract class Source { /// must implement it manually. Future<Pubspec> describe(PackageId id) { if (!shouldCache) throw "Source $name must implement describe(id)."; - return installToSystemCache(id).transform((package) => package.pubspec); + return installToSystemCache(id).then((package) => package.pubspec); } /// Installs the package identified by [id] to [path]. Returns a [Future] that @@ -104,10 +105,10 @@ abstract class Source { /// By default, this uses [systemCacheDirectory] and [install]. Future<Package> installToSystemCache(PackageId id) { var path = systemCacheDirectory(id); - return exists(path).chain((exists) { + return exists(path).then((exists) { if (exists) return new Future<bool>.immediate(true); - return ensureDir(dirname(path)).chain((_) => install(id, path)); - }).chain((found) { + return ensureDir(dirname(path)).then((_) => install(id, path)); + }).then((found) { if (!found) throw 'Package $id not found.'; return Package.load(id.name, path, systemCache.sources); }); diff --git a/lib/src/system_cache.dart b/lib/src/system_cache.dart index abd23482..5b00dc30 100644 --- a/lib/src/system_cache.dart +++ b/lib/src/system_cache.dart @@ -5,6 +5,7 @@ library system_cache; import 'dart:io'; +import 'dart:async'; import 'git_source.dart'; import 'hosted_source.dart'; @@ -83,7 +84,7 @@ class SystemCache { /// temp directory to ensure that it's on the same volume as the pub system /// cache so that it can move the directory from it. Future<Directory> createTempDir() { - return ensureDir(tempDir).chain((temp) { + return ensureDir(tempDir).then((temp) { return io.createTempDir(join(temp, 'dir')); }); } @@ -91,7 +92,7 @@ class SystemCache { /// Delete's the system cache's internal temp directory. Future deleteTempDir() { log.fine('Clean up system cache temp directory $tempDir.'); - return dirExists(tempDir).chain((exists) { + return dirExists(tempDir).then((exists) { if (!exists) return new Future.immediate(null); return deleteDir(tempDir); }); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 557e67de..b922d845 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -5,6 +5,7 @@ /// Generic utility functions. Stuff that should possibly be in core. library utils; +import 'dart:async'; import 'dart:crypto'; import 'dart:isolate'; import 'dart:uri'; @@ -42,17 +43,12 @@ String padRight(String source, int length) { /// Runs [fn] after [future] completes, whether it completes successfully or /// not. Essentially an asynchronous `finally` block. always(Future future, fn()) { - var completer = new Completer(); - future.then((_) => fn()); - future.handleException((_) { - fn(); - return false; - }); + future.catchError((_) {}).then((_) => fn()); } -/// Flattens nested collections into a single list containing only non-list -/// elements. -List flatten(Collection nested) { +/// Flattens nested lists inside an iterable into a single list containing only +/// non-list elements. +List flatten(Iterable nested) { var result = []; helper(list) { for (var element in list) { @@ -69,10 +65,11 @@ List flatten(Collection nested) { /// Asserts that [iter] contains only one element, and returns it. only(Iterable iter) { - var iterator = iter.iterator(); - assert(iterator.hasNext); - var obj = iterator.next(); - assert(!iterator.hasNext); + var iterator = iter.iterator; + var currentIsValid = iterator.moveNext(); + assert(currentIsValid); + var obj = iterator.current; + assert(!iterator.moveNext()); return obj; } @@ -108,7 +105,7 @@ bool endsWithPattern(String str, Pattern matcher) { /// Returns the hex-encoded sha1 hash of [source]. String sha1(String source) => - CryptoUtils.bytesToHex(new SHA1().update(source.charCodes).digest()); + CryptoUtils.bytesToHex(new SHA1().add(source.charCodes).close()); /// Returns a [Future] that completes in [milliseconds]. Future sleep(int milliseconds) { @@ -120,11 +117,11 @@ Future sleep(int milliseconds) { /// Configures [future] so that its result (success or exception) is passed on /// to [completer]. void chainToCompleter(Future future, Completer completer) { - future.handleException((e) { - completer.completeException(e, future.stackTrace); - return true; - }); - future.then(completer.complete); + future + .then(completer.complete) + .catchError((e) { + completer.completeError(e.error, e.stackTrace); + }); } // TODO(nweiz): unify the following functions with the utility functions in @@ -171,7 +168,7 @@ String mapToQuery(Map<String, String> map) { value = (value == null || value.isEmpty) ? null : encodeUriComponent(value); pairs.add([key, value]); }); - return Strings.join(pairs.map((pair) { + return Strings.join(pairs.mappedBy((pair) { if (pair[1] == null) return pair[0]; return "${pair[0]}=${pair[1]}"; }), "&"); diff --git a/lib/src/validator.dart b/lib/src/validator.dart index 63a2386c..70f5a9ff 100644 --- a/lib/src/validator.dart +++ b/lib/src/validator.dart @@ -55,10 +55,13 @@ abstract class Validator { // 3356, which causes a bug if all validators are (synchronously) using // Future.immediate and an error is thrown before a handler is set up. return sleep(0).chain((_) { - return Futures.wait(validators.map((validator) => validator.validate())); - }).transform((_) { - var errors = flatten(validators.map((validator) => validator.errors)); - var warnings = flatten(validators.map((validator) => validator.warnings)); + return Futures.wait( + validators.mappedBy((validator) => validator.validate())); + }).then((_) { + var errors = + flatten(validators.mappedBy((validator) => validator.errors)); + var warnings = + flatten(validators.mappedBy((validator) => validator.warnings)); if (!errors.isEmpty) { log.error("Missing requirements:"); diff --git a/lib/src/validator/directory.dart b/lib/src/validator/directory.dart index 07ad933c..80568bab 100644 --- a/lib/src/validator/directory.dart +++ b/lib/src/validator/directory.dart @@ -17,8 +17,8 @@ class DirectoryValidator extends Validator { Future validate() { return listDir(entrypoint.root.dir).chain((dirs) { - return Futures.wait(dirs.map((dir) { - return dirExists(dir).transform((exists) { + return Futures.wait(dirs.mappedBy((dir) { + return dirExists(dir).then((exists) { if (!exists) return; dir = basename(dir); diff --git a/lib/src/validator/lib.dart b/lib/src/validator/lib.dart index b0dfbe5e..6afeb88f 100644 --- a/lib/src/validator/lib.dart +++ b/lib/src/validator/lib.dart @@ -29,8 +29,8 @@ class LibValidator extends Validator { return new Future.immediate(null); } - return listDir(libDir).transform((files) { - files = files.map((file) => relativeTo(file, libDir)); + return listDir(libDir).then((files) { + files = files.mappedBy((file) => relativeTo(file, libDir)).toList(); if (files.isEmpty) { errors.add('You must have a non-empty "lib" directory.\n' "Without that, users cannot import any code from your package."); diff --git a/lib/src/validator/license.dart b/lib/src/validator/license.dart index fcc6a49c..066ffbba 100644 --- a/lib/src/validator/license.dart +++ b/lib/src/validator/license.dart @@ -15,10 +15,10 @@ class LicenseValidator extends Validator { : super(entrypoint); Future validate() { - return listDir(entrypoint.root.dir).transform((files) { + return listDir(entrypoint.root.dir).then((files) { var licenseLike = new RegExp( r"^([a-zA-Z0-9]+[-_])?(LICENSE|COPYING)(\..*)?$"); - if (files.map(basename).some(licenseLike.hasMatch)) return; + if (files.mappedBy(basename).any(licenseLike.hasMatch)) return; errors.add( "You must have a COPYING or LICENSE file in the root directory.\n" diff --git a/lib/src/validator/name.dart b/lib/src/validator/name.dart index 3d467c57..8d9e93df 100644 --- a/lib/src/validator/name.dart +++ b/lib/src/validator/name.dart @@ -49,7 +49,7 @@ class NameValidator extends Validator { return dirExists(libDir).chain((libDirExists) { if (!libDirExists) return new Future.immediate([]); return listDir(libDir, recursive: true); - }).transform((files) { + }).then((files) { return files.map((file) => relativeTo(file, dirname(libDir))) .filter((file) { return !splitPath(file).contains("src") && diff --git a/lib/src/version.dart b/lib/src/version.dart index f60ad19c..e7ca3d12 100644 --- a/lib/src/version.dart +++ b/lib/src/version.dart @@ -57,9 +57,9 @@ class Version implements Comparable, VersionConstraint { } try { - int major = parseInt(match[1]); - int minor = parseInt(match[2]); - int patch = parseInt(match[3]); + int major = int.parse(match[1]); + int minor = int.parse(match[2]); + int patch = int.parse(match[3]); String preRelease = match[5]; String build = match[8]; @@ -190,14 +190,14 @@ class Version implements Comparable, VersionConstraint { /// Splits a string of dot-delimited identifiers into their component parts. /// Identifiers that are numeric are converted to numbers. List _splitParts(String text) { - return text.split('.').map((part) { + return text.split('.').mappedBy((part) { try { - return parseInt(part); + return int.parse(part); } on FormatException catch (ex) { // Not a number. return part; } - }); + }).toList(); } } @@ -241,7 +241,7 @@ abstract class VersionConstraint { /// allow. If constraints is empty, then it returns a VersionConstraint that /// allows all versions. factory VersionConstraint.intersection( - Collection<VersionConstraint> constraints) { + Iterable<VersionConstraint> constraints) { var constraint = new VersionRange(); for (var other in constraints) { constraint = constraint.intersect(other); diff --git a/lib/src/version_solver.dart b/lib/src/version_solver.dart index a4b70f89..f277169f 100644 --- a/lib/src/version_solver.dart +++ b/lib/src/version_solver.dart @@ -35,7 +35,8 @@ /// the beginning again. library version_solver; -import 'dart:json'; +import 'dart:async'; +import 'dart:json' as json; import 'dart:math'; import 'lock_file.dart'; import 'log.dart' as log; @@ -116,7 +117,7 @@ class VersionSolver { // If we have an async operation to perform, chain the loop to resume // when it's done. Otherwise, just loop synchronously. if (future != null) { - return future.chain(processNextWorkItem); + return future.then(processNextWorkItem); } } } @@ -143,7 +144,7 @@ class VersionSolver { /// Returns the most recent version of [dependency] that satisfies all of its /// version constraints. Future<Version> getBestVersion(Dependency dependency) { - return dependency.getVersions().transform((versions) { + return dependency.getVersions().then((versions) { var best = null; for (var version in versions) { if (dependency.useLatestVersion || @@ -189,12 +190,12 @@ class VersionSolver { } } - return dependency.dependers.map(getDependency).some((subdependency) => + return dependency.dependers.mappedBy(getDependency).any((subdependency) => tryUnlockDepender(subdependency, seen)); } List<PackageId> buildResults() { - return _packages.values.filter((dep) => dep.isDependedOn).map((dep) { + return _packages.values.where((dep) => dep.isDependedOn).mappedBy((dep) { var description = dep.description; // If the lockfile contains a fully-resolved description for the package, @@ -208,7 +209,8 @@ class VersionSolver { } return new PackageId(dep.name, dep.source, dep.version, description); - }); + }) + .toList(); } } @@ -254,7 +256,7 @@ class ChangeVersion implements WorkItem { // them both and update any constraints that differ between the two. return Futures.wait([ getDependencyRefs(solver, oldVersion), - getDependencyRefs(solver, version)]).transform((list) { + getDependencyRefs(solver, version)]).then((list) { var oldDependencyRefs = list[0]; var newDependencyRefs = list[1]; @@ -289,7 +291,7 @@ class ChangeVersion implements WorkItem { } var id = new PackageId(package, source, version, description); - return solver._pubspecs.load(id).transform((pubspec) { + return solver._pubspecs.load(id).then((pubspec) { var dependencies = <String, PackageRef>{}; for (var dependency in pubspec.dependencies) { dependencies[dependency.name] = dependency; @@ -364,7 +366,7 @@ abstract class ChangeConstraint implements WorkItem { // The constraint has changed, so see what the best version of the package // that meets the new constraint is. - return solver.getBestVersion(newDependency).transform((best) { + return solver.getBestVersion(newDependency).then((best) { if (best == null) { undo(solver); } else if (newDependency.version != best) { @@ -438,7 +440,7 @@ class UnlockPackage implements WorkItem { log.fine("Unlocking ${package.name}."); solver.lockFile.packages.remove(package.name); - return solver.getBestVersion(package).transform((best) { + return solver.getBestVersion(package).then((best) { if (best == null) return null; solver.enqueue(new ChangeVersion( package.name, package.source, package.description, best)); @@ -470,7 +472,7 @@ class PubspecCache { return new Future<Pubspec>.immediate(_pubspecs[id]); } - return id.describe().transform((pubspec) { + return id.describe().then((pubspec) { // Cache it. _pubspecs[id] = pubspec; return pubspec; @@ -500,7 +502,7 @@ class Dependency { bool get isDependedOn => !_refs.isEmpty; /// The names of all the packages that depend on this dependency. - Collection<String> get dependers => _refs.keys; + Iterable<String> get dependers => _refs.keys; /// Gets the overall constraint that all packages are placing on this one. /// If no packages have a constraint on this one (which can happen when this @@ -508,7 +510,7 @@ class Dependency { VersionConstraint get constraint { if (_refs.isEmpty) return null; return new VersionConstraint.intersection( - _refs.values.map((ref) => ref.constraint)); + _refs.values.mappedBy((ref) => ref.constraint)); } /// The source of this dependency's package. @@ -535,7 +537,7 @@ class Dependency { for (var ref in refs) { if (ref is RootSource) return ref; } - return refs[0]; + return refs.first; } Dependency(this.name) @@ -576,7 +578,7 @@ class Dependency { String _requiredDepender() { if (_refs.isEmpty) return null; - var dependers = _refs.keys; + var dependers = _refs.keys.toList(); if (dependers.length == 1) { var depender = dependers[0]; if (_refs[depender].source is RootSource) return null; @@ -700,8 +702,8 @@ class DescriptionMismatchException implements Exception { // TODO(nweiz): Dump descriptions to YAML when that's supported. return "Incompatible dependencies on '$package':\n" "- '$depender1' depends on it with description " - "${JSON.stringify(description1)}\n" + "${json.stringify(description1)}\n" "- '$depender2' depends on it with description " - "${JSON.stringify(description2)}"; + "${json.stringify(description2)}"; } } diff --git a/lib/src/yaml/composer.dart b/lib/src/yaml/composer.dart index 79aa2741..e9c18796 100644 --- a/lib/src/yaml/composer.dart +++ b/lib/src/yaml/composer.dart @@ -115,7 +115,7 @@ class _Composer extends _Visitor { var match = new RegExp("^[-+]?[0-9]+\$").firstMatch(content); if (match != null) { return new _ScalarNode(_Tag.yaml("int"), - value: Math.parseInt(match.group(0))); + value: int.parse(match.group(0))); } match = new RegExp("^0o([0-7]+)\$").firstMatch(content); @@ -132,7 +132,7 @@ class _Composer extends _Visitor { match = new RegExp("^0x[0-9a-fA-F]+\$").firstMatch(content); if (match != null) { return new _ScalarNode(_Tag.yaml("int"), - value: Math.parseInt(match.group(0))); + value: int.parse(match.group(0))); } return null; @@ -148,20 +148,20 @@ class _Composer extends _Visitor { // floats by removing the trailing dot. var matchStr = match.group(0).replaceAll(new RegExp(r"\.$"), ""); return new _ScalarNode(_Tag.yaml("float"), - value: Math.parseDouble(matchStr)); + value: double.parse(matchStr)); } match = new RegExp("^([+-]?)\.(inf|Inf|INF)\$").firstMatch(content); if (match != null) { var infinityStr = match.group(1) == "-" ? "-Infinity" : "Infinity"; return new _ScalarNode(_Tag.yaml("float"), - value: Math.parseDouble(infinityStr)); + value: double.parse(infinityStr)); } match = new RegExp("^\.(nan|NaN|NAN)\$").firstMatch(content); if (match != null) { return new _ScalarNode(_Tag.yaml("float"), - value: Math.parseDouble("NaN")); + value: double.parse("NaN")); } return null; diff --git a/lib/src/yaml/model.dart b/lib/src/yaml/model.dart index 57bf202b..8c111afe 100644 --- a/lib/src/yaml/model.dart +++ b/lib/src/yaml/model.dart @@ -90,7 +90,8 @@ class _SequenceNode extends _Node { return true; } - String toString() => '$tag [${Strings.join(content.map((e) => '$e'), ', ')}]'; + String toString() => + '$tag [${Strings.join(content.mappedBy((e) => '$e'), ', ')}]'; int get hashCode => super.hashCode ^ _hashCode(content); @@ -149,7 +150,7 @@ class _ScalarNode extends _Node { // TODO(nweiz): This could be faster if we used a RegExp to check for // special characters and short-circuited if they didn't exist. - var escapedValue = value.charCodes.map((c) { + var escapedValue = value.charCodes.mappedBy((c) { switch (c) { case _Parser.TAB: return "\\t"; case _Parser.LF: return "\\n"; @@ -221,8 +222,9 @@ class _MappingNode extends _Node { } String toString() { - var strContent = Strings.join(content.keys. - map((k) => '${k}: ${content[k]}'), ', '); + var strContent = content.keys + .mappedBy((k) => '${k}: ${content[k]}') + .join(', '); return '$tag {$strContent}'; } diff --git a/lib/src/yaml/parser.dart b/lib/src/yaml/parser.dart index 8652ff45..f2f255e7 100644 --- a/lib/src/yaml/parser.dart +++ b/lib/src/yaml/parser.dart @@ -633,7 +633,7 @@ class _Parser { if (!captureAs('', () => consumeChar(char))) return false; var captured = captureAndTransform( () => nAtOnce(digits, (c, _) => isHexDigit(c)), - (hex) => new String.fromCharCodes([Math.parseInt("0x$hex")])); + (hex) => new String.fromCharCodes([int.parse("0x$hex")])); return expect(captured, "$digits hexidecimal digits"); } diff --git a/lib/src/yaml/visitor.dart b/lib/src/yaml/visitor.dart index 1d6282ae..b5c14c94 100644 --- a/lib/src/yaml/visitor.dart +++ b/lib/src/yaml/visitor.dart @@ -13,7 +13,8 @@ class _Visitor { visitScalar(_ScalarNode scalar) => scalar; /// Visits each node in [seq] and returns a list of the results. - visitSequence(_SequenceNode seq) => seq.content.map((e) => e.visit(this)); + visitSequence(_SequenceNode seq) + => seq.content.mappedBy((e) => e.visit(this)).toList(); /// Visits each key and value in [map] and returns a map of the results. visitMapping(_MappingNode map) { diff --git a/lib/src/yaml/yaml.dart b/lib/src/yaml/yaml.dart index 11984c34..6ce890cc 100644 --- a/lib/src/yaml/yaml.dart +++ b/lib/src/yaml/yaml.dart @@ -39,8 +39,9 @@ loadYaml(String yaml) { /// are YamlMaps. These have a few small behavioral differences from the default /// Map implementation; for details, see the YamlMap class. List loadYamlStream(String yaml) { - return new _Parser(yaml).l_yamlStream().map((doc) => - new _Constructor(new _Composer(doc).compose()).construct()); + return new _Parser(yaml).l_yamlStream().mappedBy((doc) => + new _Constructor(new _Composer(doc).compose()).construct()) + .toList(); } /// An error thrown by the YAML processor. diff --git a/lib/src/yaml/yaml_map.dart b/lib/src/yaml/yaml_map.dart index 285027ce..65dd1199 100644 --- a/lib/src/yaml/yaml_map.dart +++ b/lib/src/yaml/yaml_map.dart @@ -29,8 +29,8 @@ class YamlMap implements Map { void clear() => _map.clear(); void forEach(void f(key, value)) => _map.forEach((k, v) => f(_unwrapKey(k), v)); - Collection get keys => _map.keys.map(_unwrapKey); - Collection get values => _map.values; + Iterable get keys => _map.keys.mappedBy(_unwrapKey); + Iterable get values => _map.values; int get length => _map.length; bool get isEmpty => _map.isEmpty; String toString() => _map.toString(); @@ -81,7 +81,7 @@ class _WrappedHashKey { int _hashCode(obj, [List parents]) { if (parents == null) { parents = []; - } else if (parents.some((p) => identical(p, obj))) { + } else if (parents.any((p) => identical(p, obj))) { return -1; } @@ -94,7 +94,7 @@ int _hashCode(obj, [List parents]) { return _hashCode(obj.keys, parents) ^ _hashCode(obj.values, parents); } - if (obj is List) { + if (obj is Iterable) { // This is probably a really bad hash function, but presumably we'll get // this in the standard library before it actually matters. int hash = 0; diff --git a/test/curl_client_test.dart b/test/curl_client_test.dart index c040c2db..c2f6fb3f 100644 --- a/test/curl_client_test.dart +++ b/test/curl_client_test.dart @@ -215,7 +215,7 @@ void main() { tearDown(stopServer); test('head', () { - expect(new CurlClient().head(serverUrl).transform((response) { + expect(new CurlClient().head(serverUrl).then((response) { expect(response.statusCode, equals(200)); expect(response.body, equals('')); }), completes); @@ -225,7 +225,7 @@ void main() { expect(new CurlClient().get(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'GET', @@ -245,7 +245,7 @@ void main() { }, fields: { 'some-field': 'value', 'other-field': 'other value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'POST', @@ -268,7 +268,7 @@ void main() { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value', 'Content-Type': 'text/plain' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'POST', @@ -289,7 +289,7 @@ void main() { }, fields: { 'some-field': 'value', 'other-field': 'other value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'PUT', @@ -312,7 +312,7 @@ void main() { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value', 'Content-Type': 'text/plain' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'PUT', @@ -330,7 +330,7 @@ void main() { expect(new CurlClient().delete(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((response) { + }).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'DELETE', @@ -366,7 +366,7 @@ void main() { var future = new CurlClient().readBytes(serverUrl, headers: { 'X-Random-Header': 'Value', 'X-Other-Header': 'Other Value' - }).transform((bytes) => new String.fromCharCodes(bytes)); + }).then((bytes) => new String.fromCharCodes(bytes)); expect(future, completion(parse(equals({ 'method': 'GET', @@ -389,11 +389,11 @@ void main() { request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json; charset=utf-8'; - var future = client.send(request).chain((response) { + var future = client.send(request).then((response) { expect(response.statusCode, equals(200)); return consumeInputStream(response.stream); - }).transform((bytes) => new String.fromCharCodes(bytes)); - future.onComplete((_) => client.close()); + }).then((bytes) => new String.fromCharCodes(bytes)); + future.catchError((_) {}).then((_) => client.close()); expect(future, completion(parse(equals({ 'method': 'POST', @@ -411,7 +411,7 @@ void main() { test('with one redirect', () { var url = serverUrl.resolve('/redirect'); - expect(new CurlClient().get(url).transform((response) { + expect(new CurlClient().get(url).then((response) { expect(response.statusCode, equals(200)); expect(response.body, parse(equals({ 'method': 'GET', @@ -433,7 +433,7 @@ void main() { test('with one redirect via HEAD', () { var url = serverUrl.resolve('/redirect'); - expect(new CurlClient().head(url).transform((response) { + expect(new CurlClient().head(url).then((response) { expect(response.statusCode, equals(200)); }), completes); }); @@ -451,8 +451,8 @@ void main() { test('without following redirects', () { var request = new http.Request('GET', serverUrl.resolve('/redirect')); request.followRedirects = false; - expect(new CurlClient().send(request).chain(http.Response.fromStream) - .transform((response) { + expect(new CurlClient().send(request).then(http.Response.fromStream) + .then((response) { expect(response.statusCode, equals(302)); expect(response.isRedirect, true); }), completes); diff --git a/test/oauth2_test.dart b/test/oauth2_test.dart index f3d38e04..d8f3b34a 100644 --- a/test/oauth2_test.dart +++ b/test/oauth2_test.dart @@ -68,7 +68,7 @@ main() { confirmPublish(pub); server.handle('POST', '/token', (request, response) { - return consumeInputStream(request.inputStream).transform((bytes) { + return consumeInputStream(request.inputStream).then((bytes) { var body = new String.fromCharCodes(bytes); expect(body, matches( new RegExp(r'(^|&)refresh_token=refresh\+token(&|$)'))); @@ -199,7 +199,7 @@ void authorizePub(ScheduledProcess pub, ScheduledServer server, redirectUrl = addQueryParameters(redirectUrl, {'code': 'access code'}); return (new http.Request('GET', redirectUrl)..followRedirects = false) .send(); - }).transform((response) { + }).then((response) { expect(response.headers['location'], equals(['http://pub.dartlang.org/authorized'])); }), anything); @@ -209,7 +209,7 @@ void authorizePub(ScheduledProcess pub, ScheduledServer server, void handleAccessTokenRequest(ScheduledServer server, String accessToken) { server.handle('POST', '/token', (request, response) { - return consumeInputStream(request.inputStream).transform((bytes) { + return consumeInputStream(request.inputStream).then((bytes) { var body = new String.fromCharCodes(bytes); expect(body, matches(new RegExp(r'(^|&)code=access\+code(&|$)'))); diff --git a/test/pub_lish_test.dart b/test/pub_lish_test.dart index 69555784..5319c466 100644 --- a/test/pub_lish_test.dart +++ b/test/pub_lish_test.dart @@ -13,7 +13,7 @@ import '../../pub/io.dart'; void handleUploadForm(ScheduledServer server, [Map body]) { server.handle('GET', '/packages/versions/new.json', (request, response) { - return server.url.transform((url) { + return server.url.then((url) { expect(request.headers.value('authorization'), equals('Bearer access token')); @@ -38,7 +38,7 @@ void handleUpload(ScheduledServer server) { server.handle('POST', '/upload', (request, response) { // TODO(nweiz): Once a multipart/form-data parser in Dart exists, validate // that the request body is correctly formatted. See issue 6952. - return server.url.transform((url) { + return server.url.then((url) { response.statusCode = 302; response.headers.set('location', url.resolve('/create').toString()); response.outputStream.close(); diff --git a/test/test_pub.dart b/test/test_pub.dart index 3da8fce9..a6042fb8 100644 --- a/test/test_pub.dart +++ b/test/test_pub.dart @@ -8,9 +8,9 @@ /// tests like that. library test_pub; +import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; -import 'dart:json'; +import 'dart:json' as json; import 'dart:math'; import 'dart:uri'; @@ -80,7 +80,7 @@ void serve([List<Descriptor> contents]) { var baseDir = dir("serve-dir", contents); _schedule((_) { - return _closeServer().transform((_) { + return _closeServer().then((_) { _server = new HttpServer(); _server.defaultRequestHandler = (request, response) { var path = request.uri.replaceFirst("/", "").split("/"); @@ -101,9 +101,7 @@ void serve([List<Descriptor> contents]) { response.contentLength = data.length; response.outputStream.write(data); response.outputStream.close(); - }); - - future.handleException((e) { + }).catchError((e) { print("Exception while handling ${request.uri}: $e"); response.statusCode = 500; response.reasonPhrase = e.message; @@ -161,7 +159,7 @@ void servePackages(List<Map> pubspecs) { } _schedule((_) { - return _awaitObject(pubspecs).transform((resolvedPubspecs) { + return _awaitObject(pubspecs).then((resolvedPubspecs) { for (var spec in resolvedPubspecs) { var name = spec['name']; var version = spec['version']; @@ -172,12 +170,12 @@ void servePackages(List<Map> pubspecs) { _servedPackageDir.contents.clear(); for (var name in _servedPackages.keys) { - var versions = _servedPackages[name].keys; + var versions = _servedPackages[name].keys.toList()); _servedPackageDir.contents.addAll([ file('$name.json', - JSON.stringify({'versions': versions})), + json.stringify({'versions': versions})), dir(name, [ - dir('versions', flatten(versions.map((version) { + dir('versions', flatten(versions.mappedBy((version) { return [ file('$version.yaml', _servedPackages[name][version]), tar('$version.tar.gz', [ @@ -194,7 +192,7 @@ void servePackages(List<Map> pubspecs) { } /// Converts [value] into a YAML string. -String yaml(value) => JSON.stringify(value); +String yaml(value) => json.stringify(value); /// Describes a package that passes all validation. Descriptor get normalPackage => dir(appPath, [ @@ -211,7 +209,7 @@ Descriptor get normalPackage => dir(appPath, [ /// [contents] may contain [Future]s that resolve to serializable objects, /// which may in turn contain [Future]s recursively. Descriptor pubspec(Map contents) { - return async(_awaitObject(contents).transform((resolvedContents) => + return async(_awaitObject(contents).then((resolvedContents) => file("pubspec.yaml", yaml(resolvedContents)))); } @@ -261,7 +259,7 @@ Map package(String name, String version, [List dependencies]) { /// Describes a map representing a dependency on a package in the package /// repository. Map dependency(String name, [String versionConstraint]) { - var url = port.transform((p) => "http://localhost:$p"); + var url = port.then((p) => "http://localhost:$p"); var dependency = {"hosted": {"name": name, "url": url}}; if (versionConstraint != null) dependency["version"] = versionConstraint; return dependency; @@ -331,7 +329,7 @@ DirectoryDescriptor cacheDir(Map packages) { }); return dir(cachePath, [ dir('hosted', [ - async(port.transform((p) => dir('localhost%58$p', contents))) + async(port.then((p) => dir('localhost%58$p', contents))) ]) ]); } @@ -344,7 +342,7 @@ Descriptor credentialsFile( String accessToken, {String refreshToken, Date expiration}) { - return async(server.url.transform((url) { + return async(server.url.then((url) { return dir(cachePath, [ file('credentials.json', new oauth2.Credentials( accessToken, @@ -364,10 +362,10 @@ DirectoryDescriptor appDir(List dependencies) => /// Converts a list of dependencies as passed to [package] into a hash as used /// in a pubspec. Future<Map> _dependencyListToMap(List<Map> dependencies) { - return _awaitObject(dependencies).transform((resolvedDependencies) { + return _awaitObject(dependencies).then((resolvedDependencies) { var result = <String, Map>{}; for (var dependency in resolvedDependencies) { - var keys = dependency.keys.filter((key) => key != "version"); + var keys = dependency.keys.where((key) => key != "version"); var sourceName = only(keys); var source; switch (sourceName) { @@ -453,7 +451,7 @@ void run() { var asyncDone = expectAsync0(() {}); Future cleanup() { - return _runScheduled(createdSandboxDir, _scheduledCleanup).chain((_) { + return _runScheduled(createdSandboxDir, _scheduledCleanup).then((_) { _scheduled = null; _scheduledCleanup = null; _scheduledOnException = null; @@ -462,29 +460,25 @@ void run() { }); } - final future = _setUpSandbox().chain((sandboxDir) { + final future = _setUpSandbox().then((sandboxDir) { createdSandboxDir = sandboxDir; return _runScheduled(sandboxDir, _scheduled); }); - future.handleException((error) { + future.catchError((error) { // If an error occurs during testing, delete the sandbox, throw the error so // that the test framework sees it, then finally call asyncDone so that the // test framework knows we're done doing asynchronous stuff. var subFuture = _runScheduled(createdSandboxDir, _scheduledOnException) - .chain((_) => cleanup()); - subFuture.handleException((e) { - print("Exception while cleaning up: $e"); - print(subFuture.stackTrace); - registerException(error, subFuture.stackTrace); + .then((_) => cleanup()); + subFuture.catchError((e) { + print("Exception while cleaning up: ${e.error}"); + print(e.stackTrace); + registerException(e.error, e.stackTrace); return true; }); - subFuture.then((_) => registerException(error, future.stackTrace)); - return true; - }); - timeout(future, _TIMEOUT, 'waiting for a test to complete') - .chain((_) => cleanup()) + .then((_) => cleanup()) .then((_) => asyncDone()); } @@ -503,7 +497,7 @@ void schedulePub({List args, Pattern output, Pattern error, Future<Uri> tokenEndpoint, int exitCode: 0}) { _schedule((sandboxDir) { return _doPub(runProcess, sandboxDir, args, tokenEndpoint) - .transform((result) { + .then((result) { var failures = []; _validateOutput(failures, 'stdout', output, result.stdout); @@ -518,7 +512,7 @@ void schedulePub({List args, Pattern output, Pattern error, if (error == null) { // If we aren't validating the error, still show it on failure. failures.add('Pub stderr:'); - failures.addAll(result.stderr.map((line) => '| $line')); + failures.addAll(result.stderr.mappedBy((line) => '| $line')); } throw new ExpectException(Strings.join(failures, '\n')); @@ -629,7 +623,7 @@ Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { /// about the pub git tests). void ensureGit() { _schedule((_) { - return isGitInstalled.transform((installed) { + return isGitInstalled.then((installed) { if (!installed && !Platform.environment.containsKey('BUILDBOT_BUILDERNAME')) { _abortScheduled = true; @@ -655,18 +649,18 @@ Future<Directory> _setUpSandbox() => createTempDir(); Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) { if (scheduled == null) return new Future.immediate(null); - var iterator = scheduled.iterator(); + var iterator = scheduled.iterator; Future runNextEvent(_) { - if (_abortScheduled || !iterator.hasNext) { + if (_abortScheduled || !iterator.moveNext()) { _abortScheduled = false; scheduled.clear(); return new Future.immediate(null); } - var future = iterator.next()(parentDir); + var future = iterator.current(parentDir); if (future != null) { - return future.chain(runNextEvent); + return future.then(runNextEvent); } else { return runNextEvent(null); } @@ -699,7 +693,7 @@ void _validateOutputRegex(List<String> failures, String pipe, failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); } else { failures.add('Expected $pipe to match "${expected.pattern}" but got:'); - failures.addAll(actual.map((line) => '| $line')); + failures.addAll(actual.mappedBy((line) => '| $line')); } } @@ -744,7 +738,7 @@ void _validateOutputString(List<String> failures, String pipe, // If any lines mismatched, show the expected and actual. if (failed) { failures.add('Expected $pipe:'); - failures.addAll(expected.map((line) => '| $line')); + failures.addAll(expected.mappedBy((line) => '| $line')); failures.add('Got:'); failures.addAll(results); } @@ -802,7 +796,7 @@ abstract class Descriptor { // Special-case strings to support multi-level names like "myapp/packages". if (name is String) { var path = join(dir, name); - return exists(path).chain((exists) { + return exists(path).then((exists) { if (!exists) Expect.fail('File $name in $dir not found.'); return validate(path); }); @@ -816,9 +810,9 @@ abstract class Descriptor { stackTrace = localStackTrace; } - return listDir(dir).chain((files) { - var matches = files.filter((file) => endsWithPattern(file, name)); - if (matches.length == 0) { + return listDir(dir).then((files) { + var matches = files.where((file) => endsWithPattern(file, name)).toList(); + if (matches.isEmpty) { Expect.fail('No files in $dir match pattern $name.'); } if (matches.length == 1) return validate(matches[0]); @@ -845,16 +839,15 @@ abstract class Descriptor { for (var match in matches) { var future = validate(match); - future.handleException((e) { + future.catchError((e) { failures.add(e); checkComplete(); - return true; }); future.then((_) { successes++; checkComplete(); - }); + }).catchError(() {}); } return completer.future; }); @@ -885,7 +878,7 @@ class FileDescriptor extends Descriptor { /// Validates that this file correctly matches the actual file at [path]. Future validate(String path) { return _validateOneMatch(path, (file) { - return readTextFile(file).transform((text) { + return readTextFile(file).then((text) { if (text == contents) return null; Expect.fail('File $file should contain:\n\n$contents\n\n' @@ -923,13 +916,14 @@ class DirectoryDescriptor extends Descriptor { /// the creation is done. Future<Directory> create(parentDir) { // Create the directory. - return ensureDir(join(parentDir, _stringName)).chain((dir) { + return ensureDir(join(parentDir, _stringName)).then((dir) { if (contents == null) return new Future<Directory>.immediate(dir); // Recursively create all of its children. - final childFutures = contents.map((child) => child.create(dir)); + final childFutures = + contents.mappedBy((child) => child.create(dir)).toList(); // Only complete once all of the children have been created too. - return Futures.wait(childFutures).transform((_) => dir); + return Futures.wait(childFutures).then((_) => dir); }); } @@ -946,10 +940,11 @@ class DirectoryDescriptor extends Descriptor { Future validate(String path) { return _validateOneMatch(path, (dir) { // Validate each of the items in this directory. - final entryFutures = contents.map((entry) => entry.validate(dir)); + final entryFutures = + contents.mappedBy((entry) => entry.validate(dir)).toList(); // If they are all valid, the directory is valid. - return Futures.wait(entryFutures).transform((entries) => null); + return Futures.wait(entryFutures).then((entries) => null); }); } @@ -978,11 +973,11 @@ class FutureDescriptor extends Descriptor { FutureDescriptor(this._future) : super('<unknown>'); - Future create(dir) => _future.chain((desc) => desc.create(dir)); + Future create(dir) => _future.then((desc) => desc.create(dir)); - Future validate(dir) => _future.chain((desc) => desc.validate(dir)); + Future validate(dir) => _future.then((desc) => desc.validate(dir)); - Future delete(dir) => _future.chain((desc) => desc.delete(dir)); + Future delete(dir) => _future.then((desc) => desc.delete(dir)); InputStream load(List<String> path) { var resultStream = new ListInputStream(); @@ -1020,9 +1015,9 @@ class GitRepoDescriptor extends DirectoryDescriptor { /// referred to by [ref] at the current point in the scheduled test run. Future<String> revParse(String ref) { return _scheduleValue((parentDir) { - return super.create(parentDir).chain((rootDir) { + return super.create(parentDir).then((rootDir) { return _runGit(['rev-parse', ref], rootDir); - }).transform((output) => output[0]); + }).then((output) => output[0]); }); } @@ -1040,10 +1035,10 @@ class GitRepoDescriptor extends DirectoryDescriptor { Future runGitStep(_) { if (commands.isEmpty) return new Future.immediate(workingDir); var command = commands.removeAt(0); - return _runGit(command, workingDir).chain(runGitStep); + return _runGit(command, workingDir).then(runGitStep); } - return super.create(parentDir).chain((rootDir) { + return super.create(parentDir).then((rootDir) { workingDir = rootDir; return runGitStep(null); }); @@ -1060,7 +1055,7 @@ class GitRepoDescriptor extends DirectoryDescriptor { }; return runGit(args, workingDir: workingDir.path, - environment: environment).transform((result) { + environment: environment).then((result) { if (!result.success) { throw "Error running: git ${Strings.join(args, ' ')}\n" "${Strings.join(result.stderr, '\n')}"; @@ -1083,15 +1078,15 @@ class TarFileDescriptor extends Descriptor { Future<File> create(parentDir) { // TODO(rnystrom): Use withTempDir(). var tempDir; - return createTempDir().chain((_tempDir) { + return createTempDir().then((_tempDir) { tempDir = _tempDir; - return Futures.wait(contents.map((child) => child.create(tempDir))); - }).chain((createdContents) { + return Futures.wait(contents.mappedBy((child) => child.create(tempDir))); + }).then((createdContents) { return consumeInputStream(createTarGz(createdContents, baseDir: tempDir)); - }).chain((bytes) { + }).then((bytes) { return new File(join(parentDir, _stringName)).writeAsBytes(bytes); - }).chain((file) { - return deleteDir(tempDir).transform((_) => file); + }).then((file) { + return deleteDir(tempDir).then((_) => file); }); } @@ -1116,7 +1111,7 @@ class TarFileDescriptor extends Descriptor { var tempDir; // TODO(rnystrom): Use withTempDir() here. // TODO(nweiz): propagate any errors to the return value. See issue 3657. - createTempDir().chain((_tempDir) { + createTempDir().then((_tempDir) { tempDir = _tempDir; return create(tempDir); }).then((tar) { @@ -1137,7 +1132,7 @@ class NothingDescriptor extends Descriptor { Future delete(dir) => new Future.immediate(null); Future validate(String dir) { - return exists(join(dir, name)).transform((exists) { + return exists(join(dir, name)).then((exists) { if (exists) Expect.fail('File $name in $dir should not exist.'); }); } @@ -1167,7 +1162,7 @@ Future<Pair<List<String>, List<String>>> schedulePackageValidation( return Entrypoint.load(join(sandboxDir, appPath), cache) .chain((entrypoint) { var validator = fn(entrypoint); - return validator.validate().transform((_) { + return validator.validate().then((_) { return new Pair(validator.errors, validator.warnings); }); }); @@ -1240,8 +1235,8 @@ class ScheduledProcess { /// Wraps a [Process] [Future] in a scheduled process. ScheduledProcess(this.name, Future<Process> process) : _process = process, - _stdout = process.transform((p) => new StringInputStream(p.stdout)), - _stderr = process.transform((p) => new StringInputStream(p.stderr)) { + _stdout = process.then((p) => new StringInputStream(p.stdout)), + _stderr = process.then((p) => new StringInputStream(p.stderr)) { _schedule((_) { if (!_endScheduled) { @@ -1249,7 +1244,7 @@ class ScheduledProcess { "or kill() called before the test is run."); } - return _process.transform((p) { + return _process.then((p) { p.onExit = (c) { if (_endExpected) { _exitCodeCompleter.complete(c); @@ -1343,7 +1338,7 @@ class ScheduledProcess { /// Writes [line] to the process as stdin. void writeLine(String line) { - _schedule((_) => _process.transform((p) => p.stdin.writeString('$line\n'))); + _schedule((_) => _process.then((p) => p.stdin.writeString('$line\n'))); } /// Kills the process, and waits until it's dead. @@ -1366,7 +1361,7 @@ class ScheduledProcess { _schedule((_) { _endExpected = true; return timeout(_exitCode, _SCHEDULE_TIMEOUT, - "waiting for process $name to exit").transform((exitCode) { + "waiting for process $name to exit").then((exitCode) { if (expectedExitCode != null) { expect(exitCode, equals(expectedExitCode)); } @@ -1378,7 +1373,7 @@ class ScheduledProcess { /// Prints nothing if the straems are empty. Future _printStreams() { Future printStream(String streamName, StringInputStream stream) { - return consumeStringInputStream(stream).transform((output) { + return consumeStringInputStream(stream).then((output) { if (output.isEmpty) return; print('\nProcess $name $streamName:'); @@ -1424,11 +1419,11 @@ class ScheduledServer { } /// The port on which the server is listening. - Future<int> get port => _server.transform((s) => s.port); + Future<int> get port => _server.then((s) => s.port); /// The base URL of the server, including its port. Future<Uri> get url => - port.transform((p) => new Uri.fromString("http://localhost:$p")); + port.then((p) => new Uri.fromString("http://localhost:$p")); /// Assert that the next request has the given [method] and [path], and pass /// it to [handler] to handle. If [handler] returns a [Future], wait until @@ -1466,7 +1461,7 @@ class ScheduledServer { fail('Unexpected ${request.method} request to ${request.path}.'); } return _handlers.removeFirst(); - }).transform((handler) { + }).then((handler) { handler(request, response); }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " "${request.path}"); @@ -1479,16 +1474,18 @@ class ScheduledServer { /// Completes with the fully resolved structure. Future _awaitObject(object) { // Unroll nested futures. - if (object is Future) return object.chain(_awaitObject); - if (object is Collection) return Futures.wait(object.map(_awaitObject)); + if (object is Future) return object.then(_awaitObject); + if (object is Collection) { + return Futures.wait(object.mappedBy(_awaitObject).toList()); + } if (object is! Map) return new Future.immediate(object); var pairs = <Future<Pair>>[]; object.forEach((key, value) { pairs.add(_awaitObject(value) - .transform((resolved) => new Pair(key, resolved))); + .then((resolved) => new Pair(key, resolved))); }); - return Futures.wait(pairs).transform((resolvedPairs) { + return Futures.wait(pairs).then((resolvedPairs) { var map = {}; for (var pair in resolvedPairs) { map[pair.first] = pair.last; @@ -1537,7 +1534,7 @@ void _scheduleOnException(_ScheduledEvent event) { void expectLater(Future actual, matcher, {String reason, FailureHandler failureHandler, bool verbose: false}) { _schedule((_) { - return actual.transform((value) { + return actual.then((value) { expect(value, matcher, reason: reason, failureHandler: failureHandler, verbose: false); }); diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart index eb49d3d8..b5b30eda 100644 --- a/test/version_solver_test.dart +++ b/test/version_solver_test.dart @@ -4,8 +4,8 @@ library pub_update_test; +import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; import '../../pub/lock_file.dart'; import '../../pub/package.dart'; @@ -452,10 +452,9 @@ testResolve(description, packages, {lockfile, result, Matcher error}) { // If we aren't expecting an error, print some debugging info if we get one. if (error == null) { - future.handleException((ex) { + future.catchError((ex) { print(ex); print(future.stackTrace); - return true; }); } }); @@ -478,7 +477,7 @@ class MockSource extends Source { : _packages = <String, Map<Version, Package>>{}; Future<List<Version>> getVersions(String name, String description) { - return fakeAsync(() => _packages[description].keys); + return fakeAsync(() => _packages[description].keys.toList()); } Future<Pubspec> describe(PackageId id) { diff --git a/test/yaml_test.dart b/test/yaml_test.dart index 85cbdf81..889923e5 100644 --- a/test/yaml_test.dart +++ b/test/yaml_test.dart @@ -4,8 +4,6 @@ library yaml_test; -import 'dart:math'; - import '../../../pkg/unittest/lib/unittest.dart'; import '../../pub/yaml/yaml.dart'; import '../../pub/yaml/deep_equals.dart'; @@ -32,8 +30,8 @@ expectYamlStreamLoads(List expected, String source) { } main() { - var infinity = parseDouble("Infinity"); - var nan = parseDouble("NaN"); + var infinity = double.parse("Infinity"); + var nan = double.parse("NaN"); group('YamlMap', () { group('accepts as a key', () { -- GitLab