| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A Path is an immutable wrapper of a String, with additional member functions | 8 * A Path is an immutable wrapper of a String, with additional member functions |
| 9 * for useful path manipulations and queries. | 9 * for useful path manipulations and queries. |
| 10 * On the Windows platform, Path also converts from and to native paths. | 10 * On the Windows platform, Path also converts from native paths to paths using |
| 11 * '/' as a path separator, and vice versa. |
| 11 * | 12 * |
| 12 * Joining of paths and path normalization handle '.' and '..' in the usual way. | 13 * Joining of paths and path normalization handle '.' and '..' in the usual way. |
| 13 */ | 14 */ |
| 14 abstract class Path { | 15 abstract class Path { |
| 15 /** | 16 /** |
| 16 * Creates a Path from a String that uses the native filesystem's conventions. | 17 * Creates a Path from a String that uses the native filesystem's conventions. |
| 17 * | 18 * |
| 18 * On Windows, this converts '\' to '/' and has special handling for drive | 19 * On Windows, this converts '\' to '/' and has special handling for drive |
| 19 * letters and shares. | 20 * letters and shares. |
| 20 * | 21 * |
| 21 * If the path starts with a drive letter, like 'C:', a '/' is added | 22 * If the path starts with a drive letter, like 'C:', a '/' is added |
| 22 * before the drive letter. | 23 * before the drive letter. |
| 23 * | 24 * |
| 24 * new Path(r'c:\a\b').toString() == '/c:/a/b' | 25 * new Path(r'c:\a\b').toString() == '/c:/a/b' |
| 25 * | 26 * |
| 26 * A path starting with '/c:/' (or any other character instead of 'c') is | 27 * A path starting with a drive letter is |
| 27 * treated specially. Backwards links ('..') cannot cancel the drive letter. | 28 * treated specially. Backwards links ('..') cannot cancel the drive letter. |
| 28 * | 29 * |
| 29 * If the path is a share path this is recorded in the Path object and | 30 * If the path is a share path this is recorded in the Path object and |
| 30 * maintained in operations on the Path object. | 31 * maintained in operations on the Path object. |
| 31 * | 32 * |
| 32 * var share = new Path(r'\\share\a\b\c'); | 33 * var share = new Path(r'\\share\a\b\c'); |
| 33 * share.isWindowsShare == true | 34 * share.isWindowsShare == true |
| 34 * share.toString() == '/share/a/b/c' | 35 * share.toString() == '/share/a/b/c' |
| 35 * share.toNativePath() == r'\\share\a\b\c' | 36 * share.toNativePath() == r'\\share\a\b\c' |
| 36 * share.append('final').isWindowsShare == true | 37 * share.append('final').isWindowsShare == true |
| 37 */ | 38 */ |
| 38 factory Path(String source) => new _Path(source); | 39 factory Path(String source) => new _Path(source); |
| 39 | 40 |
| 40 /** | 41 /** |
| 41 * Creates a Path from the String [source]. [source] is used as-is, so if | 42 * Creates a Path from the String [source]. [source] is used as-is, so if |
| 42 * the string does not consist of segments separated by forward slashes, the | 43 * the string does not consist of segments separated by forward slashes, the |
| 43 * behavior may not be as expected. Paths are immutable. | 44 * behavior may not be as expected. Paths are immutable. |
| 44 */ | 45 */ |
| 45 factory Path.raw(String source) => new _Path.raw(source); | 46 factory Path.raw(String source) => new _Path.raw(source); |
| 46 | 47 |
| 47 /** | 48 /** |
| 48 * Is this path the empty string? | 49 * Is this path the empty string? |
| 49 */ | 50 */ |
| 50 bool get isEmpty; | 51 bool get isEmpty; |
| 51 | 52 |
| 52 /** | 53 /** |
| 53 * Is this path an absolute path, beginning with a path separator? | 54 * Is this path an absolute path, beginning with a '/'? Note that |
| 55 * Windows paths beginning with '\' or with a drive letter are absolute, |
| 56 * and a leading '/' is added when they are converted to a Path. |
| 54 */ | 57 */ |
| 55 bool get isAbsolute; | 58 bool get isAbsolute; |
| 56 | 59 |
| 57 /** | 60 /** |
| 58 * Is this path a Windows share path? | 61 * Is this path a Windows share path? |
| 59 */ | 62 */ |
| 60 bool get isWindowsShare; | 63 bool get isWindowsShare; |
| 61 | 64 |
| 62 /** | 65 /** |
| 63 * Does this path end with a path separator? | 66 * Does this path end with a '/'? |
| 64 */ | 67 */ |
| 65 bool get hasTrailingSeparator; | 68 bool get hasTrailingSeparator; |
| 66 | 69 |
| 67 /** | 70 /** |
| 68 * Does this path contain no consecutive path separators, no segments that | 71 * Does this path contain no consecutive '/'s, no segments that |
| 69 * are '.' unless the path is exactly '.', and segments that are '..' only | 72 * are '.' unless the path is exactly '.', and segments that are '..' only |
| 70 * as the leading segments on a relative path? | 73 * as the leading segments on a relative path? |
| 71 */ | 74 */ |
| 72 bool get isCanonical; | 75 bool get isCanonical; |
| 73 | 76 |
| 74 /** | 77 /** |
| 75 * Make a path canonical by dropping segments that are '.', cancelling | 78 * Make a path canonical by dropping segments that are '.', cancelling |
| 76 * segments that are '..' with preceding segments, if possible, | 79 * segments that are '..' with preceding segments, if possible, |
| 77 * and combining consecutive path separators. Leading '..' segments | 80 * and combining consecutive '/'s. Leading '..' segments |
| 78 * are kept on relative paths, and dropped from absolute paths. | 81 * are kept on relative paths, and dropped from absolute paths. |
| 79 */ | 82 */ |
| 80 Path canonicalize(); | 83 Path canonicalize(); |
| 81 | 84 |
| 82 /** | 85 /** |
| 83 * Joins the relative path [further] to this path. Canonicalizes the | 86 * Joins the relative path [further] to this path. Canonicalizes the |
| 84 * resulting joined path using [canonicalize], | 87 * resulting joined path using [canonicalize], |
| 85 * interpreting '.' and '..' as directory traversal commands, and removing | 88 * interpreting '.' and '..' as directory traversal commands, and removing |
| 86 * consecutive path separators. | 89 * consecutive '/'s. |
| 87 * | 90 * |
| 88 * If [further] is an absolute path, an IllegalArgument exception is thrown. | 91 * If [further] is an absolute path, an IllegalArgument exception is thrown. |
| 89 * | 92 * |
| 90 * Examples: | 93 * Examples: |
| 91 * `new Path('/a/b/c').join(new Path('d/e'))` returns the Path object | 94 * `new Path('/a/b/c').join(new Path('d/e'))` returns the Path object |
| 92 * containing `'a/b/c/d/e'`. | 95 * containing `'a/b/c/d/e'`. |
| 93 * | 96 * |
| 94 * `new Path('a/b/../c/').join(new Path('d/./e//')` returns the Path | 97 * `new Path('a/b/../c/').join(new Path('d/./e//')` returns the Path |
| 95 * containing `'a/c/d/e/'`. | 98 * containing `'a/c/d/e/'`. |
| 96 * | 99 * |
| 97 * `new Path('a/b/c').join(new Path('d/../../e')` returns the Path | 100 * `new Path('a/b/c').join(new Path('d/../../e')` returns the Path |
| 98 * containing `'a/b/e'`. | 101 * containing `'a/b/e'`. |
| 99 * | 102 * |
| 100 * Note that the join operation does not drop the last segment of the | 103 * Note that the join operation does not drop the last segment of the |
| 101 * base path, the way URL joining does. That would be accomplished with | 104 * base path, the way URL joining does. To join basepath to further using |
| 102 * basepath.directoryPath.join(further). | 105 * URL semantics, use |
| 106 * [:basepath.directoryPath.join(further):]. |
| 103 * | 107 * |
| 104 * If you want to avoid joins that traverse | 108 * If you want to avoid joins that traverse |
| 105 * parent directories in the base, you can check whether | 109 * parent directories in the base, you can check whether |
| 106 * `further.canonicalize()` starts with '../' or equals '..'. | 110 * `further.canonicalize()` starts with '../' or equals '..'. |
| 107 */ | 111 */ |
| 108 Path join(Path further); | 112 Path join(Path further); |
| 109 | 113 |
| 110 | 114 |
| 111 /** | 115 /** |
| 112 * Returns a path [:relative:] such that | 116 * Returns a path [:relative:] such that |
| 113 * [:base.join(relative) == this.canonicalize():]. | 117 * [:base.join(relative) == this.canonicalize():]. |
| 114 * Throws an exception if such a path is impossible. | 118 * Throws an exception if such a path is impossible. |
| 115 * For example, if [base] is '../../a/b' and [this] is '.'. | 119 * For example, if [base] is '../../a/b' and [this] is '.'. |
| 116 * The computation is independent of the file system and current directory. | 120 * The computation is independent of the file system and current directory. |
| 121 * |
| 122 * To compute a relative path using URL semantics, where the final |
| 123 * path component of the base is dropped unless it ends with a slash, |
| 124 * call [: a.relativeTo(b.directoryPath) :] instead of [: a.relativeTo(b) :]. |
| 117 */ | 125 */ |
| 118 Path relativeTo(Path base); | 126 Path relativeTo(Path base); |
| 119 | 127 |
| 120 /** | 128 /** |
| 121 * Converts a path to a string using the native filesystem's conventions. | 129 * Converts a path to a string using the native filesystem's conventions. |
| 122 * | 130 * |
| 123 * On Windows, converts path separators to backwards slashes, and removes | 131 * On Windows, converts '/'s to backwards slashes, and removes |
| 124 * the leading path separator if the path starts with a drive specification. | 132 * the leading '/' if the path starts with a drive specification. |
| 125 * For most valid Windows paths, this should be the inverse of the | 133 * For most valid Windows paths, this should be the inverse of the |
| 126 * constructor Path.fromNative. | 134 * conversion that the constructor new Path() performs. If the path is |
| 135 * a Windows share, restores the '\\' at the start of the path. |
| 127 */ | 136 */ |
| 128 String toNativePath(); | 137 String toNativePath(); |
| 129 | 138 |
| 130 /** | 139 /** |
| 131 * Returns the path as a string. If this path is constructed using | 140 * Returns the path as a string. If this path is constructed using |
| 132 * new Path.raw(), or new Path() on a non-Windows system, the | 141 * new Path.raw(), or new Path() on a non-Windows system, the |
| 133 * returned value is the original string argument to the constructor. | 142 * returned value is the original string argument to the constructor. |
| 134 */ | 143 */ |
| 135 String toString(); | 144 String toString(); |
| 136 | 145 |
| 137 /** | 146 /** |
| 138 * Gets the segments of a Path. Paths beginning or ending with the | 147 * Gets the segments of a Path. The segments are just the result of |
| 139 * path separator do not have leading or terminating empty segments. | 148 * splitting the path on any '/' characters, except that a '/' at the |
| 140 * Other than that, the segments are just the result of splitting the | 149 * beginning does not create an empty segment before it, and a '/' at |
| 141 * path on the path separator. | 150 * the end does not create an empty segment after it. |
| 142 * | 151 * |
| 143 * new Path('/a/b/c/d').segments() == ['a', 'b', 'c', d']; | 152 * new Path('/a/b/c/d').segments() == ['a', 'b', 'c', d']; |
| 144 * new Path(' foo bar //../') == [' foo bar ', '', '..']; | 153 * new Path(' foo bar //../') == [' foo bar ', '', '..']; |
| 145 */ | 154 */ |
| 146 List<String> segments(); | 155 List<String> segments(); |
| 147 | 156 |
| 148 /** | 157 /** |
| 149 * Appends [finalSegment] to a path as a new segment. Adds a path separator | 158 * Appends [finalSegment] to a path as a new segment. Adds a '/' |
| 150 * between the path and [finalSegment] if the path does not already end in | 159 * between the path and [finalSegment] if the path does not already end in |
| 151 * a path separator. The path is not canonicalized, and [finalSegment] may | 160 * a '/'. The path is not canonicalized, and [finalSegment] may |
| 152 * contain path separators. | 161 * contain '/'s. |
| 153 */ | 162 */ |
| 154 Path append(String finalSegment); | 163 Path append(String finalSegment); |
| 155 | 164 |
| 156 /** | 165 /** |
| 157 * Drops the final path separator and whatever follows it from this Path, | 166 * Drops the final '/' and whatever follows it from this Path, |
| 158 * and returns the resulting Path object. If the only path separator in | 167 * and returns the resulting Path object. If the only '/' in |
| 159 * this Path is the first character, returns '/' instead of the empty string. | 168 * this Path is the first character, returns '/' instead of the empty string. |
| 160 * If there is no path separator in the Path, returns the empty string. | 169 * If there is no '/' in the Path, returns the empty string. |
| 161 * | 170 * |
| 162 * new Path('../images/dot.gif').directoryPath == '../images' | 171 * new Path('../images/dot.gif').directoryPath == '../images' |
| 163 * new Path('/usr/geoffrey/www/').directoryPath == '/usr/geoffrey/www' | 172 * new Path('/usr/geoffrey/www/').directoryPath == '/usr/geoffrey/www' |
| 164 * new Path('lost_file_old').directoryPath == '' | 173 * new Path('lost_file_old').directoryPath == '' |
| 165 * new Path('/src').directoryPath == '/' | 174 * new Path('/src').directoryPath == '/' |
| 166 * Note: new Path('/D:/src').directoryPath == '/D:' | 175 * Note: new Path('/D:/src').directoryPath == '/D:' |
| 167 */ | 176 */ |
| 168 Path get directoryPath; | 177 Path get directoryPath; |
| 169 | 178 |
| 170 /** | 179 /** |
| 171 * The part of the path after the last path separator, or the entire path if | 180 * The part of the path after the last '/', or the entire path if |
| 172 * it contains no path separator. | 181 * it contains no '/'. |
| 173 * | 182 * |
| 174 * new Path('images/DSC_0027.jpg).filename == 'DSC_0027.jpg' | 183 * new Path('images/DSC_0027.jpg).filename == 'DSC_0027.jpg' |
| 175 * new Path('users/fred/').filename == '' | 184 * new Path('users/fred/').filename == '' |
| 176 */ | 185 */ |
| 177 String get filename; | 186 String get filename; |
| 178 | 187 |
| 179 /** | 188 /** |
| 180 * The part of [filename] before the last '.', or the entire filename if it | 189 * The part of [filename] before the last '.', or the entire filename if it |
| 181 * contains no '.'. If [filename] is '.' or '..' it is unchanged. | 190 * contains no '.'. If [filename] is '.' or '..' it is unchanged. |
| 182 * | 191 * |
| 183 * new Path('/c:/My Documents/Heidi.txt').filenameWithoutExtension | 192 * new Path('/c:/My Documents/Heidi.txt').filenameWithoutExtension |
| 184 * would return 'Heidi'. | 193 * would return 'Heidi'. |
| 185 * new Path('not what I would call a path').filenameWithoutExtension | 194 * new Path('not what I would call a path').filenameWithoutExtension |
| 186 * would return 'not what I would call a path'. | 195 * would return 'not what I would call a path'. |
| 187 */ | 196 */ |
| 188 String get filenameWithoutExtension; | 197 String get filenameWithoutExtension; |
| 189 | 198 |
| 190 /** | 199 /** |
| 191 * The part of [filename] after the last '.', or '' if [filename] | 200 * The part of [filename] after the last '.', or '' if [filename] |
| 192 * contains no '.'. If [filename] is '.' or '..', returns ''. | 201 * contains no '.'. If [filename] is '.' or '..', returns ''. |
| 193 * | 202 * |
| 194 * new Path('tiger.svg').extension == 'svg' | 203 * new Path('tiger.svg').extension == 'svg' |
| 195 * new Path('/src/dart/dart_secrets').extension == '' | 204 * new Path('/src/dart/dart_secrets').extension == '' |
| 196 */ | 205 */ |
| 197 String get extension; | 206 String get extension; |
| 198 } | 207 } |
| OLD | NEW |