Update from Google.

--
MOE_MIGRATED_REVID=85702957
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
new file mode 100644
index 0000000..e84f9aa
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -0,0 +1,376 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.analysis;
+
+import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.ABSTRACT;
+import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.TEST;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
+import com.google.devtools.build.lib.analysis.config.DefaultsPackage;
+import com.google.devtools.build.lib.analysis.config.FragmentOptions;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.graph.Digraph;
+import com.google.devtools.build.lib.graph.Node;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClassProvider;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.rules.SkylarkModules;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
+import com.google.devtools.build.lib.syntax.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkType;
+import com.google.devtools.build.lib.syntax.ValidationEnvironment;
+import com.google.devtools.common.options.OptionsClassProvider;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Knows about every rule Blaze supports and the associated configuration options.
+ *
+ * <p>This class is initialized on server startup and the set of rules, build info factories
+ * and configuration options is guarantees not to change over the life time of the Blaze server.
+ */
+public class ConfiguredRuleClassProvider implements RuleClassProvider {
+  /**
+   * Custom dependency validation logic.
+   */
+  public static interface PrerequisiteValidator {
+    /**
+     * Checks whether the rule in {@code contextBuilder} is allowed to depend on
+     * {@code prerequisite} through the attribute {@code attribute}.
+     *
+     * <p>Can be used for enforcing any organization-specific policies about the layout of the
+     * workspace.
+     */
+    void validate(
+        RuleContext.Builder contextBuilder, ConfiguredTarget prerequisite, Attribute attribute);
+  }
+
+  /**
+   * Builder for {@link ConfiguredRuleClassProvider}.
+   */
+  public static class Builder implements RuleDefinitionEnvironment {
+    private final List<ConfigurationFragmentFactory> configurationFragments = new ArrayList<>();
+    private final List<BuildInfoFactory> buildInfoFactories = new ArrayList<>();
+    private final List<Class<? extends FragmentOptions>> configurationOptions = new ArrayList<>();
+
+    private final Map<String, RuleClass> ruleClassMap = new HashMap<>();
+    private final  Map<String, Class<? extends RuleDefinition>> ruleDefinitionMap =
+        new HashMap<>();
+    private final Map<Class<? extends RuleDefinition>, RuleClass> ruleMap = new HashMap<>();
+    private final Digraph<Class<? extends RuleDefinition>> dependencyGraph =
+        new Digraph<>();
+    private ConfigurationCollectionFactory configurationCollectionFactory;
+    private PrerequisiteValidator prerequisiteValidator;
+    private ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses = ImmutableMap.of();
+
+    public Builder setPrerequisiteValidator(PrerequisiteValidator prerequisiteValidator) {
+      this.prerequisiteValidator = prerequisiteValidator;
+      return this;
+    }
+
+    public Builder addBuildInfoFactory(BuildInfoFactory factory) {
+      buildInfoFactories.add(factory);
+      return this;
+    }
+
+    public Builder addRuleDefinition(Class<? extends RuleDefinition> ruleDefinition) {
+      dependencyGraph.createNode(ruleDefinition);
+      BlazeRule annotation = ruleDefinition.getAnnotation(BlazeRule.class);
+      for (Class<? extends RuleDefinition> ancestor : annotation.ancestors()) {
+        dependencyGraph.addEdge(ancestor, ruleDefinition);
+      }
+
+      return this;
+    }
+
+    public Builder addConfigurationOptions(Class<? extends FragmentOptions> configurationOptions) {
+      this.configurationOptions.add(configurationOptions);
+      return this;
+    }
+
+    public Builder addConfigurationFragment(ConfigurationFragmentFactory factory) {
+      configurationFragments.add(factory);
+      return this;
+    }
+
+    public Builder setConfigurationCollectionFactory(ConfigurationCollectionFactory factory) {
+      this.configurationCollectionFactory = factory;
+      return this;
+    }
+
+    public Builder setSkylarkAccessibleJavaClasses(ImmutableMap<String, SkylarkType> objects) {
+      this.skylarkAccessibleJavaClasses = objects;
+      return this;
+    }
+
+    private RuleConfiguredTargetFactory createFactory(
+        Class<? extends RuleConfiguredTargetFactory> factoryClass) {
+      try {
+        Constructor<? extends RuleConfiguredTargetFactory> ctor = factoryClass.getConstructor();
+        return ctor.newInstance();
+      } catch (NoSuchMethodException | IllegalAccessException | InstantiationException
+          | InvocationTargetException e) {
+        throw new IllegalStateException(e);
+      }
+    }
+
+    private RuleClass commitRuleDefinition(Class<? extends RuleDefinition> definitionClass) {
+      BlazeRule annotation = definitionClass.getAnnotation(BlazeRule.class);
+      Preconditions.checkArgument(ruleClassMap.get(annotation.name()) == null, annotation.name());
+
+      Preconditions.checkArgument(
+          annotation.type() == ABSTRACT ^
+          annotation.factoryClass() != RuleConfiguredTargetFactory.class);
+      Preconditions.checkArgument(
+          (annotation.type() != TEST) ||
+          Arrays.asList(annotation.ancestors()).contains(
+              BaseRuleClasses.TestBaseRule.class));
+
+      RuleDefinition instance;
+      try {
+        instance = definitionClass.newInstance();
+      } catch (IllegalAccessException | InstantiationException e) {
+        throw new IllegalStateException(e);
+      }
+      RuleClass[] ancestorClasses = new RuleClass[annotation.ancestors().length];
+      for (int i = 0; i < annotation.ancestors().length; i++) {
+        ancestorClasses[i] = ruleMap.get(annotation.ancestors()[i]);
+        if (ancestorClasses[i] == null) {
+          // Ancestors should have been initialized by now
+          throw new IllegalStateException("Ancestor " + annotation.ancestors()[i] + " of "
+              + annotation.name() + " is not initialized");
+        }
+      }
+
+      RuleConfiguredTargetFactory factory = null;
+      if (annotation.type() != ABSTRACT) {
+        factory = createFactory(annotation.factoryClass());
+      }
+
+      RuleClass.Builder builder = new RuleClass.Builder(
+          annotation.name(), annotation.type(), false, ancestorClasses);
+      builder.factory(factory);
+      RuleClass ruleClass = instance.build(builder, this);
+      ruleMap.put(definitionClass, ruleClass);
+      ruleClassMap.put(ruleClass.getName(), ruleClass);
+      ruleDefinitionMap.put(ruleClass.getName(), definitionClass);
+
+      return ruleClass;
+    }
+
+    public ConfiguredRuleClassProvider build() {
+      for (Node<Class<? extends RuleDefinition>> ruleDefinition :
+        dependencyGraph.getTopologicalOrder()) {
+        commitRuleDefinition(ruleDefinition.getLabel());
+      }
+
+      return new ConfiguredRuleClassProvider(
+          ImmutableMap.copyOf(ruleClassMap),
+          ImmutableMap.copyOf(ruleDefinitionMap),
+          ImmutableList.copyOf(buildInfoFactories),
+          ImmutableList.copyOf(configurationOptions),
+          ImmutableList.copyOf(configurationFragments),
+          configurationCollectionFactory,
+          prerequisiteValidator,
+          skylarkAccessibleJavaClasses);
+    }
+
+    @Override
+    public Label getLabel(String labelValue) {
+      return LABELS.getUnchecked(labelValue);
+    }
+  }
+
+  /**
+   * Used to make the label instances unique, so that we don't create a new
+   * instance for every rule.
+   */
+  private static LoadingCache<String, Label> LABELS = CacheBuilder.newBuilder().build(
+      new CacheLoader<String, Label>() {
+    @Override
+    public Label load(String from) {
+      try {
+        return Label.parseAbsolute(from);
+      } catch (Label.SyntaxException e) {
+        throw new IllegalArgumentException(from);
+      }
+    }
+  });
+
+  /**
+   * Maps rule class name to the metaclass instance for that rule.
+   */
+  private final ImmutableMap<String, RuleClass> ruleClassMap;
+
+  /**
+   * Maps rule class name to the rule definition metaclasses.
+   */
+  private final ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap;
+
+  /**
+   * The configuration options that affect the behavior of the rules.
+   */
+  private final ImmutableList<Class<? extends FragmentOptions>> configurationOptions;
+
+  /**
+   * The set of configuration fragment factories.
+   */
+  private final ImmutableList<ConfigurationFragmentFactory> configurationFragments;
+
+  /**
+   * The factory that creates the configuration collection.
+   */
+  private final ConfigurationCollectionFactory configurationCollectionFactory;
+
+  private final ImmutableList<BuildInfoFactory> buildInfoFactories;
+
+  private final PrerequisiteValidator prerequisiteValidator;
+
+  private final ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses;
+
+  private final ValidationEnvironment skylarkValidationEnvironment;
+
+  public ConfiguredRuleClassProvider(
+      ImmutableMap<String, RuleClass> ruleClassMap,
+      ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap,
+      ImmutableList<BuildInfoFactory> buildInfoFactories,
+      ImmutableList<Class<? extends FragmentOptions>> configurationOptions,
+      ImmutableList<ConfigurationFragmentFactory> configurationFragments,
+      ConfigurationCollectionFactory configurationCollectionFactory,
+      PrerequisiteValidator prerequisiteValidator,
+      ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses) {
+
+    this.ruleClassMap = ruleClassMap;
+    this.ruleDefinitionMap = ruleDefinitionMap;
+    this.buildInfoFactories = buildInfoFactories;
+    this.configurationOptions = configurationOptions;
+    this.configurationFragments = configurationFragments;
+    this.configurationCollectionFactory = configurationCollectionFactory;
+    this.prerequisiteValidator = prerequisiteValidator;
+    this.skylarkAccessibleJavaClasses = skylarkAccessibleJavaClasses;
+    this.skylarkValidationEnvironment = SkylarkModules.getValidationEnvironment(
+        ImmutableMap.<String, SkylarkType>builder()
+            .putAll(skylarkAccessibleJavaClasses)
+            .put("native", SkylarkType.of(NativeModule.class))
+            .build());
+  }
+
+  public PrerequisiteValidator getPrerequisiteValidator() {
+    return prerequisiteValidator;
+  }
+
+  @Override
+  public Map<String, RuleClass> getRuleClassMap() {
+    return ruleClassMap;
+  }
+
+  /**
+   * Returns a list of build info factories that are needed for the supported languages.
+   */
+  public ImmutableList<BuildInfoFactory> getBuildInfoFactories() {
+    return buildInfoFactories;
+  }
+
+  /**
+   * Returns the set of configuration fragments provided by this module.
+   */
+  public ImmutableList<ConfigurationFragmentFactory> getConfigurationFragments() {
+    return configurationFragments;
+  }
+
+  /**
+   * Returns the set of configuration options that are supported in this module.
+   */
+  public ImmutableList<Class<? extends FragmentOptions>> getConfigurationOptions() {
+    return configurationOptions;
+  }
+
+  /**
+   * Returns the definition of the rule class definition with the specified name.
+   */
+  public Class<? extends RuleDefinition> getRuleClassDefinition(String ruleClassName) {
+    return ruleDefinitionMap.get(ruleClassName);
+  }
+
+  /**
+   * Returns the configuration collection creator.
+   */
+  public ConfigurationCollectionFactory getConfigurationCollectionFactory() {
+    return configurationCollectionFactory;
+  }
+
+  /**
+   * Returns the defaults package for the default settings.
+   */
+  public String getDefaultsPackageContent() {
+    return DefaultsPackage.getDefaultsPackageContent(configurationOptions);
+  }
+
+  /**
+   * Returns the defaults package for the given options taken from an optionsProvider.
+   */
+  public String getDefaultsPackageContent(OptionsClassProvider optionsProvider) {
+    return DefaultsPackage.getDefaultsPackageContent(
+        BuildOptions.of(configurationOptions, optionsProvider));
+  }
+
+  /**
+   * Creates a BuildOptions class for the given options taken from an optionsProvider.
+   */
+  public BuildOptions createBuildOptions(OptionsClassProvider optionsProvider) {
+    return BuildOptions.of(configurationOptions, optionsProvider);
+  }
+
+  @SkylarkModule(name = "native", namespace = true, onlyLoadingPhase = true,
+      doc = "Module for native rules.")
+  private static final class NativeModule {}
+
+  public static final NativeModule nativeModule = new NativeModule();
+
+  @Override
+  public SkylarkEnvironment createSkylarkRuleClassEnvironment(
+      EventHandler eventHandler, String astFileContentHashCode) {
+    SkylarkEnvironment env = SkylarkModules.getNewEnvironment(eventHandler, astFileContentHashCode);
+    for (Map.Entry<String, SkylarkType> entry : skylarkAccessibleJavaClasses.entrySet()) {
+      env.update(entry.getKey(), entry.getValue().getType());
+    }
+    return env;
+  }
+
+  @Override
+  public ValidationEnvironment getSkylarkValidationEnvironment() {
+    return skylarkValidationEnvironment;
+  }
+
+  @Override
+  public Object getNativeModule() {
+    return nativeModule;
+  }
+}