| Index: utils/pub/path.dart
|
| diff --git a/utils/pub/path.dart b/utils/pub/path.dart
|
| index d803fd17075726750cd3c559d4731ff6478af52b..bcfbf7ce1b93b719db785343c4d675c869cda022 100644
|
| --- a/utils/pub/path.dart
|
| +++ b/utils/pub/path.dart
|
| @@ -37,6 +37,12 @@ String basename(String path) => _builder.basename(path);
|
| String basenameWithoutExtension(String path) =>
|
| _builder.basenameWithoutExtension(path);
|
|
|
| +/// Gets the part of [path] before the last separator.
|
| +///
|
| +/// path.dirname('path/to/foo.dart'); // -> 'path/to'
|
| +/// path.dirname('path/to'); // -> 'to'
|
| +String dirname(String path) => _builder.dirname(path);
|
| +
|
| /// Gets the file extension of [path]: the portion of [basename] from the last
|
| /// `.` to the end (including the `.` itself).
|
| ///
|
| @@ -52,6 +58,19 @@ String basenameWithoutExtension(String path) =>
|
| /// path.extension('~/.notes.txt'); // -> '.txt'
|
| String extension(String path) => _builder.extension(path);
|
|
|
| +// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
|
| +/// Returns the root of [path], if it's absolute, or the empty string if it's
|
| +/// relative.
|
| +///
|
| +/// // Unix
|
| +/// path.rootPrefix('path/to/foo'); // -> ''
|
| +/// path.rootPrefix('/path/to/foo'); // -> '/'
|
| +///
|
| +/// // Windows
|
| +/// path.rootPrefix(r'path\to\foo'); // -> ''
|
| +/// path.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
|
| +String rootPrefix(String path) => _builder.rootPrefix(path);
|
| +
|
| /// Returns `true` if [path] is an absolute path and `false` if it is a
|
| /// relative path. On POSIX systems, absolute paths start with a `/` (forward
|
| /// slash). On Windows, an absolute path starts with `\\`, or a drive letter
|
| @@ -78,17 +97,24 @@ bool isRelative(String path) => _builder.isRelative(path);
|
| ///
|
| /// path.join('path', '/to', 'foo'); // -> '/to/foo'
|
| String join(String part1, [String part2, String part3, String part4,
|
| - String part5, String part6, String part7, String part8]) {
|
| - if (!?part2) return _builder.join(part1);
|
| - if (!?part3) return _builder.join(part1, part2);
|
| - if (!?part4) return _builder.join(part1, part2, part3);
|
| - if (!?part5) return _builder.join(part1, part2, part3, part4);
|
| - if (!?part6) return _builder.join(part1, part2, part3, part4, part5);
|
| - if (!?part7) return _builder.join(part1, part2, part3, part4, part5, part6);
|
| - if (!?part8) return _builder.join(part1, part2, part3, part4, part5, part6,
|
| - part7);
|
| - return _builder.join(part1, part2, part3, part4, part5, part6, part7, part8);
|
| -}
|
| + String part5, String part6, String part7, String part8]) =>
|
| + _builder.join(part1, part2, part3, part4, part5, part6, part7, part8);
|
| +
|
| +// TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
|
| +/// Splits [path] into its components using the current platform's [separator].
|
| +/// Example:
|
| +///
|
| +/// path.split('path/to/foo'); // -> ['path', 'to', 'foo']
|
| +///
|
| +/// If [path] is absolute, the root directory will be the first element in the
|
| +/// array. Example:
|
| +///
|
| +/// // Unix
|
| +/// path.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo']
|
| +///
|
| +/// // Windows
|
| +/// path.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
|
| +List<String> split(String path) => _builder.split(path);
|
|
|
| /// Normalizes [path], simplifying it by handling `..`, and `.`, and
|
| /// removing redundant path separators whenever possible.
|
| @@ -103,12 +129,19 @@ String normalize(String path) => _builder.normalize(path);
|
| /// path.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
|
| /// path.relative('/root/other.dart'); // -> '../other.dart'
|
| ///
|
| +/// If the [from] argument is passed, [path] is made relative to that instead.
|
| +///
|
| +/// path.relative('/root/path/a/b.dart',
|
| +/// from: '/root/path'); // -> 'a/b.dart'
|
| +/// path.relative('/root/other.dart',
|
| +/// from: '/root/path'); // -> '../other.dart'
|
| +///
|
| /// Since there is no relative path from one drive letter to another on Windows,
|
| /// this will return an absolute path in that case.
|
| ///
|
| -/// // Given current directory is C:\home:
|
| -/// path.relative(r'D:\other'); // -> 'D:\other'
|
| -String relative(String path) => _builder.relative(path);
|
| +/// path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other'
|
| +String relative(String path, {String from}) =>
|
| + _builder.relative(path, from: from);
|
|
|
| /// Removes a trailing extension from the last part of [path].
|
| ///
|
| @@ -163,6 +196,24 @@ class Builder {
|
| String basenameWithoutExtension(String path) =>
|
| _parse(path).basenameWithoutExtension;
|
|
|
| + /// Gets the part of [path] before the last separator.
|
| + ///
|
| + /// builder.dirname('path/to/foo.dart'); // -> 'path/to'
|
| + /// builder.dirname('path/to'); // -> 'to'
|
| + String dirname(String path) {
|
| + var parsed = _parse(path);
|
| + if (parsed.parts.isEmpty) return parsed.root == null ? '.' : parsed.root;
|
| + if (!parsed.hasTrailingSeparator) {
|
| + if (parsed.parts.length == 1) {
|
| + return parsed.root == null ? '.' : parsed.root;
|
| + }
|
| + parsed.parts.removeLast();
|
| + parsed.separators.removeLast();
|
| + }
|
| + parsed.separators[parsed.separators.length - 1] = '';
|
| + return parsed.toString();
|
| + }
|
| +
|
| /// Gets the file extension of [path]: the portion of [basename] from the last
|
| /// `.` to the end (including the `.` itself).
|
| ///
|
| @@ -178,6 +229,22 @@ class Builder {
|
| /// builder.extension('~/.notes.txt'); // -> '.txt'
|
| String extension(String path) => _parse(path).extension;
|
|
|
| + // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
|
| + /// Returns the root of [path], if it's absolute, or an empty string if it's
|
| + /// relative.
|
| + ///
|
| + /// // Unix
|
| + /// builder.rootPrefix('path/to/foo'); // -> ''
|
| + /// builder.rootPrefix('/path/to/foo'); // -> '/'
|
| + ///
|
| + /// // Windows
|
| + /// builder.rootPrefix(r'path\to\foo'); // -> ''
|
| + /// builder.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
|
| + String rootPrefix(String path) {
|
| + var root = _parse(path).root;
|
| + return root == null ? '' : root;
|
| + }
|
| +
|
| /// Returns `true` if [path] is an absolute path and `false` if it is a
|
| /// relative path. On POSIX systems, absolute paths start with a `/` (forward
|
| /// slash). On Windows, an absolute path starts with `\\`, or a drive letter
|
| @@ -208,8 +275,16 @@ class Builder {
|
| var buffer = new StringBuffer();
|
| var needsSeparator = false;
|
|
|
| - addPart(condition, part) {
|
| - if (!condition) return;
|
| + var parts = [part1, part2, part3, part4, part5, part6, part7, part8];
|
| + for (var i = 1; i < parts.length; i++) {
|
| + if (parts[i] != null && parts[i - 1] == null) {
|
| + throw new ArgumentError("join(): part ${i - 1} was null, but part $i "
|
| + "was not.");
|
| + }
|
| + }
|
| +
|
| + for (var part in parts) {
|
| + if (part == null) continue;
|
|
|
| if (this.isAbsolute(part)) {
|
| // An absolute path discards everything before it.
|
| @@ -231,18 +306,31 @@ class Builder {
|
| !style.separatorPattern.hasMatch(part[part.length - 1]);
|
| }
|
|
|
| - addPart(true, part1);
|
| - addPart(?part2, part2);
|
| - addPart(?part3, part3);
|
| - addPart(?part4, part4);
|
| - addPart(?part5, part5);
|
| - addPart(?part6, part6);
|
| - addPart(?part7, part7);
|
| - addPart(?part8, part8);
|
| -
|
| return buffer.toString();
|
| }
|
|
|
| + // TODO(nweiz): add a UNC example for Windows once issue 7323 is fixed.
|
| + /// Splits [path] into its components using the current platform's
|
| + /// [separator]. Example:
|
| + ///
|
| + /// builder.split('path/to/foo'); // -> ['path', 'to', 'foo']
|
| + ///
|
| + /// If [path] is absolute, the root directory will be the first element in the
|
| + /// array. Example:
|
| + ///
|
| + /// // Unix
|
| + /// builder.split('/path/to/foo'); // -> ['/', 'path', 'to', 'foo']
|
| + ///
|
| + /// // Windows
|
| + /// builder.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
|
| + List<String> split(String path) {
|
| + var parsed = _parse(path);
|
| + // Filter out empty parts that exist due to multiple separators in a row.
|
| + parsed.parts = parsed.parts.filter((part) => part != '');
|
| + if (parsed.root != null) parsed.parts.insertRange(0, 1, parsed.root);
|
| + return parsed.parts;
|
| + }
|
| +
|
| /// Normalizes [path], simplifying it by handling `..`, and `.`, and
|
| /// removing redundant path separators whenever possible.
|
| ///
|
| @@ -278,23 +366,44 @@ class Builder {
|
| /// builder.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
|
| /// builder.relative('/root/other.dart'); // -> '../other.dart'
|
| ///
|
| + /// If the [from] argument is passed, [path] is made relative to that instead.
|
| + ///
|
| + /// builder.relative('/root/path/a/b.dart',
|
| + /// from: '/root/path'); // -> 'a/b.dart'
|
| + /// builder.relative('/root/other.dart',
|
| + /// from: '/root/path'); // -> '../other.dart'
|
| + ///
|
| /// Since there is no relative path from one drive letter to another on
|
| /// Windows, this will return an absolute path in that case.
|
| ///
|
| - /// var builder = new Builder(root: r'C:\home');
|
| - /// builder.relative(r'D:\other'); // -> 'D:\other'
|
| - String relative(String path) {
|
| + /// builder.relative(r'D:\other', from: r'C:\other'); // -> 'D:\other'
|
| + ///
|
| + /// This will also return an absolute path if an absolute [path] is passed to
|
| + /// a builder with a relative [root].
|
| + ///
|
| + /// var builder = new Builder(r'some/relative/path');
|
| + /// builder.relative(r'/absolute/path'); // -> '/absolute/path'
|
| + String relative(String path, {String from}) {
|
| if (path == '') return '.';
|
|
|
| - // If the base path is relative, resolve it relative to the current
|
| - // directory.
|
| - var base = root;
|
| - if (this.isRelative(base)) base = absolute(base);
|
| + from = from == null ? root : this.join(root, from);
|
| +
|
| + // We can't determine the path from a relative path to an absolute path.
|
| + if (this.isRelative(from) && this.isAbsolute(path)) {
|
| + return this.normalize(path);
|
| + }
|
|
|
| - // If the given path is relative, resolve it relative to the base.
|
| - if (this.isRelative(path)) return this.normalize(path);
|
| + // If the given path is relative, resolve it relative to the root of the
|
| + // builder.
|
| + if (this.isRelative(path)) path = this.resolve(path);
|
| +
|
| + // If the path is still relative and `from` is absolute, we're unable to
|
| + // find a path from `from` to `path`.
|
| + if (this.isRelative(path) && this.isAbsolute(from)) {
|
| + throw new ArgumentError('Unable to find a path to "$path" from "$from".');
|
| + }
|
|
|
| - var baseParsed = _parse(base)..normalize();
|
| + var fromParsed = _parse(from)..normalize();
|
| var pathParsed = _parse(path)..normalize();
|
|
|
| // If the root prefixes don't match (for example, different drive letters
|
| @@ -302,21 +411,21 @@ class Builder {
|
| // one.
|
| // TODO(rnystrom): Drive letters are case-insentive on Windows. Should
|
| // handle "C:\" and "c:\" being the same root.
|
| - if (baseParsed.root != pathParsed.root) return pathParsed.toString();
|
| + if (fromParsed.root != pathParsed.root) return pathParsed.toString();
|
|
|
| // Strip off their common prefix.
|
| - while (baseParsed.parts.length > 0 && pathParsed.parts.length > 0 &&
|
| - baseParsed.parts[0] == pathParsed.parts[0]) {
|
| - baseParsed.parts.removeAt(0);
|
| - baseParsed.separators.removeAt(0);
|
| + while (fromParsed.parts.length > 0 && pathParsed.parts.length > 0 &&
|
| + fromParsed.parts[0] == pathParsed.parts[0]) {
|
| + fromParsed.parts.removeAt(0);
|
| + fromParsed.separators.removeAt(0);
|
| pathParsed.parts.removeAt(0);
|
| pathParsed.separators.removeAt(0);
|
| }
|
|
|
| // If there are any directories left in the root path, we need to walk up
|
| // out of them.
|
| - pathParsed.parts.insertRange(0, baseParsed.parts.length, '..');
|
| - pathParsed.separators.insertRange(0, baseParsed.parts.length,
|
| + pathParsed.parts.insertRange(0, fromParsed.parts.length, '..');
|
| + pathParsed.separators.insertRange(0, fromParsed.parts.length,
|
| style.separator);
|
|
|
| // Corner case: the paths completely collapsed.
|
|
|