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

Side by Side Diff: runtime/bin/path_impl.dart

Issue 10417053: Add Path class to dart:io, and add unit tests for it. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix 2 bugs. Created 8 years, 6 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 | « runtime/bin/path.dart ('k') | tests/standalone/io/path_test.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 class _Path implements Path {
6 final String path;
7
8 const _Path(String source) : path = source;
9 _Path.fromNative(String source) : path = _clean(source);
10
11 static String _clean(String source) {
12 switch (Platform.operatingSystem) {
13 case 'windows':
14 return _cleanWindows(source);
15 default:
16 return source;
17 }
18 }
19
20 static String _cleanWindows(source) {
21 // Change \ to /.
22 var clean = source.replaceAll('\\', '/');
23 // Add / before intial [Drive letter]:
24 if (clean.length >= 2 && clean[1] == ':') {
25 clean = '/$clean';
26 }
27 return clean;
28 }
29
30 bool get isEmpty() => path.isEmpty();
31 bool get isAbsolute() => path.startsWith('/');
32 bool get hasTrailingSeparator() => path.endsWith('/');
33
34 String toString() => path;
35
36 Path relativeTo(Path base) {
37 // Throws exception if an unimplemented or impossible case is reached.
38 // Returns a path "relative" such that
39 // base.join(relative) == this.canonlicalize.
40 // Throws an exception if no such path exists, or the case is not
41 // implemented yet.
42 if (base.isAbsolute && path.startsWith(base.path)) {
43 if (path == base.path) return new Path('.');
44 if (path[base.path.length] == '/') {
45 return new Path(path.substring(base.path.length + 1));
46 }
47 }
48 throw new NotImplementedException(
49 "Unimplemented case of Path.relativeTo(base):\n"
50 " Only absolute paths with strict containment are handled at present.\n"
51 " Arguments: $path.relativeTo($base)");
52 }
53
54 Path join(Path further) {
55 if (further.isAbsolute) {
56 throw new IllegalArgumentException(
57 "Path.join called with absolute Path as argument.");
58 }
59 if (isEmpty) {
60 return further.canonicalize();
61 }
62 if (hasTrailingSeparator) {
63 return new Path('$path${further.path}').canonicalize();
64 }
65 return new Path('$path/${further.path}').canonicalize();
66 }
67
68 // Note: The URI RFC names for these operations are normalize, resolve, and
69 // relativize.
70 Path canonicalize() {
71 if (isCanonical) return this;
72 return makeCanonical();
73 }
74
75 bool get isCanonical() {
76 // Contains no consecutive path separators.
77 // Contains no segments that are '.'.
78 // Absolute paths have no segments that are '..'.
79 // All '..' segments of a relative path are at the beginning.
80 if (isEmpty) return false; // The canonical form of '' is '.'.
81 if (path == '.') return true;
82 List segs = path.split('/'); // Don't mask the getter 'segments'.
83 if (segs[0] == '') { // Absolute path
84 segs[0] = null; // Faster than removeRange().
85 } else { // A canonical relative path may start with .. segments.
86 for (int pos = 0;
87 pos < segs.length && segs[pos] == '..';
88 ++pos) {
89 segs[pos] = null;
90 }
91 }
92 if (segs.last() == '') segs.removeLast(); // Path ends with /.
93 // No remaining segments can be ., .., or empty.
94 return !segs.some((s) => s == '' || s == '.' || s == '..');
95 }
96
97 Path makeCanonical() {
98 bool isAbs = isAbsolute;
99 List segs = segments();
100 String drive;
101 if (isAbs &&
102 !segs.isEmpty() &&
103 segs[0].length == 2 &&
104 segs[0][1] == ':') {
105 drive = segs[0];
106 segs.removeRange(0, 1);
107 }
108 List newSegs = [];
109 for (String segment in segs) {
110 switch (segment) {
111 case '..':
112 // Absolute paths drop leading .. markers, including after a drive.
113 if (newSegs.isEmpty()) {
114 if (isAbs) {
115 // Do nothing: drop the segment.
116 } else {
117 newSegs.add('..');
118 }
119 } else if (newSegs.last() == '..') {
120 newSegs.add('..');
121 } else {
122 newSegs.removeLast();
123 }
124 break;
125 case '.':
126 case '':
127 // Do nothing - drop the segment.
128 break;
129 default:
130 newSegs.add(segment);
131 break;
132 }
133 }
134
135 List segmentsToJoin = [];
136 if (isAbs) {
137 segmentsToJoin.add('');
138 if (drive != null) {
139 segmentsToJoin.add(drive);
140 }
141 }
142
143 if (newSegs.isEmpty()) {
144 if (isAbs) {
145 segmentsToJoin.add('');
146 } else {
147 segmentsToJoin.add('.');
148 }
149 } else {
150 segmentsToJoin.addAll(newSegs);
151 if (hasTrailingSeparator) {
152 segmentsToJoin.add('');
153 }
154 }
155 return new Path(Strings.join(segmentsToJoin, '/'));
156 }
157
158
159 String toNativePath() {
160 if (Platform.operatingSystem == 'windows') {
161 String nativePath = path;
162 // Drop '/' before a drive letter.
163 if (nativePath.startsWith('/') && nativePath[2] == ':') {
164 nativePath = nativePath.substring(1);
165 }
166 nativePath = nativePath.replaceAll('/', '\\');
167 return nativePath;
168 }
169 return path;
170 }
171
172 List<String> segments() {
173 List result = path.split('/');
174 if (isAbsolute) result.removeRange(0, 1);
175 if (hasTrailingSeparator) result.removeLast();
176 return result;
177 }
178
179 String get filenameWithoutExtension() {
180 var name = filename;
181 int pos = name.lastIndexOf('.');
182 return (pos < 0) ? name : name.substring(0, pos);
183 }
184
185 String get extension() {
186 var name = filename;
187 int pos = name.lastIndexOf('.');
188 return (pos < 0) ? '' : name.substring(pos + 1);
189 }
190
191 Path get directoryPath() {
192 int pos = path.lastIndexOf('/');
193 if (pos < 0) return new Path('');
194 while (pos > 0 && path[pos - 1] == '/') --pos;
195 return new Path((pos > 0) ? path.substring(0, pos) : '/');
196 }
197
198 String get filename() {
199 int pos = path.lastIndexOf('/');
200 return path.substring(pos + 1);
201 }
202 }
OLDNEW
« no previous file with comments | « runtime/bin/path.dart ('k') | tests/standalone/io/path_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698