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

Side by Side Diff: tools/migration/lib/src/path.dart

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

Powered by Google App Engine
This is Rietveld 408576698