Chromium Code Reviews| 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 source.sdk_ext; | 5 library source.embedder; |
| 6 | 6 |
| 7 import 'dart:convert'; | |
| 8 import 'dart:core' hide Resource; | 7 import 'dart:core' hide Resource; |
| 8 import 'dart:collection' show HashMap; | |
| 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/generated/java_io.dart' show JavaFile; | 11 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; |
| 12 import 'package:analyzer/src/generated/source.dart'; | 12 import 'package:analyzer/src/generated/source.dart'; |
| 13 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; | 13 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; |
| 14 import 'package:path/path.dart' as pathos; | 14 import 'package:path/path.dart' as pathos; |
| 15 import 'package:yaml/yaml.dart'; | |
| 15 | 16 |
| 16 /// Given a packageMap (see [PackageMapProvider]), check in each package's lib | 17 /// Given a packageMap, check in each package's lib directory for the |
| 17 /// directory for the existence of a `_sdkext` file. This file must contain a | 18 /// existence of an `_embedder.yaml` file. If the file contains a top level |
| 18 /// JSON encoded map. Each key in the map is a `dart:` library name. Each value | 19 /// YamlMap, it will be added to the [embedderYamls] map. |
| 19 /// is a path (relative to the directory containing `_sdkext`) to a dart script | 20 class EmbedderYamlLocator { |
| 20 /// for the given library. For example: | 21 static const String EMBEDDER_FILE_NAME = '_embedder.yaml'; |
| 21 /// { | |
| 22 /// "dart:sky": "../sdk_ext/dart_sky.dart" | |
| 23 /// } | |
| 24 /// | |
| 25 /// If a key doesn't begin with `dart:` it is ignored. | |
| 26 class SdkExtUriResolver extends UriResolver { | |
| 27 static const String SDK_EXT_NAME = '_sdkext'; | |
| 28 static const String DART_COLON_PREFIX = 'dart:'; | |
| 29 | 22 |
| 30 final Map<String, String> _urlMappings = <String, String>{}; | 23 // Map from package's library directory to the parsed |
| 24 // YamlMap. | |
| 25 final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>(); | |
| 31 | 26 |
| 32 /// Construct a [SdkExtUriResolver] from a package map | 27 EmbedderYamlLocator(Map<String, List<Folder>> packageMap) { |
| 33 /// (see [PackageMapProvider]). | 28 if (packageMap != null) { |
| 34 SdkExtUriResolver(Map<String, List<Folder>> packageMap) { | 29 refresh(packageMap); |
| 30 } | |
| 31 } | |
| 32 | |
| 33 void refresh(Map<String, List<Folder>> packageMap) { | |
| 34 // Clear existing. | |
| 35 embedderYamls.clear(); | |
| 35 if (packageMap == null) { | 36 if (packageMap == null) { |
| 36 return; | 37 return; |
| 37 } | 38 } |
| 38 packageMap.forEach(_processPackage); | 39 packageMap.forEach(_processPackage); |
| 39 } | 40 } |
| 40 | 41 |
| 41 /// Number of sdk extensions. | 42 /// Programatically add an _embedder.yaml mapping. |
| 43 void addEmbedderYaml(Folder libDir, String embedderYaml) { | |
| 44 _processEmbedderYaml(libDir, embedderYaml); | |
| 45 } | |
| 46 | |
| 47 /// Given a package [name] and a list of folders ([libDirs]), | |
| 48 /// add any found `_embedder.yaml` files. | |
| 49 void _processPackage(String name, List<Folder> libDirs) { | |
| 50 for (Folder libDir in libDirs) { | |
| 51 String embedderYaml = _readEmbedderYaml(libDir); | |
| 52 if (embedderYaml != null) { | |
| 53 _processEmbedderYaml(libDir, embedderYaml); | |
| 54 } | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 /// Given the yaml for an embedder ([embedderYaml]) and a folder | |
| 59 /// ([libDir]), setup the uri mapping. | |
| 60 void _processEmbedderYaml(Folder libDir, String embedderYaml) { | |
| 61 YamlNode yaml; | |
| 62 try { | |
| 63 yaml = loadYaml(embedderYaml); | |
| 64 } catch (e) { | |
|
pquitslund
2015/11/14 00:32:53
Nit: (e) => (_)
Cutch
2015/11/14 00:36:44
Done.
| |
| 65 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 66 // _embedder.yaml file in libDir. | |
| 67 return; | |
| 68 } | |
| 69 if (yaml == null) { | |
| 70 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 71 // _embedder.yaml file in libDir. | |
| 72 return; | |
| 73 } | |
| 74 if (yaml is! YamlMap) { | |
| 75 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 76 // _embedder.yaml file in libDir. | |
| 77 return; | |
| 78 } | |
| 79 embedderYamls[libDir] = yaml; | |
| 80 } | |
| 81 | |
| 82 | |
| 83 /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string. | |
| 84 /// Returns null if the file doesn't exist. | |
| 85 String _readEmbedderYaml(Folder libDir) { | |
| 86 File file = libDir.getChild(EMBEDDER_FILE_NAME); | |
| 87 try { | |
| 88 return file.readAsStringSync(); | |
| 89 } on FileSystemException { | |
| 90 // File can't be read. | |
| 91 return null; | |
| 92 } | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 /// Given the [embedderYamls] from [EmbedderYamlLocator] check each one for the | |
| 97 /// top level key 'embedder_libs'. Under the 'embedder_libs' key are key value | |
| 98 /// pairs. Each key is a 'dart:' library uri and each value is a path | |
| 99 /// (relative to the directory containing `_embedder.yaml`) to a dart script | |
| 100 /// for the given library. For example: | |
| 101 /// | |
| 102 /// embedder_libs: | |
| 103 /// 'dart:io': '../../sdk/io/io.dart' | |
| 104 /// | |
| 105 /// If a key doesn't begin with `dart:` it is ignored. | |
| 106 /// | |
| 107 class EmbedderUriResolver extends UriResolver { | |
| 108 static const String DART_COLON_PREFIX = 'dart:'; | |
| 109 | |
| 110 final Map<String, String> _urlMappings = <String, String>{}; | |
| 111 | |
| 112 /// Construct a [EmbedderUriResolver] from a package map | |
| 113 /// (see [PackageMapProvider]). | |
| 114 EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls) { | |
| 115 if (embedderYamls == null) { | |
| 116 return; | |
| 117 } | |
| 118 embedderYamls.forEach(_processEmbedderYaml); | |
| 119 } | |
| 120 | |
| 121 void _processEmbedderYaml(Folder libDir, YamlMap map) { | |
| 122 YamlNode embedder_libs = map['embedder_libs']; | |
| 123 if (embedder_libs == null) { | |
| 124 return; | |
| 125 } | |
| 126 if (embedder_libs is! YamlMap) { | |
| 127 return; | |
| 128 } | |
| 129 (embedder_libs as YamlMap).forEach((k, v) => | |
| 130 _processEmbedderLibs(k, v, libDir)); | |
| 131 } | |
| 132 | |
| 133 /// Install the mapping from [name] to [libDir]/[file]. | |
| 134 void _processEmbedderLibs(String name, String file, Folder libDir) { | |
| 135 if (!name.startsWith(DART_COLON_PREFIX)) { | |
| 136 // SDK libraries must begin with 'dart:'. | |
| 137 // TODO(pquitslund): Notify developer that something is wrong with the | |
| 138 // _embedder.yaml file in libDir. | |
| 139 return; | |
| 140 } | |
| 141 String key = name; | |
| 142 String value = libDir.canonicalizePath(file); | |
| 143 _urlMappings[key] = value; | |
| 144 } | |
| 145 | |
| 146 /// Number of embedder libraries. | |
| 42 int get length => _urlMappings.length; | 147 int get length => _urlMappings.length; |
| 43 | 148 |
| 44 /// Return the path mapping for [libName] or null if there is none. | 149 /// Return the path mapping for [libName] or null if there is none. |
| 45 String operator [](String libName) => _urlMappings[libName]; | 150 String operator [](String libName) => _urlMappings[libName]; |
| 46 | 151 |
| 47 /// Programmatically add a new SDK extension given a JSON description | |
| 48 /// ([sdkExtJSON]) and a lib directory ([libDir]). | |
| 49 void addSdkExt(String sdkExtJSON, Folder libDir) { | |
| 50 _processSdkExt(sdkExtJSON, libDir); | |
| 51 } | |
| 52 | |
| 53 @override | 152 @override |
| 54 Source resolveAbsolute(Uri importUri, [Uri actualUri]) { | 153 Source resolveAbsolute(Uri importUri, [Uri actualUri]) { |
| 55 String libraryName = _libraryName(importUri); | 154 String libraryName = _libraryName(importUri); |
| 56 String partPath = _partPath(importUri); | 155 String partPath = _partPath(importUri); |
| 57 // Lookup library name in mappings. | 156 // Lookup library name in mappings. |
| 58 String mapping = _urlMappings[libraryName]; | 157 String mapping = _urlMappings[libraryName]; |
| 59 if (mapping == null) { | 158 if (mapping == null) { |
| 60 // Not found. | 159 // Not found. |
| 61 return null; | 160 return null; |
| 62 } | 161 } |
| 63 // This mapping points to the main entry file of the sdk extension. | 162 // This mapping points to the main entry file of the dart: library. |
| 64 Uri libraryEntry = new Uri.file(mapping); | 163 Uri libraryEntry = new Uri.file(mapping); |
| 65 if (!libraryEntry.isAbsolute) { | 164 if (!libraryEntry.isAbsolute) { |
| 66 // We expect an absolute path. | 165 // We expect an absolute path. |
| 67 return null; | 166 return null; |
| 68 } | 167 } |
| 69 | 168 |
| 70 if (partPath != null) { | 169 if (partPath != null) { |
| 71 return _resolvePart(libraryEntry, partPath, importUri); | 170 return _resolvePart(libraryEntry, partPath, importUri); |
| 72 } else { | 171 } else { |
| 73 return _resolveEntry(libraryEntry, importUri); | 172 return _resolveEntry(libraryEntry, importUri); |
| 74 } | 173 } |
| 75 } | 174 } |
| 76 | 175 |
| 77 @override | 176 @override |
| 78 Uri restoreAbsolute(Source source) { | 177 Uri restoreAbsolute(Source source) { |
| 79 String extensionName = _findExtensionNameFor(source.fullName); | 178 String extensionName = _findExtensionNameFor(source.fullName); |
| 80 if (extensionName != null) { | 179 if (extensionName != null) { |
| 81 return Uri.parse(extensionName); | 180 return Uri.parse(extensionName); |
| 82 } | 181 } |
| 83 // TODO(johnmccutchan): Handle restoring parts. | 182 // TODO(johnmccutchan): Handle restoring parts. |
| 84 return null; | 183 return null; |
| 85 } | 184 } |
| 86 | 185 |
| 87 /// Return the extension name for [fullName] or `null`. | 186 /// Return the extension name for [fullName] or `null`. |
| 88 String _findExtensionNameFor(String fullName) { | 187 String _findExtensionNameFor(String fullName) { |
| 89 var result; | 188 String result; |
| 90 _urlMappings.forEach((extensionName, pathMapping) { | 189 _urlMappings.forEach((extensionName, pathMapping) { |
| 91 if (pathMapping == fullName) { | 190 if (pathMapping == fullName) { |
| 92 result = extensionName; | 191 result = extensionName; |
| 93 } | 192 } |
| 94 }); | 193 }); |
| 95 return result; | 194 return result; |
| 96 } | 195 } |
| 97 | 196 |
| 98 /// Return the library name of [importUri]. | 197 /// Return the library name of [importUri]. |
| 99 String _libraryName(Uri importUri) { | 198 String _libraryName(Uri importUri) { |
| 100 var uri = importUri.toString(); | 199 String uri = importUri.toString(); |
| 101 int index = uri.indexOf('/'); | 200 int index = uri.indexOf('/'); |
| 102 if (index >= 0) { | 201 if (index >= 0) { |
| 103 return uri.substring(0, index); | 202 return uri.substring(0, index); |
| 104 } | 203 } |
| 105 return uri; | 204 return uri; |
| 106 } | 205 } |
| 107 | 206 |
| 108 /// Return the part path of [importUri]. | 207 /// Return the part path of [importUri]. |
| 109 String _partPath(Uri importUri) { | 208 String _partPath(Uri importUri) { |
| 110 var uri = importUri.toString(); | 209 String uri = importUri.toString(); |
| 111 int index = uri.indexOf('/'); | 210 int index = uri.indexOf('/'); |
| 112 if (index >= 0) { | 211 if (index >= 0) { |
| 113 return uri.substring(index + 1); | 212 return uri.substring(index + 1); |
| 114 } | 213 } |
| 115 return null; | 214 return null; |
| 116 } | 215 } |
| 117 | 216 |
| 118 /// Given a package [name] and a list of folders ([libDirs]), | |
| 119 /// add any found sdk extensions. | |
| 120 void _processPackage(String name, List<Folder> libDirs) { | |
| 121 for (var libDir in libDirs) { | |
| 122 var sdkExt = _readDotSdkExt(libDir); | |
| 123 if (sdkExt != null) { | |
| 124 _processSdkExt(sdkExt, libDir); | |
| 125 } | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 /// Given the JSON for an SDK extension ([sdkExtJSON]) and a folder | |
| 130 /// ([libDir]), setup the uri mapping. | |
| 131 void _processSdkExt(String sdkExtJSON, Folder libDir) { | |
| 132 var sdkExt; | |
| 133 try { | |
| 134 sdkExt = JSON.decode(sdkExtJSON); | |
| 135 } catch (e) { | |
| 136 return; | |
| 137 } | |
| 138 if ((sdkExt == null) || (sdkExt is! Map)) { | |
| 139 return; | |
| 140 } | |
| 141 sdkExt.forEach((k, v) => _processSdkExtension(k, v, libDir)); | |
| 142 } | |
| 143 | |
| 144 /// Install the mapping from [name] to [libDir]/[file]. | |
| 145 void _processSdkExtension(String name, String file, Folder libDir) { | |
| 146 if (!name.startsWith(DART_COLON_PREFIX)) { | |
| 147 // SDK extensions must begin with 'dart:'. | |
| 148 return; | |
| 149 } | |
| 150 var key = name; | |
| 151 var value = libDir.canonicalizePath(file); | |
| 152 _urlMappings[key] = value; | |
| 153 } | |
| 154 | |
| 155 /// Read the contents of [libDir]/[SDK_EXT_NAME] as a string. | |
| 156 /// Returns null if the file doesn't exist. | |
| 157 String _readDotSdkExt(Folder libDir) { | |
| 158 var file = libDir.getChild(SDK_EXT_NAME); | |
| 159 try { | |
| 160 return file.readAsStringSync(); | |
| 161 } on FileSystemException { | |
| 162 // File can't be read. | |
| 163 return null; | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 /// Resolve an import of an sdk extension. | 217 /// Resolve an import of an sdk extension. |
| 168 Source _resolveEntry(Uri libraryEntry, Uri importUri) { | 218 Source _resolveEntry(Uri libraryEntry, Uri importUri) { |
| 169 // Library entry. | 219 // Library entry. |
| 170 JavaFile javaFile = new JavaFile.fromUri(libraryEntry); | 220 JavaFile javaFile = new JavaFile.fromUri(libraryEntry); |
| 171 return new FileBasedSource(javaFile, importUri); | 221 return new FileBasedSource(javaFile, importUri); |
| 172 } | 222 } |
| 173 | 223 |
| 174 /// Resolve a 'part' statement inside an sdk extension. | 224 /// Resolve a 'part' statement inside an sdk extension. |
| 175 Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) { | 225 Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) { |
| 176 // Library part. | 226 // Library part. |
| 177 var directory = pathos.dirname(libraryEntry.path); | 227 String directory = pathos.dirname(libraryEntry.path); |
| 178 var partUri = new Uri.file(pathos.join(directory, partPath)); | 228 Uri partUri = new Uri.file(pathos.join(directory, partPath)); |
| 179 assert(partUri.isAbsolute); | 229 assert(partUri.isAbsolute); |
| 180 JavaFile javaFile = new JavaFile.fromUri(partUri); | 230 JavaFile javaFile = new JavaFile.fromUri(partUri); |
| 181 return new FileBasedSource(javaFile, importUri); | 231 return new FileBasedSource(javaFile, importUri); |
| 182 } | 232 } |
| 183 } | 233 } |
| OLD | NEW |