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