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

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

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

Powered by Google App Engine
This is Rietveld 408576698