add from option to run

R=sigmund@google.com

Review URL: https://codereview.chromium.org//1008533003
diff --git a/.status b/.status
index 9f3adba..7c37a03 100644
--- a/.status
+++ b/.status
@@ -14,15 +14,17 @@
 # tests that don't need to be ran after pub-build
 build/test/transformer_test: Skip
 build/test/initializer_cycle_error_test.initialize_test: Skip # Build time warning
+build/test/initializer_from_test: RuntimeError # By Design
 
 # tests that need to run, but we use the bootstrap output instead
 # (build/test/foo.initialize.dart) which is renamed by the .test_config scripts.
 build/test/deferred_library_test: Skip
 build/test/initializer_custom_filter_test: Skip
 build/test/initializer_cycle_error_test: Skip
-build/test/initializer_test: Skip
+build/test/initializer_from_test: Skip
 build/test/initializer_parts_test: Skip
 build/test/initializer_super_test: Skip
+build/test/initializer_test: Skip
 build/test/initializer_type_filter_test: Skip
 build/test/init_method_test: Skip
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bb8b00..624f0eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 0.6.0
+
+* Added the `from` option to `run`. This should be a `Uri` pointing to a library
+in the mirror system, and throws if not in mirrors mode. This can be used to
+run initializers in a custom order at development time.
+* This package no longer tries to handle initializing scripts found in html
+imports. If you need this feature please use `initWebComponents` from the
+`web_components` package.
+
 ## 0.5.1+8
 * Make sure to crawl the entire supertype chain for annotations, and run them
 in reverse order.
diff --git a/lib/initialize.dart b/lib/initialize.dart
index c5d07dd..0df98d9 100644
--- a/lib/initialize.dart
+++ b/lib/initialize.dart
@@ -12,12 +12,20 @@
 part 'src/initializer.dart';
 
 /// Top level function which crawls the dependency graph and runs initializers.
-/// If `typeFilter` and/or `customFilter` are supplied then only those types of
+/// If [typeFilter] and/or [customFilter] are supplied then only those types of
 /// annotations will be parsed. If both filters are supplied they are treated
 /// as an AND.
-Future run({List<Type> typeFilter, InitializerFilter customFilter}) {
+///
+/// If [from] is supplied then initializers will be found starting from the
+/// library at the supplied uri.
+///
+/// **Warning**: Do not use [from] directly in your code unless you are building
+/// a framework that will use a transformer to remove this argument later. This
+/// parameter is supported in Dartium, but [run] will throw if you use the
+/// argument after building an application with `pub build` or `pub serve`.
+Future run({List<Type> typeFilter, InitializerFilter customFilter, Uri from}) {
   return _runInitQueue(loader.loadInitializers(
-      typeFilter: typeFilter, customFilter: customFilter));
+      typeFilter: typeFilter, customFilter: customFilter, from: from));
 }
 
 Future _runInitQueue(Queue<Function> initializers) {
diff --git a/lib/src/mirror_loader.dart b/lib/src/mirror_loader.dart
index c847215..46ac819 100644
--- a/lib/src/mirror_loader.dart
+++ b/lib/src/mirror_loader.dart
@@ -11,8 +11,8 @@
 final _root = currentMirrorSystem().isolate.rootLibrary;
 
 Queue<Function> loadInitializers(
-    {List<Type> typeFilter, InitializerFilter customFilter}) {
-  return new InitializationCrawler(typeFilter, customFilter).run();
+    {List<Type> typeFilter, InitializerFilter customFilter, Uri from}) {
+  return new InitializationCrawler(typeFilter, customFilter, from: from).run();
 }
 
 // Crawls a library and all its dependencies for `Initializer` annotations using
@@ -30,7 +30,17 @@
   // function will be processed.
   final InitializerFilter customFilter;
 
-  InitializationCrawler(this.typeFilter, this.customFilter);
+  /// The library to start crawling from.
+  final LibraryMirror _rootLibrary;
+
+  /// Note: The [from] argument is only supported in the mirror_loader.dart. It
+  /// is not supported statically.
+  InitializationCrawler(this.typeFilter, this.customFilter, {Uri from})
+      : _rootLibrary = from == null
+          ? _root
+          : currentMirrorSystem().libraries[from] {
+    if (_rootLibrary == null) throw 'Unable to find library at $from.';
+  }
 
   // The primary function in this class, invoke it to crawl and collect all the
   // annotations into a queue of init functions.
@@ -39,38 +49,7 @@
     var queue = new Queue<Function>();
     var libraries = currentMirrorSystem().libraries;
 
-    var trampolineUri = Uri.parse('${_root.uri}\$trampoline');
-    if (libraries.containsKey(trampolineUri)) {
-      // In dartium, process all relative libraries in reverse order of when
-      // they were seen.
-      // TODO(jakemac): This is an approximation of what we actually want.
-      // https://github.com/dart-lang/initialize/issues/25
-      var relativeLibraryUris = new List.from(libraries.keys
-          .where((uri) => uri.scheme != 'package' && uri.scheme != 'dart'));
-
-      for (var import in relativeLibraryUris.reversed) {
-        // Always load the package: version of a library if available for
-        // canonicalization purposes.
-        var libToRun;
-        if (_isHttpStylePackageUrl(import)) {
-          var packageUri = _packageUriFor(import);
-          libToRun = libraries[packageUri];
-        }
-        if (libToRun == null) libToRun = libraries[import];
-
-        // Dartium creates an extra trampoline lib that loads the main dart script
-        // and breaks our ordering, we should skip it.
-        if (librariesSeen.contains(libToRun) ||
-            libToRun.uri.path.endsWith('\$trampoline')) {
-          continue;
-        }
-        _readLibraryDeclarations(libToRun, librariesSeen, queue);
-      }
-    } else {
-      // Not in dartium, just process from the root library.
-      _readLibraryDeclarations(_root, librariesSeen, queue);
-    }
-
+    _readLibraryDeclarations(_rootLibrary, librariesSeen, queue);
     return queue;
   }
 
diff --git a/lib/src/static_loader.dart b/lib/src/static_loader.dart
index 11980fa..edc679b 100644
--- a/lib/src/static_loader.dart
+++ b/lib/src/static_loader.dart
@@ -24,7 +24,10 @@
 /// Returns initializer functions matching the supplied filters and removes them
 /// from `initializers` so they won't be ran again.
 Queue<Function> loadInitializers(
-    {List<Type> typeFilter, InitializerFilter customFilter}) {
+    {List<Type> typeFilter, InitializerFilter customFilter, Uri from}) {
+  if (from != null) {
+    throw 'The `from` option is not supported in deploy mode.';
+  }
   Queue<Function> result = new Queue<Function>();
 
   var matchesFilters = (initializer) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 8d9c88d..eb5e50c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: initialize
-version: 0.5.1+8
+version: 0.6.0
 author: Polymer.dart Authors <web@dartlang.org>
 description: Generic building blocks for doing static initialization.
 homepage: https://github.com/dart-lang/initialize
@@ -25,6 +25,7 @@
     entry_points:
       - test/deferred_library_test.dart
       - test/initializer_test.dart
+      - test/initializer_from_test.dart
       - test/initializer_parts_test.dart
       - test/initializer_super_test.dart
       - test/initializer_cycle_error_test.dart
diff --git a/test/initializer_from_test.dart b/test/initializer_from_test.dart
new file mode 100644
index 0000000..30587f5
--- /dev/null
+++ b/test/initializer_from_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+@initializeTracker
+library initialize.test.initializer_from_test;
+
+import 'package:initialize/src/initialize_tracker.dart';
+import 'package:initialize/initialize.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/compact_vm_config.dart';
+import 'package:test_package/bar.dart'; // Used for annotations
+
+main() {
+  useCompactVMConfiguration();
+
+  test('The `from` option', () {
+    var expectedNames = [];
+    return run(from: Uri.parse('package:test_package/bar.dart')).then((_) {
+      // First just run on the test packages bar.dart file.
+      expectedNames.add(const LibraryIdentifier(
+          #test_package.bar, 'test_package', 'bar.dart'));
+      expect(InitializeTracker.seen, expectedNames);
+    }).then((_) => run()).then((_) {
+      // Now we run on the rest (just this file).
+      expectedNames.add(const LibraryIdentifier(
+          #initialize.test.initializer_from_test, null,
+          'initializer_from_test.dart'));
+      expect(InitializeTracker.seen, expectedNames);
+    });
+  });
+}