| Index: utils/pub/io.dart
 | 
| diff --git a/utils/pub/io.dart b/utils/pub/io.dart
 | 
| index 0ecc7b2498942789d4dbbabfa8db420dec1a3bdb..e6ea0718e57b93191cbb70ee1e158ddd2b891d08 100644
 | 
| --- a/utils/pub/io.dart
 | 
| +++ b/utils/pub/io.dart
 | 
| @@ -30,45 +30,24 @@ final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?");
 | 
|   * platform-specific path separators. Parts can be [String], [Directory], or
 | 
|   * [File] objects.
 | 
|   */
 | 
| -String join(part1, [part2, part3, part4]) {
 | 
| -  part1 = _getPath(part1);
 | 
| -  if (part2 != null) part2 = _getPath(part2);
 | 
| -  if (part3 != null) part3 = _getPath(part3);
 | 
| -  if (part4 != null) part4 = _getPath(part4);
 | 
| -
 | 
| -  // TODO(nweiz): Don't use "?part" in path.dart.
 | 
| -  if (part4 != null) {
 | 
| -    return path.join(part1, part2, part3, part4);
 | 
| -  } else if (part3 != null) {
 | 
| -    return path.join(part1, part2, part3);
 | 
| -  } else if (part2 != null) {
 | 
| -    return path.join(part1, part2);
 | 
| -  } else {
 | 
| -    return path.join(part1);
 | 
| -  }
 | 
| +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));
 | 
| +
 | 
| +  return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5],
 | 
| +      parts[6], parts[7]);
 | 
|  }
 | 
|  
 | 
|  /// Gets the basename, the file name without any leading directory path, for
 | 
|  /// [file], which can either be a [String], [File], or [Directory].
 | 
|  String basename(file) => path.basename(_getPath(file));
 | 
|  
 | 
| -// TODO(nweiz): move this into path.dart.
 | 
|  /// Gets the the leading directory path for [file], which can either be a
 | 
|  /// [String], [File], or [Directory].
 | 
| -String dirname(file) {
 | 
| -  file = _sanitizePath(file);
 | 
| -
 | 
| -  int lastSlash = file.lastIndexOf('/', file.length);
 | 
| -  if (lastSlash == -1) {
 | 
| -    return '.';
 | 
| -  } else {
 | 
| -    return file.substring(0, lastSlash);
 | 
| -  }
 | 
| -}
 | 
| +String dirname(file) => path.dirname(_getPath(file));
 | 
|  
 | 
| -// TODO(nweiz): move this into path.dart.
 | 
| -/// Splits [path] into its individual components.
 | 
| -List<String> splitPath(path) => _sanitizePath(path).split('/');
 | 
| +/// Splits [entry] into its individual components.
 | 
| +List<String> splitPath(entry) => path.split(_getPath(entry));
 | 
|  
 | 
|  /// Returns whether or not [entry] is nested somewhere within [dir]. This just
 | 
|  /// performs a path comparison; it doesn't look at the actual filesystem.
 | 
| @@ -77,10 +56,8 @@ bool isBeneath(entry, dir) {
 | 
|    return !path.isAbsolute(relative) && splitPath(relative)[0] != '..';
 | 
|  }
 | 
|  
 | 
| -// TODO(nweiz): move this into path.dart.
 | 
|  /// Returns the path to [target] from [base].
 | 
| -String relativeTo(target, base) =>
 | 
| -  new path.Builder(root: base).relative(target);
 | 
| +String relativeTo(target, base) => path.relative(target, from: base);
 | 
|  
 | 
|  /**
 | 
|   * Asynchronously determines if [path], which can be a [String] file path, a
 | 
| @@ -1067,40 +1044,6 @@ String _getPath(entry) {
 | 
|    throw 'Entry $entry is not a supported type.';
 | 
|  }
 | 
|  
 | 
| -/// Gets the path string for [entry], normalizing backslashes to forward slashes
 | 
| -/// on Windows.
 | 
| -String _sanitizePath(entry) {
 | 
| -  entry = _getPath(entry);
 | 
| -  if (Platform.operatingSystem != 'windows') return entry;
 | 
| -
 | 
| -  var split = _splitAbsolute(entry);
 | 
| -  if (split.first == null) return split.last.replaceAll('\\', '/');
 | 
| -
 | 
| -  // For absolute Windows paths, we don't want the prefix (either "\\" or e.g.
 | 
| -  // "C:\") to look like a normal path component, so we ensure that it only
 | 
| -  // contains backslashes.
 | 
| -  return '${split.first.replaceAll('/', '\\')}'
 | 
| -         '${split.last.replaceAll('\\', '/')}';
 | 
| -}
 | 
| -
 | 
| -// TODO(nweiz): Add something like this to path.dart.
 | 
| -/// Splits [entry] into two components: the absolute path prefix and the
 | 
| -/// remaining path. Takes into account Windows' quirky absolute paths syntaxes.
 | 
| -Pair<String, String> _splitAbsolute(entry) {
 | 
| -  var path = _getPath(entry);
 | 
| -
 | 
| -  if (Platform.operatingSystem != 'windows') {
 | 
| -    return !path.startsWith('/') ? new Pair(null, path)
 | 
| -        : new Pair('/', path.substring(1));
 | 
| -  }
 | 
| -
 | 
| -  // An absolute path on Windows is either UNC (two leading backslashes),
 | 
| -  // or a drive letter followed by a colon and a slash.
 | 
| -  var match = new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])').firstMatch(path);
 | 
| -  return match == null ? new Pair(null, path)
 | 
| -      : new Pair(match.group(0), path.substring(match.end));
 | 
| -}
 | 
| -
 | 
|  /**
 | 
|   * Gets a [Directory] for [entry], which can either already be one, or be a
 | 
|   * [String].
 | 
| 
 |