Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: sdk/lib/io/path_impl.dart

Issue 25421003: dart:io | Remove deprecated _Path library, and use FileSystemEntity.parent for recursive Directory.… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/io/path.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.io;
6
7 class __Path implements _Path {
8 final String _path;
9 final bool isWindowsShare;
10
11 __Path(String source)
12 : _path = _clean(source), isWindowsShare = _isWindowsShare(source);
13
14 __Path.raw(String source) : _path = source, isWindowsShare = false;
15
16 __Path._internal(String this._path, bool this.isWindowsShare);
17
18 static String _clean(String source) {
19 if (Platform.operatingSystem == 'windows') return _cleanWindows(source);
20 return source;
21 }
22
23 static String _cleanWindows(String source) {
24 // Change \ to /.
25 var clean = source.replaceAll('\\', '/');
26 // Add / before intial [Drive letter]:
27 if (clean.length >= 2 && clean[1] == ':') {
28 clean = '/$clean';
29 }
30 if (_isWindowsShare(source)) {
31 return clean.substring(1, clean.length);
32 }
33 return clean;
34 }
35
36 static bool _isWindowsShare(String source) {
37 return Platform.operatingSystem == 'windows' && source.startsWith('\\\\');
38 }
39
40 int get hashCode => _path.hashCode;
41 bool get isEmpty => _path.isEmpty;
42 bool get isAbsolute => _path.startsWith('/');
43 bool get hasTrailingSeparator => _path.endsWith('/');
44
45 String toString() => _path;
46
47 _Path relativeTo(_Path base) {
48 // Returns a path "relative" such that
49 // base.join(relative) == this.canonicalize.
50 // Throws exception if an impossible case is reached.
51 if (base.isAbsolute != isAbsolute ||
52 base.isWindowsShare != isWindowsShare) {
53 throw new ArgumentError(
54 "Invalid case of _Path.relativeTo(base):\n"
55 " Path and base must both be relative, or both absolute.\n"
56 " Arguments: $_path.relativeTo($base)");
57 }
58
59 var basePath = base.toString();
60 // Handle drive letters specially on Windows.
61 if (base.isAbsolute && Platform.operatingSystem == 'windows') {
62 bool baseHasDrive =
63 basePath.length >= 4 && basePath[2] == ':' && basePath[3] == '/';
64 bool pathHasDrive =
65 _path.length >= 4 && _path[2] == ':' && _path[3] == '/';
66 if (baseHasDrive && pathHasDrive) {
67 int baseDrive = basePath.codeUnitAt(1) | 32; // Convert to uppercase.
68 if (baseDrive >= 'a'.codeUnitAt(0) &&
69 baseDrive <= 'z'.codeUnitAt(0) &&
70 baseDrive == (_path.codeUnitAt(1) | 32)) {
71 if(basePath[1] != _path[1]) {
72 // Replace the drive letter in basePath with that from _path.
73 basePath = '/${_path[1]}:/${basePath.substring(4)}';
74 base = new _Path(basePath);
75 }
76 } else {
77 throw new ArgumentError(
78 "Invalid case of _Path.relativeTo(base):\n"
79 " Base path and target path are on different Windows drives.\n"
80 " Arguments: $_path.relativeTo($base)");
81 }
82 } else if (baseHasDrive != pathHasDrive) {
83 throw new ArgumentError(
84 "Invalid case of _Path.relativeTo(base):\n"
85 " Base path must start with a drive letter if and "
86 "only if target path does.\n"
87 " Arguments: $_path.relativeTo($base)");
88 }
89
90 }
91 if (_path.startsWith(basePath)) {
92 if (_path == basePath) return new _Path('.');
93 // There must be a '/' at the end of the match, or immediately after.
94 int matchEnd = basePath.length;
95 if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') {
96 // Drop any extra '/' characters at matchEnd
97 while (matchEnd < _path.length && _path[matchEnd] == '/') {
98 matchEnd++;
99 }
100 return new _Path(_path.substring(matchEnd)).canonicalize();
101 }
102 }
103
104 List<String> baseSegments = base.canonicalize().segments();
105 List<String> pathSegments = canonicalize().segments();
106 if (baseSegments.length == 1 && baseSegments[0] == '.') {
107 baseSegments = [];
108 }
109 if (pathSegments.length == 1 && pathSegments[0] == '.') {
110 pathSegments = [];
111 }
112 int common = 0;
113 int length = min(pathSegments.length, baseSegments.length);
114 while (common < length && pathSegments[common] == baseSegments[common]) {
115 common++;
116 }
117 final segments = new List<String>();
118
119 if (common < baseSegments.length && baseSegments[common] == '..') {
120 throw new ArgumentError(
121 "Invalid case of _Path.relativeTo(base):\n"
122 " Base path has more '..'s than path does.\n"
123 " Arguments: $_path.relativeTo($base)");
124 }
125 for (int i = common; i < baseSegments.length; i++) {
126 segments.add('..');
127 }
128 for (int i = common; i < pathSegments.length; i++) {
129 segments.add('${pathSegments[i]}');
130 }
131 if (segments.isEmpty) {
132 segments.add('.');
133 }
134 if (hasTrailingSeparator) {
135 segments.add('');
136 }
137 return new _Path(segments.join('/'));
138 }
139
140
141 _Path join(_Path further) {
142 if (further.isAbsolute) {
143 throw new ArgumentError(
144 "Path.join called with absolute Path as argument.");
145 }
146 if (isEmpty) {
147 return further.canonicalize();
148 }
149 if (hasTrailingSeparator) {
150 var joined = new __Path._internal('$_path${further}', isWindowsShare);
151 return joined.canonicalize();
152 }
153 var joined = new __Path._internal('$_path/${further}', isWindowsShare);
154 return joined.canonicalize();
155 }
156
157 // Note: The URI RFC names for canonicalize, join, and relativeTo
158 // are normalize, resolve, and relativize. But resolve and relativize
159 // drop the last segment of the base path (the filename), on URIs.
160 _Path canonicalize() {
161 if (isCanonical) return this;
162 return makeCanonical();
163 }
164
165 bool get isCanonical {
166 // Contains no consecutive path separators.
167 // Contains no segments that are '.'.
168 // Absolute paths have no segments that are '..'.
169 // All '..' segments of a relative path are at the beginning.
170 if (isEmpty) return false; // The canonical form of '' is '.'.
171 if (_path == '.') return true;
172 List segs = _path.split('/'); // Don't mask the getter 'segments'.
173 if (segs[0] == '') { // Absolute path
174 segs[0] = null; // Faster than removeRange().
175 } else { // A canonical relative path may start with .. segments.
176 for (int pos = 0;
177 pos < segs.length && segs[pos] == '..';
178 ++pos) {
179 segs[pos] = null;
180 }
181 }
182 if (segs.last == '') segs.removeLast(); // Path ends with /.
183 // No remaining segments can be ., .., or empty.
184 return !segs.any((s) => s == '' || s == '.' || s == '..');
185 }
186
187 _Path makeCanonical() {
188 bool isAbs = isAbsolute;
189 List segs = segments();
190 String drive;
191 if (isAbs &&
192 !segs.isEmpty &&
193 segs[0].length == 2 &&
194 segs[0][1] == ':') {
195 drive = segs[0];
196 segs.removeRange(0, 1);
197 }
198 List newSegs = [];
199 for (String segment in segs) {
200 switch (segment) {
201 case '..':
202 // Absolute paths drop leading .. markers, including after a drive.
203 if (newSegs.isEmpty) {
204 if (isAbs) {
205 // Do nothing: drop the segment.
206 } else {
207 newSegs.add('..');
208 }
209 } else if (newSegs.last == '..') {
210 newSegs.add('..');
211 } else {
212 newSegs.removeLast();
213 }
214 break;
215 case '.':
216 case '':
217 // Do nothing - drop the segment.
218 break;
219 default:
220 newSegs.add(segment);
221 break;
222 }
223 }
224
225 List segmentsToJoin = [];
226 if (isAbs) {
227 segmentsToJoin.add('');
228 if (drive != null) {
229 segmentsToJoin.add(drive);
230 }
231 }
232
233 if (newSegs.isEmpty) {
234 if (isAbs) {
235 segmentsToJoin.add('');
236 } else {
237 segmentsToJoin.add('.');
238 }
239 } else {
240 segmentsToJoin.addAll(newSegs);
241 if (hasTrailingSeparator) {
242 segmentsToJoin.add('');
243 }
244 }
245 return new __Path._internal(segmentsToJoin.join('/'), isWindowsShare);
246 }
247
248 String toNativePath() {
249 if (isEmpty) return '.';
250 if (Platform.operatingSystem == 'windows') {
251 String nativePath = _path;
252 // Drop '/' before a drive letter.
253 if (nativePath.length >= 3 &&
254 nativePath.startsWith('/') &&
255 nativePath[2] == ':') {
256 nativePath = nativePath.substring(1);
257 }
258 nativePath = nativePath.replaceAll('/', '\\');
259 if (isWindowsShare) {
260 return '\\$nativePath';
261 }
262 return nativePath;
263 }
264 return _path;
265 }
266
267 List<String> segments() {
268 List result = _path.split('/');
269 if (isAbsolute) result.removeRange(0, 1);
270 if (hasTrailingSeparator) result.removeLast();
271 return result;
272 }
273
274 _Path append(String finalSegment) {
275 if (isEmpty) {
276 return new __Path._internal(finalSegment, isWindowsShare);
277 } else if (hasTrailingSeparator) {
278 return new __Path._internal('$_path$finalSegment', isWindowsShare);
279 } else {
280 return new __Path._internal('$_path/$finalSegment', isWindowsShare);
281 }
282 }
283
284 String get filenameWithoutExtension {
285 var name = filename;
286 if (name == '.' || name == '..') return name;
287 int pos = name.lastIndexOf('.');
288 return (pos < 0) ? name : name.substring(0, pos);
289 }
290
291 String get extension {
292 var name = filename;
293 int pos = name.lastIndexOf('.');
294 return (pos < 0) ? '' : name.substring(pos + 1);
295 }
296
297 _Path get directoryPath {
298 int pos = _path.lastIndexOf('/');
299 if (pos < 0) return new _Path('');
300 while (pos > 0 && _path[pos - 1] == '/') --pos;
301 var dirPath = (pos > 0) ? _path.substring(0, pos) : '/';
302 return new __Path._internal(dirPath, isWindowsShare);
303 }
304
305 String get filename {
306 int pos = _path.lastIndexOf('/');
307 return _path.substring(pos + 1);
308 }
309 }
OLDNEW
« no previous file with comments | « sdk/lib/io/path.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698