Enable injection of Skylark modules through the RuleClassProvider

This enable BlazeModule to specify extraneous Skylark modules. This
will be used by Skylark remote repositories to add them from the
BazelRepositoryModule.

Issue #893, step 2 of the roadmap of http://goo.gl/OZV3o0

--
MOS_MIGRATED_REVID=114677157
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 62ab8a6..798b14d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -104,6 +104,8 @@
     private Class<? extends BuildConfiguration.Fragment> universalFragment;
     private PrerequisiteValidator prerequisiteValidator;
     private ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses = ImmutableMap.of();
+    private ImmutableList.Builder<Class<?>> skylarkModules =
+        ImmutableList.<Class<?>>builder().addAll(SkylarkModules.MODULES);
     private final List<Class<? extends FragmentOptions>> buildOptions = Lists.newArrayList();
 
     public void addWorkspaceFile(String contents) {
@@ -190,6 +192,11 @@
       return this;
     }
 
+    public Builder addSkylarkModule(Class<?>... modules) {
+      this.skylarkModules.add(modules);
+      return this;
+    }
+
     private RuleConfiguredTargetFactory createFactory(
         Class<? extends RuleConfiguredTargetFactory> factoryClass) {
       try {
@@ -264,6 +271,7 @@
           universalFragment,
           prerequisiteValidator,
           skylarkAccessibleJavaClasses,
+          skylarkModules.build(),
           buildOptions);
     }
 
@@ -374,6 +382,7 @@
       Class<? extends BuildConfiguration.Fragment> universalFragment,
       PrerequisiteValidator prerequisiteValidator,
       ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses,
+      ImmutableList<Class<?>> skylarkModules,
       List<Class<? extends FragmentOptions>> buildOptions) {
     this.preludeLabel = preludeLabel;
     this.runfilesPrefix = runfilesPrefix;
@@ -388,7 +397,7 @@
     this.configurationCollectionFactory = configurationCollectionFactory;
     this.universalFragment = universalFragment;
     this.prerequisiteValidator = prerequisiteValidator;
-    this.globals = createGlobals(skylarkAccessibleJavaClasses);
+    this.globals = createGlobals(skylarkAccessibleJavaClasses, skylarkModules);
     this.buildOptions = buildOptions;
   }
 
@@ -491,10 +500,11 @@
   }
 
   private Environment.Frame createGlobals(
-      ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses) {
+      ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses,
+      ImmutableList<Class<?>> modules) {
     try (Mutability mutability = Mutability.create("ConfiguredRuleClassProvider globals")) {
       Environment env = createSkylarkRuleClassEnvironment(
-          mutability, SkylarkModules.GLOBALS, null, null, null);
+          mutability, SkylarkModules.getGlobals(modules), null, null, null);
       for (Map.Entry<String, SkylarkType> entry : skylarkAccessibleJavaClasses.entrySet()) {
         env.setup(entry.getKey(), entry.getValue().getType());
       }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
index 08487f8..ef2767b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkModules.java
@@ -17,9 +17,14 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.packages.SkylarkNativeModule;
 import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.Environment.Frame;
 import com.google.devtools.build.lib.syntax.Mutability;
 import com.google.devtools.build.lib.syntax.Runtime;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * The basis for a Skylark Environment with all build-related modules registered.
  */
@@ -40,15 +45,22 @@
       SkylarkRuleImplementationFunctions.class);
 
   /** Global bindings for all Skylark modules */
-  public static final Environment.Frame GLOBALS = createGlobals();
+  private static final Map<List<Class<?>>, Frame> cache = new HashMap<>();
 
-  private static Environment.Frame createGlobals() {
+  public static Environment.Frame getGlobals(List<Class<?>> modules) {
+    if (!cache.containsKey(modules)) {
+      cache.put(modules, createGlobals(modules));
+    }
+    return cache.get(modules);
+  }
+
+  private static Environment.Frame createGlobals(List<Class<?>> modules) {
     try (Mutability mutability = Mutability.create("SkylarkModules")) {
       Environment env = Environment.builder(mutability)
           .setSkylark()
           .setGlobals(Environment.SKYLARK)
           .build();
-      for (Class<?> moduleClass : MODULES) {
+      for (Class<?> moduleClass : modules) {
         Runtime.registerModuleGlobals(env, moduleClass);
       }
       return env.getGlobals();