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

Side by Side Diff: tools/testing/dart/path.dart

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

Powered by Google App Engine
This is Rietveld 408576698