| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.source.embedder; | 5 library analyzer.source.embedder; |
| 6 | 6 |
| 7 import 'dart:collection' show HashMap; | 7 import 'dart:collection' show HashMap; |
| 8 import 'dart:core' hide Resource; | 8 import 'dart:core' hide Resource; |
| 9 | 9 |
| 10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
| 11 import 'package:analyzer/source/package_map_provider.dart' | 11 import 'package:analyzer/source/package_map_provider.dart' |
| 12 show PackageMapProvider; | 12 show PackageMapProvider; |
| 13 import 'package:analyzer/src/context/context.dart'; | 13 import 'package:analyzer/src/context/context.dart'; |
| 14 import 'package:analyzer/src/generated/engine.dart'; | 14 import 'package:analyzer/src/generated/engine.dart'; |
| 15 import 'package:analyzer/src/generated/java_core.dart'; | 15 import 'package:analyzer/src/generated/java_core.dart'; |
| 16 import 'package:analyzer/src/generated/java_engine.dart'; | 16 import 'package:analyzer/src/generated/java_engine.dart'; |
| 17 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; | 17 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; |
| 18 import 'package:analyzer/src/generated/sdk.dart'; | 18 import 'package:analyzer/src/generated/sdk.dart'; |
| 19 import 'package:analyzer/src/generated/source.dart'; | 19 import 'package:analyzer/src/generated/source.dart'; |
| 20 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; | 20 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; |
| 21 import 'package:yaml/yaml.dart'; | 21 import 'package:yaml/yaml.dart'; |
| 22 | 22 |
| 23 const String _DART_COLON_PREFIX = 'dart:'; | 23 const String _DART_COLON_PREFIX = 'dart:'; |
| 24 const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs'; | 24 const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs'; |
| 25 | 25 |
| 26 /// Check if this map defines embedded libraries. | 26 /// Check if this map defines embedded libraries. |
| 27 bool definesEmbeddedLibs(Map map) => map[_EMBEDDED_LIB_MAP_KEY] != null; | 27 bool definesEmbeddedLibs(Map map) => map[_EMBEDDED_LIB_MAP_KEY] != null; |
| 28 | 28 |
| 29 /// An SDK backed by URI mappings derived from an `_embedder.yaml` file. |
| 29 class EmbedderSdk implements DartSdk { | 30 class EmbedderSdk implements DartSdk { |
| 30 // TODO(danrubel) Refactor this with DirectoryBasedDartSdk | 31 /// The resolver associated with this SDK. |
| 31 | |
| 32 /// The resolver associated with this embedder sdk. | |
| 33 EmbedderUriResolver _resolver; | 32 EmbedderUriResolver _resolver; |
| 34 | 33 |
| 35 /// The [AnalysisContext] which is used for all of the sources in this sdk. | 34 /// The [AnalysisContext] used for this SDK's sources. |
| 36 InternalAnalysisContext _analysisContext; | 35 InternalAnalysisContext _analysisContext; |
| 37 | 36 |
| 38 /// The library map that is populated by visiting the AST structure parsed fro
m | |
| 39 /// the contents of the libraries file. | |
| 40 final LibraryMap _librariesMap = new LibraryMap(); | 37 final LibraryMap _librariesMap = new LibraryMap(); |
| 41 | 38 |
| 39 final Map<String, String> _urlMappings = new HashMap<String, String>(); |
| 40 |
| 41 /// Analysis options for this SDK. |
| 42 AnalysisOptions analysisOptions; |
| 43 |
| 44 EmbedderSdk([Map<Folder, YamlMap> embedderYamls]) { |
| 45 embedderYamls?.forEach(_processEmbedderYaml); |
| 46 _resolver = new EmbedderUriResolver(this); |
| 47 } |
| 48 |
| 42 @override | 49 @override |
| 43 AnalysisContext get context { | 50 AnalysisContext get context { |
| 44 if (_analysisContext == null) { | 51 if (_analysisContext == null) { |
| 45 _analysisContext = new SdkAnalysisContext(null); | 52 _analysisContext = new SdkAnalysisContext(analysisOptions); |
| 46 SourceFactory factory = new SourceFactory([_resolver]); | 53 SourceFactory factory = new SourceFactory([_resolver]); |
| 47 _analysisContext.sourceFactory = factory; | 54 _analysisContext.sourceFactory = factory; |
| 48 List<String> uris = this.uris; | 55 |
| 49 ChangeSet changeSet = new ChangeSet(); | 56 ChangeSet changeSet = new ChangeSet(); |
| 50 for (String uri in uris) { | 57 for (String uri in uris) { |
| 51 changeSet.addedSource(factory.forUri(uri)); | 58 changeSet.addedSource(factory.forUri(uri)); |
| 52 } | 59 } |
| 53 _analysisContext.applyChanges(changeSet); | 60 _analysisContext.applyChanges(changeSet); |
| 54 } | 61 } |
| 55 return _analysisContext; | 62 return _analysisContext; |
| 56 } | 63 } |
| 57 | 64 |
| 58 @override | 65 @override |
| 59 List<SdkLibrary> get sdkLibraries => _librariesMap.sdkLibraries; | 66 List<SdkLibrary> get sdkLibraries => _librariesMap.sdkLibraries; |
| 60 | 67 |
| 61 // TODO(danrubel) Determine SDK version | 68 // TODO(danrubel) Determine SDK version |
| 62 @override | 69 @override |
| 63 String get sdkVersion => '0'; | 70 String get sdkVersion => '0'; |
| 64 | 71 |
| 65 @override | 72 @override |
| 66 List<String> get uris => _librariesMap.uris; | 73 List<String> get uris => _librariesMap.uris; |
| 67 | 74 |
| 75 /// The url mappings for this SDK. |
| 76 Map<String, String> get urlMappings => _urlMappings; |
| 77 |
| 68 @override | 78 @override |
| 69 Source fromFileUri(Uri uri) { | 79 Source fromFileUri(Uri uri) { |
| 70 JavaFile file = new JavaFile.fromUri(uri); | 80 JavaFile file = new JavaFile.fromUri(uri); |
| 71 String filePath = file.getAbsolutePath(); | 81 String filePath = file.getAbsolutePath(); |
| 72 | 82 |
| 73 String path; | 83 String path; |
| 74 for (SdkLibrary library in _librariesMap.sdkLibraries) { | 84 for (SdkLibrary library in _librariesMap.sdkLibraries) { |
| 75 String libraryPath = library.path.replaceAll('/', JavaFile.separator); | 85 String libraryPath = library.path.replaceAll('/', JavaFile.separator); |
| 76 if (filePath == libraryPath) { | 86 if (filePath == libraryPath) { |
| 77 path = '$_DART_COLON_PREFIX${library.shortName}'; | 87 path = library.shortName; |
| 78 break; | 88 break; |
| 79 } | 89 } |
| 80 } | 90 } |
| 81 if (path == null) { | 91 if (path == null) { |
| 82 for (SdkLibrary library in _librariesMap.sdkLibraries) { | 92 for (SdkLibrary library in _librariesMap.sdkLibraries) { |
| 83 String libraryPath = library.path.replaceAll('/', JavaFile.separator); | 93 String libraryPath = library.path.replaceAll('/', JavaFile.separator); |
| 84 int index = libraryPath.lastIndexOf(JavaFile.separator); | 94 int index = libraryPath.lastIndexOf(JavaFile.separator); |
| 85 if (index == -1) { | 95 if (index == -1) { |
| 86 continue; | 96 continue; |
| 87 } | 97 } |
| 88 String prefix = libraryPath.substring(0, index + 1); | 98 String prefix = libraryPath.substring(0, index + 1); |
| 89 if (!filePath.startsWith(prefix)) { | 99 if (!filePath.startsWith(prefix)) { |
| 90 continue; | 100 continue; |
| 91 } | 101 } |
| 92 var relPath = filePath | 102 var relPath = filePath |
| 93 .substring(prefix.length) | 103 .substring(prefix.length) |
| 94 .replaceAll(JavaFile.separator, '/'); | 104 .replaceAll(JavaFile.separator, '/'); |
| 95 path = '$_DART_COLON_PREFIX${library.shortName}/$relPath'; | 105 path = '${library.shortName}/$relPath'; |
| 96 break; | 106 break; |
| 97 } | 107 } |
| 98 } | 108 } |
| 99 | 109 |
| 100 if (path != null) { | 110 if (path != null) { |
| 101 try { | 111 try { |
| 102 return new FileBasedSource(file, parseUriWithException(path)); | 112 return new FileBasedSource(file, parseUriWithException(path)); |
| 103 } on URISyntaxException catch (exception, stackTrace) { | 113 } on URISyntaxException catch (exception, stackTrace) { |
| 104 AnalysisEngine.instance.logger.logInformation( | 114 AnalysisEngine.instance.logger.logInformation( |
| 105 "Failed to create URI: $path", | 115 "Failed to create URI: $path", |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 srcPath = '$prefix$relativePath'; | 155 srcPath = '$prefix$relativePath'; |
| 146 } | 156 } |
| 147 String filePath = srcPath.replaceAll('/', JavaFile.separator); | 157 String filePath = srcPath.replaceAll('/', JavaFile.separator); |
| 148 try { | 158 try { |
| 149 JavaFile file = new JavaFile(filePath); | 159 JavaFile file = new JavaFile(filePath); |
| 150 return new FileBasedSource(file, parseUriWithException(dartUri)); | 160 return new FileBasedSource(file, parseUriWithException(dartUri)); |
| 151 } on URISyntaxException { | 161 } on URISyntaxException { |
| 152 return null; | 162 return null; |
| 153 } | 163 } |
| 154 } | 164 } |
| 165 |
| 166 /// Install the mapping from [name] to [libDir]/[file]. |
| 167 void _processEmbeddedLibs(String name, String file, Folder libDir) { |
| 168 if (!name.startsWith(_DART_COLON_PREFIX)) { |
| 169 // SDK libraries must begin with 'dart:'. |
| 170 return; |
| 171 } |
| 172 String libPath = libDir.canonicalizePath(file); |
| 173 _urlMappings[name] = libPath; |
| 174 SdkLibraryImpl library = new SdkLibraryImpl(name); |
| 175 library.path = libPath; |
| 176 _librariesMap.setLibrary(name, library); |
| 177 } |
| 178 |
| 179 /// Given the 'embedderYamls' from [EmbedderYamlLocator] check each one for th
e |
| 180 /// top level key 'embedded_libs'. Under the 'embedded_libs' key are key value |
| 181 /// pairs. Each key is a 'dart:' library uri and each value is a path |
| 182 /// (relative to the directory containing `_embedder.yaml`) to a dart script |
| 183 /// for the given library. For example: |
| 184 /// |
| 185 /// embedded_libs: |
| 186 /// 'dart:io': '../../sdk/io/io.dart' |
| 187 /// |
| 188 /// If a key doesn't begin with `dart:` it is ignored. |
| 189 void _processEmbedderYaml(Folder libDir, YamlMap map) { |
| 190 YamlNode embedded_libs = map[_EMBEDDED_LIB_MAP_KEY]; |
| 191 if (embedded_libs is YamlMap) { |
| 192 embedded_libs.forEach((k, v) => _processEmbeddedLibs(k, v, libDir)); |
| 193 } |
| 194 } |
| 155 } | 195 } |
| 156 | 196 |
| 157 /// Given the 'embedderYamls' from [EmbedderYamlLocator] check each one for the | 197 /// Given the 'embedderYamls' from [EmbedderYamlLocator] check each one for the |
| 158 /// top level key 'embedded_libs'. Under the 'embedded_libs' key are key value | 198 /// top level key 'embedded_libs'. Under the 'embedded_libs' key are key value |
| 159 /// pairs. Each key is a 'dart:' library uri and each value is a path | 199 /// pairs. Each key is a 'dart:' library uri and each value is a path |
| 160 /// (relative to the directory containing `_embedder.yaml`) to a dart script | 200 /// (relative to the directory containing `_embedder.yaml`) to a dart script |
| 161 /// for the given library. For example: | 201 /// for the given library. For example: |
| 162 /// | 202 /// |
| 163 /// embedded_libs: | 203 /// embedded_libs: |
| 164 /// 'dart:io': '../../sdk/io/io.dart' | 204 /// 'dart:io': '../../sdk/io/io.dart' |
| 165 /// | 205 /// |
| 166 /// If a key doesn't begin with `dart:` it is ignored. | 206 /// If a key doesn't begin with `dart:` it is ignored. |
| 167 /// | 207 /// |
| 168 class EmbedderUriResolver extends DartUriResolver { | 208 class EmbedderUriResolver implements DartUriResolver { |
| 169 final Map<String, String> _urlMappings = <String, String>{}; | 209 EmbedderSdk _embedderSdk; |
| 210 DartUriResolver _dartUriResolver; |
| 170 | 211 |
| 171 /// Construct a [EmbedderUriResolver] from a package map | 212 /// Construct a [EmbedderUriResolver] from a package map |
| 172 /// (see [PackageMapProvider]). | 213 /// (see [PackageMapProvider]). |
| 173 EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls) | 214 EmbedderUriResolver(this._embedderSdk) { |
| 174 : super(new EmbedderSdk()) { | 215 _dartUriResolver = new DartUriResolver(_embedderSdk); |
| 175 (dartSdk as EmbedderSdk)._resolver = this; | |
| 176 if (embedderYamls == null) { | |
| 177 return; | |
| 178 } | |
| 179 embedderYamls.forEach(_processEmbedderYaml); | |
| 180 } | 216 } |
| 181 | 217 |
| 218 @override |
| 219 DartSdk get dartSdk => _embedderSdk; |
| 220 |
| 182 /// Number of embedded libraries. | 221 /// Number of embedded libraries. |
| 183 int get length => _urlMappings.length; | 222 int get length => _embedderSdk?.urlMappings?.length ?? 0; |
| 223 |
| 224 @override |
| 225 Source resolveAbsolute(Uri uri, [Uri actualUri]) => |
| 226 _dartUriResolver.resolveAbsolute(uri, actualUri); |
| 184 | 227 |
| 185 @override | 228 @override |
| 186 Uri restoreAbsolute(Source source) { | 229 Uri restoreAbsolute(Source source) { |
| 187 String path = source.fullName; | 230 String path = source.fullName; |
| 188 if (path.length > 3 && path[1] == ':' && path[2] == '\\') { | 231 if (path.length > 3 && path[1] == ':' && path[2] == '\\') { |
| 189 path = '/${path[0]}:${path.substring(2).replaceAll('\\', '/')}'; | 232 path = '/${path[0]}:${path.substring(2).replaceAll('\\', '/')}'; |
| 190 } | 233 } |
| 191 Source sdkSource = dartSdk.fromFileUri(Uri.parse('file://$path')); | 234 Source sdkSource = dartSdk.fromFileUri(Uri.parse('file://$path')); |
| 192 return sdkSource?.uri; | 235 return sdkSource?.uri; |
| 193 } | 236 } |
| 194 | |
| 195 /// Install the mapping from [name] to [libDir]/[file]. | |
| 196 void _processEmbeddedLibs(String name, String file, Folder libDir) { | |
| 197 if (!name.startsWith(_DART_COLON_PREFIX)) { | |
| 198 // SDK libraries must begin with 'dart:'. | |
| 199 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 200 // _embedder.yaml file in libDir. | |
| 201 return; | |
| 202 } | |
| 203 String libPath = libDir.canonicalizePath(file); | |
| 204 _urlMappings[name] = libPath; | |
| 205 String shortName = name.substring(_DART_COLON_PREFIX.length); | |
| 206 SdkLibraryImpl library = new SdkLibraryImpl(shortName); | |
| 207 library.path = libPath; | |
| 208 (dartSdk as EmbedderSdk)._librariesMap.setLibrary(name, library); | |
| 209 } | |
| 210 | |
| 211 void _processEmbedderYaml(Folder libDir, YamlMap map) { | |
| 212 YamlNode embedded_libs = map[_EMBEDDED_LIB_MAP_KEY]; | |
| 213 if (embedded_libs == null) { | |
| 214 return; | |
| 215 } | |
| 216 if (embedded_libs is YamlMap) { | |
| 217 embedded_libs.forEach((k, v) => _processEmbeddedLibs(k, v, libDir)); | |
| 218 } | |
| 219 } | |
| 220 } | 237 } |
| 221 | 238 |
| 222 /// Given a packageMap, check in each package's lib directory for the | 239 /// Given a packageMap, check in each package's lib directory for the |
| 223 /// existence of an `_embedder.yaml` file. If the file contains a top level | 240 /// existence of an `_embedder.yaml` file. If the file contains a top level |
| 224 /// YamlMap, it will be added to the [embedderYamls] map. | 241 /// YamlMap, it will be added to the [embedderYamls] map. |
| 225 class EmbedderYamlLocator { | 242 class EmbedderYamlLocator { |
| 226 static const String EMBEDDER_FILE_NAME = '_embedder.yaml'; | 243 static const String EMBEDDER_FILE_NAME = '_embedder.yaml'; |
| 227 | 244 |
| 228 // Map from package's library directory to the parsed | 245 /// Map from package's library directory to the parsed YamlMap. |
| 229 // YamlMap. | |
| 230 final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>(); | 246 final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>(); |
| 231 | 247 |
| 232 EmbedderYamlLocator(Map<String, List<Folder>> packageMap) { | 248 EmbedderYamlLocator(Map<String, List<Folder>> packageMap) { |
| 233 if (packageMap != null) { | 249 if (packageMap != null) { |
| 234 refresh(packageMap); | 250 refresh(packageMap); |
| 235 } | 251 } |
| 236 } | 252 } |
| 237 | 253 |
| 238 /// Programatically add an _embedder.yaml mapping. | 254 /// Programatically add an _embedder.yaml mapping. |
| 239 void addEmbedderYaml(Folder libDir, String embedderYaml) { | 255 void addEmbedderYaml(Folder libDir, String embedderYaml) { |
| 240 _processEmbedderYaml(libDir, embedderYaml); | 256 _processEmbedderYaml(libDir, embedderYaml); |
| 241 } | 257 } |
| 242 | 258 |
| 243 void refresh(Map<String, List<Folder>> packageMap) { | 259 void refresh(Map<String, List<Folder>> packageMap) { |
| 244 // Clear existing. | 260 // Clear existing. |
| 245 embedderYamls.clear(); | 261 embedderYamls.clear(); |
| 246 if (packageMap == null) { | 262 if (packageMap == null) { |
| 247 return; | 263 return; |
| 248 } | 264 } |
| 249 packageMap.forEach(_processPackage); | 265 packageMap.forEach(_processPackage); |
| 250 } | 266 } |
| 251 | 267 |
| 252 /// Given the yaml for an embedder ([embedderYaml]) and a folder | 268 /// Given the yaml for an embedder ([embedderYaml]) and a folder |
| 253 /// ([libDir]), setup the uri mapping. | 269 /// ([libDir]), setup the uri mapping. |
| 254 void _processEmbedderYaml(Folder libDir, String embedderYaml) { | 270 void _processEmbedderYaml(Folder libDir, String embedderYaml) { |
| 255 YamlNode yaml; | 271 YamlNode yaml; |
| 256 try { | 272 try { |
| 257 yaml = loadYaml(embedderYaml); | 273 yaml = loadYaml(embedderYaml); |
| 258 } catch (_) { | 274 } catch (_) { |
| 259 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 260 // _embedder.yaml file in libDir. | |
| 261 return; | |
| 262 } | |
| 263 if (yaml == null) { | |
| 264 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 265 // _embedder.yaml file in libDir. | |
| 266 return; | 275 return; |
| 267 } | 276 } |
| 268 if (yaml is! YamlMap) { | 277 if (yaml is! YamlMap) { |
| 269 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 270 // _embedder.yaml file in libDir. | |
| 271 return; | 278 return; |
| 272 } | 279 } |
| 273 embedderYamls[libDir] = yaml; | 280 embedderYamls[libDir] = yaml; |
| 274 } | 281 } |
| 275 | 282 |
| 276 /// Given a package [name] and a list of folders ([libDirs]), | 283 /// Given a package [name] and a list of folders ([libDirs]), |
| 277 /// add any found `_embedder.yaml` files. | 284 /// add any found `_embedder.yaml` files. |
| 278 void _processPackage(String name, List<Folder> libDirs) { | 285 void _processPackage(String name, List<Folder> libDirs) { |
| 279 for (Folder libDir in libDirs) { | 286 for (Folder libDir in libDirs) { |
| 280 String embedderYaml = _readEmbedderYaml(libDir); | 287 String embedderYaml = _readEmbedderYaml(libDir); |
| 281 if (embedderYaml != null) { | 288 if (embedderYaml != null) { |
| 282 _processEmbedderYaml(libDir, embedderYaml); | 289 _processEmbedderYaml(libDir, embedderYaml); |
| 283 } | 290 } |
| 284 } | 291 } |
| 285 } | 292 } |
| 286 | 293 |
| 287 /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string. | 294 /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string. |
| 288 /// Returns null if the file doesn't exist. | 295 /// Returns null if the file doesn't exist. |
| 289 String _readEmbedderYaml(Folder libDir) { | 296 String _readEmbedderYaml(Folder libDir) { |
| 290 File file = libDir.getChild(EMBEDDER_FILE_NAME); | 297 File file = libDir.getChild(EMBEDDER_FILE_NAME); |
| 291 try { | 298 try { |
| 292 return file.readAsStringSync(); | 299 return file.readAsStringSync(); |
| 293 } on FileSystemException { | 300 } on FileSystemException { |
| 294 // File can't be read. | 301 // File can't be read. |
| 295 return null; | 302 return null; |
| 296 } | 303 } |
| 297 } | 304 } |
| 298 } | 305 } |
| OLD | NEW |