| 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 ==(other) { |
| 90 return identical(this, other); |
| 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 { |
| 123 String content = _provider._pathToContent[_path]; |
| 124 if (content == null) { |
| 125 throw new MemoryResourceException(_path, "File '$_path' does not exist"); |
| 126 } |
| 127 return content; |
| 128 } |
| 129 |
| 130 int get _timestamp => _provider._pathToTimestamp[_path]; |
| 131 } |
| 132 |
| 133 |
| 134 /** |
| 135 * Exception thrown when a memory [Resource] file operation fails. |
| 136 */ |
| 137 class MemoryResourceException { |
| 138 final path; |
| 139 final message; |
| 140 |
| 141 MemoryResourceException(this.path, this.message); |
| 142 |
| 143 @override |
| 144 String toString() { |
| 145 return "MemoryResourceException(path=$path; message=$message)"; |
| 146 } |
| 147 } |
| 148 |
| 149 |
| 150 /** |
| 151 * An in-memory implementation of [Source]. |
| 152 */ |
| 153 class _MemoryFileSource implements Source { |
| 154 final _MemoryFile _file; |
| 155 |
| 156 final UriKind uriKind; |
| 157 |
| 158 _MemoryFileSource(this._file, this.uriKind); |
| 159 |
| 160 @override |
| 161 TimestampedData<String> get contents { |
| 162 return new TimestampedData<String>(modificationStamp, _file._content); |
| 163 } |
| 164 |
| 165 @override |
| 166 String get encoding { |
| 167 return '${new String.fromCharCode(uriKind.encoding)}${_file.fullName}'; |
| 168 } |
| 169 |
| 170 @override |
| 171 bool exists() => _file.exists; |
| 172 |
| 173 @override |
| 174 String get fullName => _file.fullName; |
| 175 |
| 176 @override |
| 177 bool get isInSystemLibrary => false; |
| 178 |
| 179 @override |
| 180 int get modificationStamp => _file._timestamp; |
| 181 |
| 182 @override |
| 183 Source resolveRelative(Uri relativeUri) { |
| 184 String relativePath = fromUri(relativeUri); |
| 185 String folderPath = dirname(_file._path); |
| 186 String path = join(folderPath, relativePath); |
| 187 path = normalize(path); |
| 188 _MemoryFile file = new _MemoryFile(_file._provider, path); |
| 189 return new _MemoryFileSource(file, uriKind); |
| 190 } |
| 191 |
| 192 @override |
| 193 String get shortName => _file.shortName; |
| 194 } |
| 195 |
| 196 |
| 197 /** |
| 198 * An in-memory implementation of [Folder]. |
| 199 */ |
| 200 class _MemoryFolder extends _MemoryResource implements Folder { |
| 201 _MemoryFolder(MemoryResourceProvider provider, String path) : |
| 202 super(provider, path); |
| 203 @override |
| 204 Resource getChild(String relPath) { |
| 205 relPath = normalize(relPath); |
| 206 String childPath = join(_path, relPath); |
| 207 childPath = normalize(childPath); |
| 208 _MemoryResource resource = _provider._pathToResource[childPath]; |
| 209 if (resource == null) { |
| 210 resource = new _MemoryFile(_provider, childPath); |
| 211 } |
| 212 return resource; |
| 213 } |
| 214 |
| 215 @override |
| 216 List<Resource> getChildren() { |
| 217 List<Resource> children = <Resource>[]; |
| 218 _provider._pathToResource.forEach((path, resource) { |
| 219 if (dirname(path) == _path) { |
| 220 children.add(resource); |
| 221 } |
| 222 }); |
| 223 return children; |
| 224 } |
| 225 } |
| 226 |
| 227 |
| 228 /** |
| 229 * An in-memory implementation of [ResourceProvider]. |
| 230 * Use `/` as a path separator. |
| 231 */ |
| 232 class MemoryResourceProvider implements ResourceProvider { |
| 233 final Map<String, _MemoryResource> _pathToResource = <String, _MemoryResource>
{}; |
| 234 final Map<String, String> _pathToContent = <String, String>{}; |
| 235 final Map<String, int> _pathToTimestamp = <String, int>{}; |
| 236 int nextStamp = 0; |
| 237 |
| 238 @override |
| 239 Resource getResource(String path) { |
| 240 path = normalize(path); |
| 241 Resource resource = _pathToResource[path]; |
| 242 if (resource == null) { |
| 243 resource = new _MemoryFile(this, path); |
| 244 } |
| 245 return resource; |
| 246 } |
| 247 |
| 248 Folder newFolder(String path) { |
| 249 path = normalize(path); |
| 250 if (path.isEmpty) { |
| 251 throw new ArgumentError('Empty paths are not supported'); |
| 252 } |
| 253 if (!path.startsWith('/')) { |
| 254 throw new ArgumentError("Path must start with '/'"); |
| 255 } |
| 256 _MemoryFolder folder = null; |
| 257 String partialPath = ""; |
| 258 for (String pathPart in path.split('/')) { |
| 259 if (pathPart.isEmpty) { |
| 260 continue; |
| 261 } |
| 262 partialPath += '/' + pathPart; |
| 263 _MemoryResource resource = _pathToResource[partialPath]; |
| 264 if (resource == null) { |
| 265 folder = new _MemoryFolder(this, partialPath); |
| 266 _pathToResource[partialPath] = folder; |
| 267 _pathToTimestamp[partialPath] = nextStamp++; |
| 268 } else if (resource is _MemoryFolder) { |
| 269 folder = resource; |
| 270 } else { |
| 271 String message = 'Folder expected at ' |
| 272 "'$partialPath'" |
| 273 'but ${resource.runtimeType} found'; |
| 274 throw new ArgumentError(message); |
| 275 } |
| 276 } |
| 277 return folder; |
| 278 } |
| 279 |
| 280 File newFile(String path, String content) { |
| 281 path = normalize(path); |
| 282 newFolder(dirname(path)); |
| 283 _MemoryFile file = new _MemoryFile(this, path); |
| 284 _pathToResource[path] = file; |
| 285 _pathToContent[path] = content; |
| 286 _pathToTimestamp[path] = nextStamp++; |
| 287 return file; |
| 288 } |
| 289 } |
| 290 |
| 291 |
| 292 /** |
| 293 * A `dart:io` based implementation of [File]. |
| 294 */ |
| 295 class _PhysicalFile extends _PhysicalResource implements File { |
| 296 _PhysicalFile(io.File file) : super(file); |
| 297 |
| 298 @override |
| 299 Source createSource(UriKind uriKind) { |
| 300 io.File file = _entry as io.File; |
| 301 JavaFile javaFile = new JavaFile(file.absolute.path); |
| 302 return new FileBasedSource.con2(javaFile, uriKind); |
| 303 } |
| 304 } |
| 305 |
| 306 |
| 307 /** |
| 308 * A `dart:io` based implementation of [Folder]. |
| 309 */ |
| 310 class _PhysicalFolder extends _PhysicalResource implements Folder { |
| 311 _PhysicalFolder(io.Directory directory) : super(directory); |
| 312 |
| 313 @override |
| 314 Resource getChild(String relPath) { |
| 315 String childPath = join(_entry.absolute.path, relPath); |
| 316 return PhysicalResourceProvider.INSTANCE.getResource(childPath); |
| 317 } |
| 318 |
| 319 @override |
| 320 List<Resource> getChildren() { |
| 321 List<Resource> children = <Resource>[]; |
| 322 io.Directory directory = _entry as io.Directory; |
| 323 List<io.FileSystemEntity> entries = directory.listSync(recursive: false); |
| 324 int numEntries = entries.length; |
| 325 for (int i = 0; i < numEntries; i++) { |
| 326 io.FileSystemEntity entity = entries[i]; |
| 327 if (entity is io.Directory) { |
| 328 children.add(new _PhysicalFolder(entity)); |
| 329 } else if (entity is io.File) { |
| 330 children.add(new _PhysicalFile(entity)); |
| 331 } |
| 332 } |
| 333 return children; |
| 334 } |
| 335 } |
| 336 |
| 337 |
| 338 /** |
| 339 * A `dart:io` based implementation of [Resource]. |
| 340 */ |
| 341 abstract class _PhysicalResource implements Resource { |
| 342 final io.FileSystemEntity _entry; |
| 343 |
| 344 _PhysicalResource(this._entry); |
| 345 |
| 346 @override |
| 347 bool get exists => _entry.existsSync(); |
| 348 |
| 349 @override |
| 350 String get fullName => _entry.absolute.path; |
| 351 |
| 352 @override |
| 353 get hashCode => _entry.hashCode; |
| 354 |
| 355 @override |
| 356 String get shortName => basename(fullName); |
| 357 |
| 358 @override |
| 359 String toString() => fullName; |
| 360 } |
| 361 |
| 362 |
| 363 /** |
| 364 * A `dart:io` based implementation of [ResourceProvider]. |
| 365 */ |
| 366 class PhysicalResourceProvider implements ResourceProvider { |
| 367 static final PhysicalResourceProvider INSTANCE = new PhysicalResourceProvider.
_(); |
| 368 |
| 369 PhysicalResourceProvider._(); |
| 370 |
| 371 @override |
| 372 Resource getResource(String path) { |
| 373 if (io.FileSystemEntity.isDirectorySync(path)) { |
| 374 io.Directory directory = new io.Directory(path); |
| 375 return new _PhysicalFolder(directory); |
| 376 } else { |
| 377 io.File file = new io.File(path); |
| 378 return new _PhysicalFile(file); |
| 379 } |
| 380 } |
| 381 } |
| OLD | NEW |