Chromium Code Reviews| Index: utils/pub/io.dart |
| diff --git a/utils/pub/io.dart b/utils/pub/io.dart |
| index 968f3546fbc4bcf77b02797f0ab46dc99357435c..1fa5a818d8f9b20f319fc9e0332836924fe01042 100644 |
| --- a/utils/pub/io.dart |
| +++ b/utils/pub/io.dart |
| @@ -13,17 +13,15 @@ import 'dart:uri'; |
| // TODO(nweiz): Make this import better. |
| import '../../pkg/http/lib/http.dart' as http; |
| -import 'utils.dart'; |
| import 'curl_client.dart'; |
| +import 'utils.dart'; |
| +import 'path.dart' as path; |
| bool _isGitInstalledCache; |
| /// The cached Git command. |
| String _gitCommandCache; |
| -/** Gets the current working directory. */ |
| -String get currentWorkingDir => new File('.').fullPathSync(); |
| - |
| final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); |
| /** |
| @@ -41,55 +39,32 @@ void printError(value) { |
| * [File] objects. |
| */ |
| String join(part1, [part2, part3, part4]) { |
| - final parts = sanitizePath(part1).split('/'); |
| - |
| - for (final part in [part2, part3, part4]) { |
| - if (part == null) continue; |
| - |
| - for (final piece in _getPath(part).split('/')) { |
| - if (piece == '..' && parts.length > 0 && |
| - parts.last != '.' && parts.last != '..') { |
| - parts.removeLast(); |
| - } else if (piece != '') { |
| - if (parts.length > 0 && parts.last == '.') { |
| - parts.removeLast(); |
| - } |
| - parts.add(piece); |
| - } |
| - } |
| - } |
| - |
| - return Strings.join(parts, Platform.pathSeparator); |
| -} |
| - |
| -/// Splits [path] into its individual components. |
| -List<String> splitPath(path) => sanitizePath(path).split('/'); |
| - |
| -/** |
| - * Gets the basename, the file name without any leading directory path, for |
| - * [file], which can either be a [String], [File], or [Directory]. |
| - */ |
| -// TODO(rnystrom): Copied from file_system (so that we don't have to add |
| -// file_system to the SDK). Should unify. |
| -String basename(file) { |
| - file = sanitizePath(file); |
| - |
| - int lastSlash = file.lastIndexOf('/', file.length); |
| - if (lastSlash == -1) { |
| - return file; |
| + 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 file.substring(lastSlash + 1); |
| + return path.join(part1); |
| } |
| } |
| -/** |
| - * Gets the the leading directory path for [file], which can either be a |
| - * [String], [File], or [Directory]. |
| - */ |
| -// TODO(nweiz): Copied from file_system (so that we don't have to add |
| -// file_system to the SDK). Should unify. |
| +/// 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.filename(_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); |
| + file = _sanitizePath(file); |
| int lastSlash = file.lastIndexOf('/', file.length); |
| if (lastSlash == -1) { |
| @@ -99,10 +74,21 @@ String dirname(file) { |
| } |
| } |
| +// TODO(nweiz): move this into path.dart. |
| +/// Splits [path] into its individual components. |
| +List<String> splitPath(path) => _sanitizePath(path).split('/'); |
| + |
| /// Returns whether or not [entry] is nested somewhere within [dir]. This just |
| /// performs a path comparison; it doesn't look at the actual filesystem. |
| -bool isBeneath(entry, dir) => |
| - sanitizePath(entry).startsWith('${sanitizePath(dir)}/'); |
| +bool isBeneath(entry, dir) { |
| + var relative = relativeTo(entry, dir); |
| + return !path.isAbsolute(relative) && !relative.startsWith('..'); |
| +} |
| + |
| +// 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); |
| /** |
| * Asynchronously determines if [path], which can be a [String] file path, a |
| @@ -399,52 +385,25 @@ Future<File> createPackageSymlink(String name, from, to, |
| /// Given [entry] which may be a [String], [File], or [Directory] relative to |
| /// the current working directory, returns its full canonicalized path. |
| -String getFullPath(entry) { |
| - var path = _getPath(entry); |
| - |
| - // Don't do anything if it's already absolute. |
| - if (isAbsolute(path)) return path; |
| - |
| - // Using Path.join here instead of File().fullPathSync() because the former |
| - // does not require an actual file to exist at that path. |
| - return new Path.fromNative(currentWorkingDir).join(new Path(path)) |
| - .toNativePath(); |
| -} |
| +String getFullPath(entry) => path.absolute(_getPath(entry)); |
| /// Returns whether or not [entry] is an absolute path. |
| -bool isAbsolute(entry) => _splitAbsolute(entry).first != null; |
| +bool isAbsolute(entry) => path.isAbsolute(_getPath(entry)); |
| -/// 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)); |
| -} |
| - |
| -/// Resolves [path] relative to the location of pub.dart. |
| -String relativeToPub(String path) { |
| +/// Resolves [target] relative to the location of pub.dart. |
| +String relativeToPub(String target) { |
| var scriptPath = new File(new Options().script).fullPathSync(); |
| // Walk up until we hit the "util(s)" directory. This lets us figure out where |
| // we are if this function is called from pub.dart, or one of the tests, |
| // which also live under "utils", or from the SDK where pub is in "util". |
| - var utilDir = new Path.fromNative(scriptPath).directoryPath; |
| - while (utilDir.filename != 'utils' && utilDir.filename != 'util') { |
| - if (utilDir.filename == '') throw 'Could not find path to pub.'; |
| - utilDir = utilDir.directoryPath; |
| + var utilDir = dirname(scriptPath); |
| + while (basename(utilDir) != 'utils' && basename(utilDir) != 'util') { |
| + if (basename(utilDir) == '') throw 'Could not find path to pub.'; |
| + utilDir = dirname(utilDir); |
| } |
| - return utilDir.append('pub').append(path).canonicalize().toNativePath(); |
| + return path.normalize(join(utilDir, 'pub', target)); |
| } |
| /// A StringInputStream reading from stdin. |
| @@ -862,7 +821,7 @@ Future<bool> _extractTarGzWindows(InputStream stream, String destination) { |
| }).chain((files) { |
| var tarFile; |
| for (var file in files) { |
| - if (new Path(file).extension == 'tar') { |
| + if (path.extension(file) == '.tar') { |
| tarFile = file; |
| break; |
| } |
| @@ -894,15 +853,14 @@ InputStream createTarGz(List contents, {baseDir}) { |
| // exit codes). See issue 3657. |
| var stream = new ListInputStream(); |
| - if (baseDir == null) baseDir = currentWorkingDir; |
| + if (baseDir == null) baseDir = path.current; |
| baseDir = getFullPath(baseDir); |
| contents = contents.map((entry) { |
| entry = getFullPath(entry); |
| if (!isBeneath(entry, baseDir)) { |
| throw 'Entry $entry is not inside $baseDir.'; |
| } |
| - return new Path.fromNative(entry).relativeTo(new Path.fromNative(baseDir)) |
| - .toNativePath(); |
| + return relativeTo(entry, baseDir); |
| }); |
| if (Platform.operatingSystem != "windows") { |
| @@ -996,7 +954,7 @@ String _getPath(entry) { |
| /// Gets the path string for [entry], normalizing backslashes to forward slashes |
| /// on Windows. |
| -String sanitizePath(entry) { |
| +String _sanitizePath(entry) { |
| entry = _getPath(entry); |
| if (Platform.operatingSystem != 'windows') return entry; |
| @@ -1010,6 +968,23 @@ String sanitizePath(entry) { |
| '${split.last.replaceAll('\\', '/')}'; |
| } |
| +/// Splits [entry] into two components: the absolute path prefix and the |
| +/// remaining path. Takes into account Windows' quirky absolute paths syntaxes. |
|
Bob Nystrom
2012/12/08 03:36:53
Add a TODO to move this (or something similar) int
nweiz
2012/12/08 03:43:45
Done.
|
| +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]. |