| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 package com.google.dart.compiler; | 5 package com.google.dart.compiler; |
| 6 | 6 |
| 7 import java.io.BufferedInputStream; |
| 7 import java.io.File; | 8 import java.io.File; |
| 9 import java.io.FileInputStream; |
| 10 import java.io.FileNotFoundException; |
| 11 import java.io.IOException; |
| 12 import java.io.InputStream; |
| 8 import java.net.URI; | 13 import java.net.URI; |
| 9 import java.net.URISyntaxException; | 14 import java.net.URISyntaxException; |
| 10 import java.util.ArrayList; | 15 import java.util.ArrayList; |
| 11 import java.util.Arrays; | |
| 12 import java.util.Collection; | 16 import java.util.Collection; |
| 17 import java.util.HashMap; |
| 18 import java.util.HashSet; |
| 13 import java.util.List; | 19 import java.util.List; |
| 14 | 20 import java.util.Map; |
| 21 import java.util.Map.Entry; |
| 22 import java.util.Properties; |
| 15 | 23 |
| 16 /** | 24 /** |
| 17 * Manages the collection of {@link SystemLibrary}s. | 25 * A Library manager that manages system libraries |
| 18 */ | 26 */ |
| 19 public class SystemLibraryManager { | 27 public class SystemLibraryManager { |
| 20 | 28 |
| 21 public static class NotADartShortUriException extends RuntimeException { | 29 private static final String IMPORT_CONFIG = "import_%s.config"; |
| 30 |
| 31 private HashMap<String, String> expansionMap; |
| 32 private Map<String, SystemLibrary> hostMap; |
| 33 private final File sdkLibPath; |
| 34 private final URI sdkLibPathUri; |
| 35 private final String platformName; |
| 36 |
| 37 private Map<URI, URI> longToShortUriMap; |
| 22 | 38 |
| 23 public NotADartShortUriException(String uriString) { | 39 private List<SystemLibrary> libraries; |
| 24 super("Expected dart:<short name>, got: " + uriString); | |
| 25 } | |
| 26 | |
| 27 public NotADartShortUriException(URI uri) { | |
| 28 super("Expected dart:<short name>, got: " + uri.toString()); | |
| 29 } | |
| 30 } | |
| 31 | |
| 32 /** | |
| 33 * The "any" platform is meant to have definitions for all known dart system l
ibraries. | |
| 34 * Other implementations may only contain a subset. | |
| 35 */ | |
| 36 public static final String DEFAULT_PLATFORM = "any"; | |
| 37 public static final File DEFAULT_SDK_PATH = new File(System.getProperty( | |
| 38 "com.google.dart.sdk", "../")); | |
| 39 | |
| 40 public static final File DEFAULT_PACKAGE_ROOT = new File("packages"); | |
| 41 public static final List<File> DEFAULT_PACKAGE_ROOTS = Arrays.asList(new File[
] {DEFAULT_PACKAGE_ROOT}); | |
| 42 | |
| 43 public static final String PACKAGE_SCHEME = "package"; | |
| 44 public static final String PACKAGE_SCHEME_SPEC = "package:"; | |
| 45 | |
| 46 public static final String DART_SCHEME = "dart"; | |
| 47 public static final String DART_SCHEME_SPEC = "dart:"; | |
| 48 | |
| 49 | |
| 50 /** | |
| 51 * Answer <code>true</code> if the string is a dart spec | |
| 52 */ | |
| 53 public static boolean isDartSpec(String spec) { | |
| 54 return spec != null && spec.startsWith(DART_SCHEME_SPEC); | |
| 55 } | |
| 56 | |
| 57 /** | |
| 58 * Answer <code>true</code> if the specified URI has a "dart" scheme | |
| 59 */ | |
| 60 public static boolean isDartUri(URI uri) { | |
| 61 return uri != null && DART_SCHEME.equals(uri.getScheme()); | |
| 62 } | |
| 63 | |
| 64 /** | |
| 65 * Answer <code>true</code> if the string is a package spec | |
| 66 */ | |
| 67 public static boolean isPackageSpec(String spec) { | |
| 68 return spec != null && spec.startsWith(PACKAGE_SCHEME_SPEC); | |
| 69 } | |
| 70 | |
| 71 /** | |
| 72 * Answer <code>true</code> if the specified URI has a "package" scheme | |
| 73 */ | |
| 74 public static boolean isPackageUri(URI uri) { | |
| 75 return uri != null && PACKAGE_SCHEME.equals(uri.getScheme()); | |
| 76 } | |
| 77 | |
| 78 private static SdkLibraryManager SDK_LIBRARY_MANAGER; | |
| 79 | |
| 80 private List<File> packageRoots = new ArrayList<File>(); | |
| 81 private List<URI> packageRootsUri = new ArrayList<URI>(); | |
| 82 | |
| 83 public SystemLibraryManager() { | |
| 84 this(DEFAULT_SDK_PATH, DEFAULT_PLATFORM); | |
| 85 } | |
| 86 | 40 |
| 87 public SystemLibraryManager(File sdkPath, String platformName) { | 41 public SystemLibraryManager(File sdkPath, String platformName) { |
| 88 if (SDK_LIBRARY_MANAGER == null){ | 42 this.sdkLibPath = new File(sdkPath, "lib").getAbsoluteFile(); |
| 89 SDK_LIBRARY_MANAGER = new SdkLibraryManager(sdkPath, platformName); | 43 this.sdkLibPathUri = sdkLibPath.toURI(); |
| 90 } | 44 this.platformName = platformName; |
| 91 setPackageRoots(DEFAULT_PACKAGE_ROOTS); | 45 setLibraries(getDefaultLibraries()); |
| 46 |
| 92 } | 47 } |
| 93 | 48 |
| 94 | |
| 95 /** | |
| 96 * Expand a relative or short URI (e.g. "dart:html") which is implementation i
ndependent to its | |
| 97 * full URI (e.g. "dart://html/com/google/dart/htmllib/html.dart"). | |
| 98 * | |
| 99 * @param uri the relative URI | |
| 100 * @return the expanded URI | |
| 101 * or the original URI if it could not be expanded | |
| 102 * or null if the uri is of the form "dart:<libname>" but does not correspond
to a system library | |
| 103 */ | |
| 104 public URI expandRelativeDartUri(URI uri) throws AssertionError { | 49 public URI expandRelativeDartUri(URI uri) throws AssertionError { |
| 105 if (isDartUri(uri)) { | |
| 106 return SDK_LIBRARY_MANAGER.expandRelativeDartUri(uri); | |
| 107 } | |
| 108 if (isPackageUri(uri)){ | |
| 109 String host = uri.getHost(); | 50 String host = uri.getHost(); |
| 110 if (host == null) { | 51 if (host == null) { |
| 111 String spec = uri.getSchemeSpecificPart(); | 52 String spec = uri.getSchemeSpecificPart(); |
| 112 if (!spec.startsWith("//")){ | 53 String replacement = expansionMap.get(spec); |
| 54 if (replacement != null) { |
| 113 try { | 55 try { |
| 114 if (spec.startsWith("/")){ | 56 uri = new URI(PackageLibraryManager.DART_SCHEME + ":" + replacement)
; |
| 115 // TODO(keertip): fix to handle spaces | |
| 116 uri = new URI(PACKAGE_SCHEME + ":/" + spec); | |
| 117 } else { | |
| 118 uri = new URI(PACKAGE_SCHEME + "://" + spec); | |
| 119 } | |
| 120 } catch (URISyntaxException e) { | 57 } catch (URISyntaxException e) { |
| 121 throw new AssertionError(); | 58 throw new AssertionError(); |
| 122 } | 59 } |
| 123 } | 60 } else { |
| 61 return null; |
| 62 } |
| 124 } | 63 } |
| 125 } | 64 return uri; |
| 126 return uri; | |
| 127 } | 65 } |
| 128 | |
| 129 | |
| 130 | 66 |
| 131 /** | |
| 132 * Given an absolute file URI (e.g. "file:/some/install/directory/dart-sdk/lib
/core/bool.dart"), | |
| 133 * answer the corresponding dart: URI (e.g. "dart://core/bool.dart") for that
file URI, | |
| 134 * or <code>null</code> if the file URI does not map to a dart: URI | |
| 135 * @param fileUri the file URI | |
| 136 * @return the dart URI or <code>null</code> | |
| 137 */ | |
| 138 public URI getRelativeUri(URI fileUri) { | 67 public URI getRelativeUri(URI fileUri) { |
| 139 // TODO (danrubel): does not convert dart: libraries outside the dart-sdk/li
b directory | 68 |
| 140 if (fileUri == null || !fileUri.getScheme().equals("file")) { | 69 if (fileUri == null || !fileUri.getScheme().equals("file")){ |
| 141 return null; | 70 return null; |
| 142 } | 71 } |
| 143 | 72 |
| 144 URI relativeUri = SDK_LIBRARY_MANAGER.getRelativeUri(fileUri); | 73 URI relativeUri = sdkLibPathUri.relativize(fileUri); |
| 145 if (relativeUri != null){ | 74 if (relativeUri.getScheme() == null) { |
| 146 return relativeUri; | 75 try { |
| 147 } | 76 return new URI(null, null, "dart://" + relativeUri.getPath(), null, null
); |
| 148 | 77 } catch (URISyntaxException e) { |
| 149 for (URI rootUri : packageRootsUri){ | |
| 150 relativeUri = rootUri.relativize(fileUri); | |
| 151 if (relativeUri.getScheme() == null) { | |
| 152 try { | |
| 153 return new URI(null, null, "package://" + relativeUri.getPath(), nul
l, null); | |
| 154 } catch (URISyntaxException e) { | |
| 155 //$FALL-THROUGH$ | 78 //$FALL-THROUGH$ |
| 156 } | |
| 157 } | 79 } |
| 158 } | 80 } |
| 159 return null; | 81 return null; |
| 160 } | 82 } |
| 161 | 83 |
| 162 /** | |
| 163 * Given a package URI (package:foo/foo.dart), convert it into a file system U
RI. | |
| 164 * | |
| 165 * @param relPath | |
| 166 * @return | |
| 167 */ | |
| 168 public URI resolvePackageUri(String packageUriRef) { | |
| 169 if (packageUriRef.startsWith(PACKAGE_SCHEME_SPEC)) { | |
| 170 String relPath = packageUriRef.substring(PACKAGE_SCHEME_SPEC.length()); | |
| 171 if (relPath.startsWith("/")){ | |
| 172 relPath = relPath.replaceAll("^\\/+", ""); | |
| 173 } | |
| 174 for (URI rootUri : packageRootsUri){ | |
| 175 URI fileUri = rootUri.resolve(relPath); | |
| 176 if (new File(fileUri).exists()){ | |
| 177 return fileUri; | |
| 178 } | |
| 179 } | |
| 180 // don't return null for package scheme | |
| 181 return packageRootsUri.get(0).resolve(relPath); | |
| 182 } | |
| 183 return null; | |
| 184 } | |
| 185 | |
| 186 /** | |
| 187 * Answer the original "dart:<libname>" URI for the specified resolved URI or
<code>null</code> if | |
| 188 * it does not map to a short URI. | |
| 189 */ | |
| 190 public URI getShortUri(URI uri) { | 84 public URI getShortUri(URI uri) { |
| 191 URI shortUri = SDK_LIBRARY_MANAGER.getShortUri(uri); | 85 URI shortUri = longToShortUriMap.get(uri); |
| 192 if (shortUri != null){ | 86 if (shortUri != null){ |
| 193 return shortUri; | 87 return shortUri; |
| 194 } | 88 } |
| 195 shortUri = getRelativeUri(uri); | 89 shortUri = getRelativeUri(uri); |
| 196 if (shortUri != null){ | 90 if (shortUri != null){ |
| 197 try { | 91 try { |
| 198 return new URI(null, null, shortUri.getScheme() + ":" + shortUri.getHos
t() + shortUri.getPath(),null, null); | 92 return new URI(null, null, shortUri.getScheme() + ":" + shortUri.getHos
t() + shortUri.getPath(),null, null); |
| 199 } catch (URISyntaxException e) { | 93 } catch (URISyntaxException e) { |
| 200 } | 94 } |
| 201 } | 95 } |
| 202 return null; | 96 return null; |
| 203 } | 97 } |
| 204 | 98 |
| 205 /** | 99 public URI translateDartUri(URI uri) { |
| 206 * Expand a relative or short URI (e.g. "dart:html") which is implementation i
ndependent to its | 100 |
| 207 * full URI (e.g. "dart://html/com/google/dart/htmllib/html.dart") and then tr
anslate that URI to | 101 String host = uri.getHost(); |
| 208 * a "file:" URI (e.g. | 102 SystemLibrary library = hostMap.get(host); |
| 209 * "file:/some/install/directory/com/google/dart/htmllib/html.dart"). | 103 if (library != null) { |
| 210 * | 104 return library.translateUri(uri); |
| 211 * @param uri the original URI | 105 } |
| 212 * @return the expanded and translated URI, which may be <code>null</code> and
may not exist | 106 if (host != null) { |
| 213 * @exception RuntimeException if the URI is a "dart" scheme, but does not map
to a defined system | 107 return new File(getSdkLibPath(), host).toURI().resolve("." + uri.getPath
()); |
| 214 * library | 108 } |
| 215 */ | 109 throw new RuntimeException("No system library defined for " + uri); |
| 216 public URI resolveDartUri(URI uri) { | 110 |
| 217 return translateDartUri(expandRelativeDartUri(uri)); | |
| 218 } | 111 } |
| 219 | 112 |
| 220 | 113 |
| 221 public List<File> getPackageRoots(){ | 114 public Collection<String> getAllLibrarySpecs() { |
| 222 return packageRoots; | 115 Collection<String> result = new ArrayList<String>(libraries.size()); |
| 116 for (SystemLibrary lib : libraries) { |
| 117 result.add("dart:" + lib.getShortName()); |
| 118 } |
| 119 return result; |
| 223 } | 120 } |
| 224 | 121 |
| 225 | 122 |
| 226 public void setPackageRoots(List<File> roots){ | 123 /** |
| 227 if (roots == null || roots.isEmpty()){ | 124 * Scan the directory returned by {@link #getLibrariesDir()} looking for libra
ries of the form |
| 228 this.packageRoots = DEFAULT_PACKAGE_ROOTS; | 125 * libraries/<name>/<name>_<platform>.dart and libraries/<name>/<name>.dart wh
ere <platform> is |
| 229 } else { | 126 * the value initialized in the {@link SystemLibraryManager}. |
| 230 packageRoots.clear(); | 127 */ |
| 231 for (File file : roots){ | 128 protected SystemLibrary[] getDefaultLibraries() { |
| 232 packageRoots.add(file.getAbsoluteFile()); | 129 libraries = new ArrayList<SystemLibrary>(); |
| 233 } | 130 longToShortUriMap = new HashMap<URI, URI>(); |
| 131 |
| 132 // Cycle through the import.config, extracting explicit mappings and searchi
ng directories |
| 133 URI base = this.sdkLibPathUri; |
| 134 Properties importConfig = getImportConfig(); |
| 135 HashSet<String> explicitShortNames = new HashSet<String>(); |
| 136 for (Entry<Object, Object> entry : importConfig.entrySet()) { |
| 137 String shortName = ((String) entry.getKey()).trim(); |
| 138 String path = ((String) entry.getValue()).trim(); |
| 139 |
| 140 File file; |
| 141 try { |
| 142 file = new File(base.resolve(new URI(null, null, path, null, null)).norm
alize()); |
| 143 } catch (URISyntaxException e) { |
| 144 continue; |
| 145 } |
| 146 if (!file.exists()) { |
| 147 throw new InternalCompilerException("Can't find system library dart:" +
shortName |
| 148 + " at " + file); |
| 149 } |
| 150 |
| 151 // If the shortName ends with ":" then search the associated directory for
libraries |
| 152 |
| 153 if (shortName.endsWith(":")) { |
| 154 if (!file.isDirectory()) { |
| 155 continue; |
| 156 } |
| 157 for (File child : file.listFiles()) { |
| 158 String host = child.getName(); |
| 159 // Do not overwrite explicit shortName to dart file mappings |
| 160 if (explicitShortNames.contains(shortName + host)) { |
| 161 continue; |
| 162 } |
| 163 if (!child.isDirectory()) { |
| 164 continue; |
| 165 } |
| 166 File dartFile = new File(child, child.getName() + ".dart"); |
| 167 if (!dartFile.isFile()) { |
| 168 // addLib() will throw an exception. In this case, we are just scann
ing |
| 169 // for libraries and don't want the error to be fatal. |
| 170 continue; |
| 171 } |
| 172 addLib(shortName, host, host, child, dartFile.getName()); |
| 173 } |
| 174 } else { |
| 175 // Otherwise treat the entry as an explicit shortName to dart file mappi
ng |
| 176 int index = shortName.indexOf(':'); |
| 177 if (index == -1) { |
| 178 continue; |
| 179 } |
| 180 explicitShortNames.add(shortName); |
| 181 String scheme = shortName.substring(0, index + 1); |
| 182 String name = shortName.substring(index + 1); |
| 183 String host = file.getParentFile().getName(); |
| 184 addLib(scheme, host, name, file.getParentFile(), file.getName()); |
| 185 } |
| 234 } | 186 } |
| 235 packageRootsUri.clear(); | 187 return libraries.toArray(new SystemLibrary[libraries.size()]); |
| 236 for (File file : roots){ | 188 } |
| 237 packageRootsUri.add(file.toURI()); | 189 |
| 190 /** |
| 191 * Read the import.config content and return it as a collection of key/value p
airs |
| 192 */ |
| 193 protected Properties getImportConfig() { |
| 194 Properties importConfig = new Properties(); |
| 195 InputStream stream = getImportConfigStream(); |
| 196 try { |
| 197 importConfig.load(stream); |
| 198 } catch (IOException ignored) { |
| 199 } finally { |
| 200 try { |
| 201 stream.close(); |
| 202 } catch (IOException ignored) { |
| 203 } |
| 204 } |
| 205 return importConfig; |
| 206 } |
| 207 |
| 208 protected InputStream getImportConfigStream() { |
| 209 File file = new File(new File(sdkLibPath, "config"), |
| 210 String.format(IMPORT_CONFIG, platformName)); |
| 211 if (!file.exists()) { |
| 212 throw new InternalCompilerException("Failed to find " + file.toString() |
| 213 + ". Is dart-sdk path correct?"); |
| 214 } |
| 215 try { |
| 216 return new BufferedInputStream(new FileInputStream(file)); |
| 217 } catch (FileNotFoundException e) { |
| 218 throw new InternalCompilerException("Failed to open " + file); |
| 238 } | 219 } |
| 239 } | 220 } |
| 240 | 221 |
| 241 /** | 222 |
| 242 * Translate the URI from dart://[host]/[pathToLib] (e.g. dart://html/html.dar
t) | 223 private boolean addLib(String scheme, String host, String name, File dir, Stri
ng libFileName) |
| 243 * to a "file:" URI (e.g. "file:/some/install/directory/html.dart") | 224 throws AssertionError { |
| 244 * | 225 File libFile = new File(dir, libFileName); |
| 245 * @param uri the original URI | 226 if (!libFile.isFile()) { |
| 246 * @return the translated URI, which may be <code>null</code> and may not exis
t | 227 throw new InternalCompilerException("Error mapping dart:" + host + ", path
" |
| 247 * @exception RuntimeException if the URI is a "dart" scheme, | 228 + libFile.getAbsolutePath() + " is not a file."); |
| 248 * but does not map to a defined system library | |
| 249 */ | |
| 250 public URI translateDartUri(URI uri) { | |
| 251 if (isDartUri(uri)) { | |
| 252 return SDK_LIBRARY_MANAGER.translateDartUri(uri); | |
| 253 } | |
| 254 if (isPackageUri(uri)){ | |
| 255 URI fileUri; | |
| 256 for (URI rootUri : packageRootsUri){ | |
| 257 fileUri = getResolvedPackageUri(uri, rootUri); | |
| 258 File file = new File(fileUri); | |
| 259 if (file.exists()){ | |
| 260 return file.toURI(); | |
| 261 } | |
| 262 } | |
| 263 // resolve against first package root | |
| 264 fileUri = getResolvedPackageUri(uri, packageRootsUri.get(0)); | |
| 265 return fileUri; | |
| 266 } | 229 } |
| 267 return uri; | 230 SystemLibrary lib = new SystemLibrary(name, host, libFileName, dir); |
| 268 } | 231 libraries.add(lib); |
| 269 | 232 String libSpec = scheme + name; |
| 270 /** | 233 URI libUri; |
| 271 * Given a uri, resolve against the list of package roots, used to find genera
ted files | 234 URI expandedUri; |
| 272 * @return uri - resolved uri if file exists, else return given uri | 235 try { |
| 273 */ | 236 libUri = new URI(libSpec); |
| 274 public URI findExistingFileInPackages(URI fileUri){ | 237 expandedUri = new URI("dart:" + "//" + host + "/" + libFileName); |
| 275 | 238 } catch (URISyntaxException e) { |
| 276 URI resolvedUri = getRelativeUri(fileUri); | 239 throw new AssertionError(e); |
| 277 if (isPackageUri(resolvedUri)){ | |
| 278 resolvedUri = resolvePackageUri(resolvedUri.toString()); | |
| 279 return resolvedUri; | |
| 280 } | 240 } |
| 281 return fileUri; | 241 URI resolvedUri = lib.translateUri(expandedUri); |
| 242 longToShortUriMap.put(resolvedUri, libUri); |
| 243 longToShortUriMap.put(expandedUri, libUri); |
| 244 return true; |
| 282 } | 245 } |
| 283 | 246 |
| 284 /** | 247 /** |
| 285 * Resolves the given uri against the package root uri | 248 * Register system libraries for the "dart:" protocol such that dart:[shortLib
Name] (e.g. |
| 249 * "dart:html") will automatically be expanded to dart://[host]/[pathToLib] (e
.g. |
| 250 * dart://html/html.dart) |
| 286 */ | 251 */ |
| 287 private URI getResolvedPackageUri(URI uri, URI packageRootUri) { | 252 private void setLibraries(SystemLibrary[] newLibraries) { |
| 288 URI fileUri; | 253 libraries = new ArrayList<SystemLibrary>(); |
| 289 // TODO(keertip): Investigate further | 254 hostMap = new HashMap<String, SystemLibrary>(); |
| 290 // if uri.getHost() returns null, then it is resolved right | 255 expansionMap = new HashMap<String, String>(); |
| 291 // so use uri.getAuthority to resolve | 256 for (SystemLibrary library : newLibraries) { |
| 292 // package://third_party/dart_lang/lib/unittest/unittest.dart | 257 String host = library.getHost(); |
| 293 if (uri.getHost() != null){ | 258 SystemLibrary existingLib = hostMap.get(host); |
| 294 fileUri = packageRootUri.resolve(uri.getHost() + uri.getPath()); | 259 if (existingLib != null) { |
| 295 } else { | 260 libraries.remove(existingLib); |
| 296 fileUri = packageRootUri.resolve(uri.getAuthority() + uri.getPath()); | 261 } |
| 262 libraries.add(library); |
| 263 hostMap.put(host, library); |
| 264 expansionMap.put(library.getShortName(), |
| 265 "//" + host + "/" + library.getPathToLib()); |
| 297 } | 266 } |
| 298 return fileUri; | |
| 299 } | |
| 300 | |
| 301 /** | |
| 302 * Answer a collection of all bundled library URL specs (e.g. "dart:html"). | |
| 303 * | |
| 304 * @return a collection of specs (not <code>null</code>, contains no <code>nul
l</code>s) | |
| 305 */ | |
| 306 public Collection<String> getAllLibrarySpecs() { | |
| 307 return SDK_LIBRARY_MANAGER.getAllLibrarySpecs(); | |
| 308 } | |
| 309 | |
| 310 protected SystemLibrary[] getDefaultLibraries() { | |
| 311 return SDK_LIBRARY_MANAGER.getDefaultLibraries(); | |
| 312 | |
| 313 } | 267 } |
| 314 | 268 |
| 315 public File getSdkLibPath() { | 269 public File getSdkLibPath() { |
| 316 return SDK_LIBRARY_MANAGER.getSdkLibPath(); | 270 return sdkLibPath; |
| 317 } | 271 } |
| 318 | 272 |
| 319 | |
| 320 | |
| 321 } | 273 } |
| OLD | NEW |