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; | 11 final _root = currentMirrorSystem().isolate.rootLibrary; |
12 | 12 |
13 Queue<Function> loadInitializers( | 13 Queue<Function> loadInitializers( |
14 {List<Type> typeFilter, InitializerFilter customFilter}) { | 14 {List<Type> typeFilter, InitializerFilter customFilter, Uri from}) { |
15 return new InitializationCrawler(typeFilter, customFilter).run(); | 15 return new InitializationCrawler(typeFilter, customFilter, from: from).run(); |
16 } | 16 } |
17 | 17 |
18 // Crawls a library and all its dependencies for `Initializer` annotations using | 18 // Crawls a library and all its dependencies for `Initializer` annotations using |
19 // mirrors | 19 // mirrors |
20 class InitializationCrawler { | 20 class InitializationCrawler { |
21 // Set of all visited annotations, keys are the declarations that were | 21 // Set of all visited annotations, keys are the declarations that were |
22 // annotated, values are the annotations that have been processed. | 22 // annotated, values are the annotations that have been processed. |
23 static final _annotationsFound = | 23 static final _annotationsFound = |
24 new Map<DeclarationMirror, Set<InstanceMirror>>(); | 24 new Map<DeclarationMirror, Set<InstanceMirror>>(); |
25 | 25 |
26 // If non-null, then only these annotations should be processed. | 26 // If non-null, then only these annotations should be processed. |
27 final List<Type> typeFilter; | 27 final List<Type> typeFilter; |
28 | 28 |
29 // 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 |
30 // function will be processed. | 30 // function will be processed. |
31 final InitializerFilter customFilter; | 31 final InitializerFilter customFilter; |
32 | 32 |
33 InitializationCrawler(this.typeFilter, this.customFilter); | 33 /// The library to start crawling from. |
| 34 final LibraryMirror _rootLibrary; |
| 35 |
| 36 /// Note: The [from] argument is only supported in the mirror_loader.dart. It |
| 37 /// is not supported statically. |
| 38 InitializationCrawler(this.typeFilter, this.customFilter, {Uri from}) |
| 39 : _rootLibrary = from == null |
| 40 ? _root |
| 41 : currentMirrorSystem().libraries[from] { |
| 42 if (_rootLibrary == null) throw 'Unable to find library at $from.'; |
| 43 } |
34 | 44 |
35 // The primary function in this class, invoke it to crawl and collect all the | 45 // The primary function in this class, invoke it to crawl and collect all the |
36 // annotations into a queue of init functions. | 46 // annotations into a queue of init functions. |
37 Queue<Function> run() { | 47 Queue<Function> run() { |
38 var librariesSeen = new Set<LibraryMirror>(); | 48 var librariesSeen = new Set<LibraryMirror>(); |
39 var queue = new Queue<Function>(); | 49 var queue = new Queue<Function>(); |
40 var libraries = currentMirrorSystem().libraries; | 50 var libraries = currentMirrorSystem().libraries; |
41 | 51 |
42 var trampolineUri = Uri.parse('${_root.uri}\$trampoline'); | 52 _readLibraryDeclarations(_rootLibrary, librariesSeen, queue); |
43 if (libraries.containsKey(trampolineUri)) { | |
44 // In dartium, process all relative libraries in reverse order of when | |
45 // they were seen. | |
46 // TODO(jakemac): This is an approximation of what we actually want. | |
47 // https://github.com/dart-lang/initialize/issues/25 | |
48 var relativeLibraryUris = new List.from(libraries.keys | |
49 .where((uri) => uri.scheme != 'package' && uri.scheme != 'dart')); | |
50 | |
51 for (var import in relativeLibraryUris.reversed) { | |
52 // Always load the package: version of a library if available for | |
53 // canonicalization purposes. | |
54 var libToRun; | |
55 if (_isHttpStylePackageUrl(import)) { | |
56 var packageUri = _packageUriFor(import); | |
57 libToRun = libraries[packageUri]; | |
58 } | |
59 if (libToRun == null) libToRun = libraries[import]; | |
60 | |
61 // Dartium creates an extra trampoline lib that loads the main dart scri
pt | |
62 // and breaks our ordering, we should skip it. | |
63 if (librariesSeen.contains(libToRun) || | |
64 libToRun.uri.path.endsWith('\$trampoline')) { | |
65 continue; | |
66 } | |
67 _readLibraryDeclarations(libToRun, librariesSeen, queue); | |
68 } | |
69 } else { | |
70 // Not in dartium, just process from the root library. | |
71 _readLibraryDeclarations(_root, librariesSeen, queue); | |
72 } | |
73 | |
74 return queue; | 53 return queue; |
75 } | 54 } |
76 | 55 |
77 /// Whether [uri] is an http URI that contains a 'packages' segment, and | 56 /// Whether [uri] is an http URI that contains a 'packages' segment, and |
78 /// therefore could be converted into a 'package:' URI. | 57 /// therefore could be converted into a 'package:' URI. |
79 bool _isHttpStylePackageUrl(Uri uri) { | 58 bool _isHttpStylePackageUrl(Uri uri) { |
80 var uriPath = uri.path; | 59 var uriPath = uri.path; |
81 return uri.scheme == _root.uri.scheme && | 60 return uri.scheme == _root.uri.scheme && |
82 // Don't process cross-domain uris. | 61 // Don't process cross-domain uris. |
83 uri.authority == _root.uri.authority && | 62 uri.authority == _root.uri.authority && |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 return true; | 218 return true; |
240 } | 219 } |
241 } | 220 } |
242 | 221 |
243 final _TOP_LEVEL_FUNCTIONS_ONLY = new UnsupportedError( | 222 final _TOP_LEVEL_FUNCTIONS_ONLY = new UnsupportedError( |
244 'Only top level methods are supported for initializers'); | 223 'Only top level methods are supported for initializers'); |
245 | 224 |
246 final _UNSUPPORTED_DECLARATION = new UnsupportedError( | 225 final _UNSUPPORTED_DECLARATION = new UnsupportedError( |
247 'Initializers are only supported on libraries, classes, and top level ' | 226 'Initializers are only supported on libraries, classes, and top level ' |
248 'methods'); | 227 'methods'); |
OLD | NEW |