Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2014, 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 resource; | |
| 6 | |
| 7 import 'dart:io' as io; | |
| 8 | |
| 9 import 'package:analyzer/src/generated/engine.dart' show TimestampedData; | |
| 10 import 'package:analyzer/src/generated/java_io.dart'; | |
| 11 import 'package:analyzer/src/generated/source_io.dart'; | |
| 12 import 'package:path/path.dart'; | |
| 13 | |
| 14 | |
| 15 /** | |
| 16 * [File]s are leaf [Resource]s which contain data. | |
| 17 */ | |
| 18 abstract class File extends Resource { | |
| 19 /** | |
| 20 * Create a new [Source] instance that serves this file. | |
| 21 */ | |
| 22 Source createSource(UriKind uriKind); | |
| 23 } | |
| 24 | |
| 25 | |
| 26 /** | |
| 27 * [Folder]s are [Resource]s which may contain files and/or other folders. | |
| 28 */ | |
| 29 abstract class Folder extends Resource { | |
| 30 /** | |
| 31 * Return an existing child [Resource] with the given [relPath]. | |
| 32 * Return a not existing [File] if no such child exist. | |
| 33 */ | |
| 34 Resource getChild(String relPath); | |
| 35 | |
| 36 /** | |
| 37 * Return a list of existing direct children [Resource]s (folders and files) | |
| 38 * in this folder, in no particular order. | |
| 39 */ | |
| 40 List<Resource> getChildren(); | |
| 41 } | |
| 42 | |
| 43 | |
| 44 /** | |
| 45 * The abstract class [Resource] is an abstraction of file or folder. | |
| 46 */ | |
| 47 abstract class Resource { | |
| 48 /** | |
| 49 * Return `true` if this resource exists. | |
| 50 */ | |
| 51 bool get exists; | |
| 52 | |
| 53 /** | |
| 54 * Return the full (long) version of the name that can be displayed to the | |
| 55 * user to denote this resource. | |
| 56 */ | |
| 57 String get fullName; | |
| 58 | |
| 59 /** | |
| 60 * Return a short version of the name that can be displayed to the user to | |
| 61 * denote this resource. | |
| 62 */ | |
| 63 String get shortName; | |
| 64 } | |
| 65 | |
| 66 | |
| 67 /** | |
| 68 * Instances of the class [ResourceProvider] convert [String] paths into | |
| 69 * [Resource]s. | |
| 70 */ | |
| 71 abstract class ResourceProvider { | |
| 72 /** | |
| 73 * Return the [Resource] that corresponds to the given [path]. | |
| 74 */ | |
| 75 Resource getResource(String path); | |
| 76 } | |
| 77 | |
| 78 | |
| 79 /** | |
| 80 * An in-memory implementation of [Resource]. | |
| 81 */ | |
| 82 abstract class _MemoryResource implements Resource { | |
| 83 final MemoryResourceProvider _provider; | |
| 84 final String _path; | |
| 85 | |
| 86 _MemoryResource(this._provider, this._path); | |
| 87 | |
| 88 @override | |
| 89 bool operator ==(o) { | |
|
Brian Wilkerson
2014/05/25 15:29:58
I really dislike single character variable names f
scheglov
2014/05/25 16:16:38
Done.
| |
| 90 return identical(this, o); | |
| 91 } | |
| 92 | |
| 93 @override | |
| 94 bool get exists => _provider._pathToResource.containsKey(_path); | |
| 95 | |
| 96 @override | |
| 97 String get fullName => _path; | |
| 98 | |
| 99 @override | |
| 100 get hashCode => _path.hashCode; | |
| 101 | |
| 102 @override | |
| 103 String get shortName => basename(_path); | |
| 104 | |
| 105 @override | |
| 106 String toString() => fullName; | |
| 107 } | |
| 108 | |
| 109 | |
| 110 /** | |
| 111 * An in-memory implementation of [File]. | |
| 112 */ | |
| 113 class _MemoryFile extends _MemoryResource implements File { | |
| 114 _MemoryFile(MemoryResourceProvider provider, String path) : | |
| 115 super(provider, path); | |
| 116 | |
| 117 @override | |
| 118 Source createSource(UriKind uriKind) { | |
| 119 return new _MemoryFileSource(this, uriKind); | |
| 120 } | |
| 121 | |
| 122 String get _content => _provider._pathToContent[_path]; | |
| 123 | |
| 124 int get _timestamp => _provider._pathToTimestamp[_path]; | |
| 125 } | |
| 126 | |
| 127 | |
| 128 /** | |
| 129 * An in-memory implementation of [Source]. | |
| 130 */ | |
| 131 class _MemoryFileSource implements Source { | |
| 132 final _MemoryFile _file; | |
| 133 | |
| 134 final UriKind uriKind; | |
| 135 | |
| 136 _MemoryFileSource(this._file, this.uriKind); | |
| 137 | |
| 138 @override | |
| 139 TimestampedData<String> get contents { | |
| 140 return new TimestampedData<String>(modificationStamp, _file._content); | |
| 141 } | |
| 142 | |
| 143 @override | |
| 144 String get encoding { | |
| 145 return '${new String.fromCharCode(uriKind.encoding)}${_file.fullName}'; | |
| 146 } | |
| 147 | |
| 148 @override | |
| 149 bool exists() => _file.exists; | |
| 150 | |
| 151 @override | |
| 152 String get fullName => _file.fullName; | |
| 153 | |
| 154 @override | |
| 155 bool get isInSystemLibrary => false; | |
| 156 | |
| 157 @override | |
| 158 int get modificationStamp => _file._timestamp; | |
| 159 | |
| 160 @override | |
| 161 Source resolveRelative(Uri relativeUri) { | |
| 162 String relativePath = fromUri(relativeUri); | |
| 163 String folderPath = dirname(_file._path); | |
| 164 String path = join(folderPath, relativePath); | |
| 165 path = normalize(path); | |
| 166 _MemoryFile file = new _MemoryFile(_file._provider, path); | |
| 167 return new _MemoryFileSource(file, uriKind); | |
| 168 } | |
| 169 | |
| 170 @override | |
| 171 String get shortName => _file.shortName; | |
| 172 } | |
| 173 | |
| 174 | |
| 175 /** | |
| 176 * An in-memory implementation of [Folder]. | |
| 177 */ | |
| 178 class _MemoryFolder extends _MemoryResource implements Folder { | |
| 179 _MemoryFolder(MemoryResourceProvider provider, String path) : | |
| 180 super(provider, path); | |
| 181 @override | |
| 182 Resource getChild(String relPath) { | |
| 183 relPath = normalize(relPath); | |
| 184 String childPath = join(_path, relPath); | |
| 185 childPath = normalize(childPath); | |
| 186 _MemoryResource resource = _provider._pathToResource[childPath]; | |
| 187 if (resource == null) { | |
| 188 resource = new _MemoryFile(_provider, childPath); | |
| 189 } | |
| 190 return resource; | |
| 191 } | |
| 192 | |
| 193 @override | |
| 194 List<Resource> getChildren() { | |
| 195 List<Resource> children = []; | |
|
Brian Wilkerson
2014/05/25 15:29:58
I think we should include a type annotation with l
scheglov
2014/05/25 16:16:38
Done.
| |
| 196 _provider._pathToResource.forEach((path, resource) { | |
| 197 if (dirname(path) == _path) { | |
| 198 children.add(resource); | |
| 199 } | |
| 200 }); | |
| 201 return children; | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 | |
| 206 /** | |
| 207 * An in-memory implementation of [ResourceProvider]. | |
| 208 * Use `/` as a path separator. | |
| 209 */ | |
| 210 class MemoryResourceProvider implements ResourceProvider { | |
| 211 final Map<String, _MemoryResource> _pathToResource = {}; | |
| 212 final Map<String, String> _pathToContent = {}; | |
| 213 final Map<String, int> _pathToTimestamp = {}; | |
| 214 int nextStamp = 0; | |
| 215 | |
| 216 @override | |
| 217 Resource getResource(String path) { | |
| 218 path = normalize(path); | |
| 219 Resource resource = _pathToResource[path]; | |
| 220 if (resource == null) { | |
| 221 resource = new _MemoryFile(this, path); | |
| 222 } | |
| 223 return resource; | |
| 224 } | |
| 225 | |
| 226 Folder newFolder(String path) { | |
| 227 path = normalize(path); | |
| 228 if (path.isEmpty) { | |
| 229 throw new ArgumentError('Empty paths are not supported'); | |
| 230 } | |
| 231 if (!path.startsWith('/')) { | |
| 232 throw new ArgumentError('Path must start with \'/\''); | |
|
Brian Wilkerson
2014/05/25 15:29:58
It would be better to use double quotes so that yo
scheglov
2014/05/25 16:16:38
Done.
| |
| 233 } | |
| 234 _MemoryFolder folder = null; | |
| 235 String partialPath = ""; | |
|
Brian Wilkerson
2014/05/25 15:29:58
It's probably more efficient to use a StringBuffer
scheglov
2014/05/25 16:16:38
It is surprising, but no, it is not faster.
Actual
| |
| 236 for (String pathPart in path.split('/')) { | |
| 237 if (pathPart.isEmpty) { | |
| 238 continue; | |
| 239 } | |
| 240 partialPath += '/' + pathPart; | |
| 241 _MemoryResource resource = _pathToResource[partialPath]; | |
| 242 if (resource == null) { | |
| 243 folder = new _MemoryFolder(this, partialPath); | |
| 244 _pathToResource[partialPath] = folder; | |
| 245 _pathToTimestamp[partialPath] = nextStamp++; | |
| 246 } else if (resource is _MemoryFolder) { | |
| 247 folder = resource; | |
| 248 } else { | |
| 249 String message = 'Folder expected at '; | |
| 250 message += "'$partialPath'"; | |
| 251 message += 'but ${resource.runtimeType} found'; | |
|
Brian Wilkerson
2014/05/25 15:29:58
It looks really strange to have a mixture of "+" a
scheglov
2014/05/25 16:16:38
Mostly because it does not fit one 80 characters l
| |
| 252 throw new ArgumentError(message); | |
| 253 } | |
| 254 } | |
| 255 return folder; | |
| 256 } | |
| 257 | |
| 258 File newFile(String path, String content) { | |
| 259 path = normalize(path); | |
| 260 newFolder(dirname(path)); | |
| 261 _MemoryFile file = new _MemoryFile(this, path); | |
| 262 _pathToResource[path] = file; | |
| 263 _pathToContent[path] = content; | |
| 264 _pathToTimestamp[path] = nextStamp++; | |
| 265 return file; | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 | |
| 270 /** | |
| 271 * A `dart:io` based implementation of [File]. | |
| 272 */ | |
| 273 class _PhysicalFile extends _PhysicalResource implements File { | |
| 274 _PhysicalFile(io.File file) : super(file); | |
| 275 | |
| 276 @override | |
| 277 Source createSource(UriKind uriKind) { | |
| 278 io.File file = _entry as io.File; | |
| 279 JavaFile javaFile = new JavaFile(file.absolute.path); | |
| 280 return new FileBasedSource.con2(javaFile, uriKind); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 | |
| 285 /** | |
| 286 * A `dart:io` based implementation of [Folder]. | |
| 287 */ | |
| 288 class _PhysicalFolder extends _PhysicalResource implements Folder { | |
| 289 _PhysicalFolder(io.Directory directory) : super(directory); | |
| 290 | |
| 291 @override | |
| 292 Resource getChild(String relPath) { | |
| 293 String childPath = join(_entry.absolute.path, relPath); | |
| 294 return PhysicalResourceProvider.INSTANCE.getResource(childPath); | |
| 295 } | |
| 296 | |
| 297 @override | |
| 298 List<Resource> getChildren() { | |
| 299 List<Resource> children = []; | |
| 300 io.Directory directory = _entry as io.Directory; | |
| 301 List<io.FileSystemEntity> entries = directory.listSync(recursive: false); | |
| 302 int numEntries = entries.length; | |
| 303 for (int i = 0; i < numEntries; i++) { | |
| 304 io.FileSystemEntity entity = entries[i]; | |
| 305 if (entity is io.Directory) { | |
| 306 children.add(new _PhysicalFolder(entity)); | |
| 307 } else if (entity is io.File) { | |
| 308 children.add(new _PhysicalFile(entity)); | |
| 309 } | |
| 310 } | |
| 311 return children; | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 | |
| 316 /** | |
| 317 * A `dart:io` based implementation of [Resource]. | |
| 318 */ | |
| 319 abstract class _PhysicalResource implements Resource { | |
| 320 final io.FileSystemEntity _entry; | |
| 321 | |
| 322 _PhysicalResource(this._entry); | |
| 323 | |
| 324 @override | |
| 325 bool get exists => _entry.existsSync(); | |
| 326 | |
| 327 @override | |
| 328 String get fullName => _entry.absolute.path; | |
| 329 | |
| 330 @override | |
| 331 get hashCode => _entry.hashCode; | |
| 332 | |
| 333 @override | |
| 334 String get shortName => basename(fullName); | |
| 335 | |
| 336 @override | |
| 337 String toString() => fullName; | |
| 338 } | |
| 339 | |
| 340 | |
| 341 /** | |
| 342 * A `dart:io` based implementation of [ResourceProvider]. | |
| 343 */ | |
| 344 class PhysicalResourceProvider implements ResourceProvider { | |
| 345 static final PhysicalResourceProvider INSTANCE = new PhysicalResourceProvider. _(); | |
| 346 | |
| 347 PhysicalResourceProvider._(); | |
| 348 | |
| 349 @override | |
| 350 Resource getResource(String path) { | |
| 351 if (io.FileSystemEntity.isDirectorySync(path)) { | |
| 352 io.Directory directory = new io.Directory(path); | |
| 353 return new _PhysicalFolder(directory); | |
| 354 } else { | |
| 355 io.File file = new io.File(path); | |
| 356 return new _PhysicalFile(file); | |
| 357 } | |
| 358 } | |
| 359 } | |
| OLD | NEW |