| 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 library initialize.mirror_loader; | 4 library initialize.mirror_loader; |
| 5 | 5 |
| 6 import 'dart:collection' show Queue; | 6 import 'dart:collection' show Queue; |
| 7 import 'dart:mirrors'; | 7 import 'dart:mirrors'; |
| 8 import 'package:path/path.dart' as path; | 8 import 'package:path/path.dart' as path; |
| 9 import 'package:initialize/initialize.dart'; | 9 import 'package:initialize/initialize.dart'; |
| 10 | 10 |
| 11 final _root = currentMirrorSystem().isolate.rootLibrary; |
| 12 |
| 11 Queue<Function> loadInitializers( | 13 Queue<Function> loadInitializers( |
| 12 {List<Type> typeFilter, InitializerFilter customFilter}) { | 14 {List<Type> typeFilter, InitializerFilter customFilter}) { |
| 13 return new InitializationCrawler(typeFilter, customFilter).run(); | 15 return new InitializationCrawler(typeFilter, customFilter).run(); |
| 14 } | 16 } |
| 15 | 17 |
| 16 // Crawls a library and all its dependencies for `Initializer` annotations using | 18 // Crawls a library and all its dependencies for `Initializer` annotations using |
| 17 // mirrors | 19 // mirrors |
| 18 class InitializationCrawler { | 20 class InitializationCrawler { |
| 19 // Set of all visited annotations, keys are the declarations that were | 21 // Set of all visited annotations, keys are the declarations that were |
| 20 // annotated, values are the annotations that have been processed. | 22 // annotated, values are the annotations that have been processed. |
| 21 static final _annotationsFound = | 23 static final _annotationsFound = |
| 22 new Map<DeclarationMirror, Set<InstanceMirror>>(); | 24 new Map<DeclarationMirror, Set<InstanceMirror>>(); |
| 23 | 25 |
| 24 // If non-null, then only these annotations should be processed. | 26 // If non-null, then only these annotations should be processed. |
| 25 final List<Type> typeFilter; | 27 final List<Type> typeFilter; |
| 26 | 28 |
| 27 // If non-null, then only annotations which return true when passed to this | 29 // If non-null, then only annotations which return true when passed to this |
| 28 // function will be processed. | 30 // function will be processed. |
| 29 final InitializerFilter customFilter; | 31 final InitializerFilter customFilter; |
| 30 | 32 |
| 31 // The root library that we start parsing from. | 33 InitializationCrawler(this.typeFilter, this.customFilter); |
| 32 LibraryMirror _root; | |
| 33 | |
| 34 InitializationCrawler(this.typeFilter, this.customFilter, | |
| 35 {LibraryMirror root}) { | |
| 36 _root = root == null ? currentMirrorSystem().isolate.rootLibrary : root; | |
| 37 } | |
| 38 | 34 |
| 39 // The primary function in this class, invoke it to crawl and collect all the | 35 // The primary function in this class, invoke it to crawl and collect all the |
| 40 // annotations into a queue of init functions. | 36 // annotations into a queue of init functions. |
| 41 Queue<Function> run() => _readLibraryDeclarations(_root); | 37 Queue<Function> run() { |
| 38 var librariesSeen = new Set<LibraryMirror>(); |
| 39 var queue = new Queue<Function>(); |
| 40 |
| 41 var libraries = currentMirrorSystem().libraries; |
| 42 var nonDartOrPackageImports = new List.from(libraries.keys.where( |
| 43 (uri) => uri.scheme != 'package' && uri.scheme != 'dart')); |
| 44 |
| 45 for (var import in nonDartOrPackageImports.reversed) { |
| 46 // Always load the package: version of a library if available. |
| 47 var libToRun; |
| 48 if (_isHttpStylePackageUrl(import)) { |
| 49 var packageUri = _packageUriFor(import); |
| 50 libToRun = libraries[packageUri]; |
| 51 } |
| 52 if (libToRun == null) libToRun = libraries[import]; |
| 53 |
| 54 // Dartium creates an extra trampoline lib that loads the main dart script |
| 55 // and breaks our ordering. |
| 56 if (librariesSeen.contains(libToRun) || |
| 57 libToRun.uri.path.endsWith('\$trampoline')) { |
| 58 continue; |
| 59 } |
| 60 _readLibraryDeclarations(libToRun, librariesSeen, queue); |
| 61 } |
| 62 |
| 63 return queue; |
| 64 } |
| 65 |
| 66 /// Whether [uri] is an http URI that contains a 'packages' segment, and |
| 67 /// therefore could be converted into a 'package:' URI. |
| 68 bool _isHttpStylePackageUrl(Uri uri) { |
| 69 var uriPath = uri.path; |
| 70 return uri.scheme == _root.uri.scheme && |
| 71 // Don't process cross-domain uris. |
| 72 uri.authority == _root.uri.authority && |
| 73 uriPath.endsWith('.dart') && |
| 74 (uriPath.contains('/packages/') || uriPath.startsWith('packages/')); |
| 75 } |
| 76 |
| 77 Uri _packageUriFor(Uri httpUri) { |
| 78 var packagePath = httpUri.path.substring( |
| 79 httpUri.path.lastIndexOf('packages/') + 'packages/'.length); |
| 80 return Uri.parse('package:$packagePath'); |
| 81 } |
| 42 | 82 |
| 43 // Reads Initializer annotations on this library and all its dependencies in | 83 // Reads Initializer annotations on this library and all its dependencies in |
| 44 // post-order. | 84 // post-order. |
| 45 Queue<Function> _readLibraryDeclarations(LibraryMirror lib, | 85 Queue<Function> _readLibraryDeclarations(LibraryMirror lib, |
| 46 [Set<LibraryMirror> librariesSeen, Queue<Function> queue]) { | 86 Set<LibraryMirror> librariesSeen, Queue<Function> queue) { |
| 47 if (librariesSeen == null) librariesSeen = new Set<LibraryMirror>(); | |
| 48 if (queue == null) queue = new Queue<Function>(); | |
| 49 librariesSeen.add(lib); | 87 librariesSeen.add(lib); |
| 50 | 88 |
| 51 // First visit all our dependencies. | 89 // First visit all our dependencies. |
| 52 for (var dependency in _sortedLibraryDependencies(lib)) { | 90 for (var dependency in _sortedLibraryDependencies(lib)) { |
| 53 // Skip dart: imports, they never use this package. | 91 // Skip dart: imports, they never use this package. |
| 54 if (dependency.targetLibrary.uri.toString().startsWith('dart:')) continue; | 92 if (dependency.targetLibrary.uri.toString().startsWith('dart:')) continue; |
| 55 if (librariesSeen.contains(dependency.targetLibrary)) continue; | 93 if (librariesSeen.contains(dependency.targetLibrary)) continue; |
| 56 | 94 |
| 57 _readLibraryDeclarations(dependency.targetLibrary, librariesSeen, queue); | 95 _readLibraryDeclarations(dependency.targetLibrary, librariesSeen, queue); |
| 58 } | 96 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 if (declaration.owner is! LibraryMirror) { | 179 if (declaration.owner is! LibraryMirror) { |
| 142 // TODO(jakemac): Support static class methods. | 180 // TODO(jakemac): Support static class methods. |
| 143 throw _TOP_LEVEL_FUNCTIONS_ONLY; | 181 throw _TOP_LEVEL_FUNCTIONS_ONLY; |
| 144 } | 182 } |
| 145 annotatedValue = (declaration.owner as ObjectMirror) | 183 annotatedValue = (declaration.owner as ObjectMirror) |
| 146 .getField(declaration.simpleName).reflectee; | 184 .getField(declaration.simpleName).reflectee; |
| 147 } else if (declaration is LibraryMirror) { | 185 } else if (declaration is LibraryMirror) { |
| 148 var package; | 186 var package; |
| 149 var filePath; | 187 var filePath; |
| 150 Uri uri = declaration.uri; | 188 Uri uri = declaration.uri; |
| 189 // Convert to a package style uri if possible. |
| 190 if (_isHttpStylePackageUrl(uri)) { |
| 191 uri = _packageUriFor(uri); |
| 192 } |
| 151 if (uri.scheme == 'file' || uri.scheme.startsWith('http')) { | 193 if (uri.scheme == 'file' || uri.scheme.startsWith('http')) { |
| 152 filePath = path.url.relative(uri.path, | 194 filePath = path.url.relative(uri.path, |
| 153 from: path.url.dirname(_root.uri.path)); | 195 from: path.url.dirname(_root.uri.path)); |
| 154 } else if (uri.scheme == 'package') { | 196 } else if (uri.scheme == 'package') { |
| 155 var segments = uri.pathSegments; | 197 var segments = uri.pathSegments; |
| 156 package = segments[0]; | 198 package = segments[0]; |
| 157 filePath = path.url.joinAll(segments.getRange(1, segments.length)); | 199 filePath = path.url.joinAll(segments.getRange(1, segments.length)); |
| 158 } else { | 200 } else { |
| 159 throw new UnsupportedError('Unsupported uri scheme ${uri.scheme} for ' | 201 throw new UnsupportedError('Unsupported uri scheme ${uri.scheme} for ' |
| 160 'library ${declaration}.'); | 202 'library ${declaration}.'); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 185 return true; | 227 return true; |
| 186 } | 228 } |
| 187 } | 229 } |
| 188 | 230 |
| 189 final _TOP_LEVEL_FUNCTIONS_ONLY = new UnsupportedError( | 231 final _TOP_LEVEL_FUNCTIONS_ONLY = new UnsupportedError( |
| 190 'Only top level methods are supported for initializers'); | 232 'Only top level methods are supported for initializers'); |
| 191 | 233 |
| 192 final _UNSUPPORTED_DECLARATION = new UnsupportedError( | 234 final _UNSUPPORTED_DECLARATION = new UnsupportedError( |
| 193 'Initializers are only supported on libraries, classes, and top level ' | 235 'Initializers are only supported on libraries, classes, and top level ' |
| 194 'methods'); | 236 'methods'); |
| OLD | NEW |