Move global objects to Runtime

Move away global constants and global namespaces out of Environment
and into a new file Runtime.

--
MOS_MIGRATED_REVID=101940218
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index 635b1ed..75afd45 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -29,6 +29,7 @@
 import com.google.devtools.build.lib.syntax.EvalUtils;
 import com.google.devtools.build.lib.syntax.FuncallExpression;
 import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
 import com.google.devtools.build.lib.syntax.SkylarkList;
@@ -100,7 +101,7 @@
           + "value is given.";
 
   private static boolean containsNonNoneKey(Map<String, Object> arguments, String key) {
-    return arguments.containsKey(key) && arguments.get(key) != Environment.NONE;
+    return arguments.containsKey(key) && arguments.get(key) != Runtime.NONE;
   }
 
   private static Attribute.Builder<?> createAttribute(
@@ -160,7 +161,7 @@
     }
 
     Object ruleClassesObj = arguments.get(ALLOW_RULES_ARG);
-    if (ruleClassesObj != null && ruleClassesObj != Environment.NONE) {
+    if (ruleClassesObj != null && ruleClassesObj != Runtime.NONE) {
       builder.allowedRuleClasses(
           castList(ruleClassesObj, String.class, "allowed rule classes for attribute definition"));
     }
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 df4876c..c52c58c 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
@@ -16,38 +16,27 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.packages.SkylarkNativeModule;
-import com.google.devtools.build.lib.syntax.BaseFunction;
 import com.google.devtools.build.lib.syntax.Environment;
 import com.google.devtools.build.lib.syntax.EvaluationContext;
 import com.google.devtools.build.lib.syntax.MethodLibrary;
+import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
-import com.google.devtools.build.lib.syntax.SkylarkModule;
-import com.google.devtools.build.lib.syntax.SkylarkSignature;
 import com.google.devtools.build.lib.syntax.ValidationEnvironment;
 
-import java.lang.reflect.Field;
-import java.util.Map;
-
 /**
- * A class to handle all Skylark modules, to create and setup Validation and regular Environments.
+ * The basis for a Skylark Environment with all build-related modules registered.
  */
-// TODO(bazel-team): move that to the syntax package and
-// let each extension register itself in a static { } statement.
-public class SkylarkModules {
+public final class SkylarkModules {
+
+  private SkylarkModules() { }
 
   /**
    * The list of built in Skylark modules.
    * Documentation is generated automatically for all these modules.
-   * They are also registered with the {@link ValidationEnvironment}
-   * and the {@link SkylarkEnvironment}.
-   * Note that only functions with a {@link SkylarkSignature} annotations are handled properly.
+   * They are also registered with the {@link Environment}.
    */
-  // TODO(bazel-team): find a more general, more automated way of registering classes and building
-  // initial environments. And don't give syntax.Environment and packages.MethodLibrary a special
-  // treatment, have them use the same registration mechanism as other classes currently below.
   public static final ImmutableList<Class<?>> MODULES = ImmutableList.of(
       SkylarkAttr.class,
       SkylarkCommandLine.class,
@@ -55,30 +44,6 @@
       SkylarkRuleClassFunctions.class,
       SkylarkRuleImplementationFunctions.class);
 
-  private static final ImmutableMap<Class<?>, ImmutableList<BaseFunction>> FUNCTION_MAP;
-  private static final ImmutableMap<String, Object> OBJECTS;
-
-  static {
-    try {
-      ImmutableMap.Builder<Class<?>, ImmutableList<BaseFunction>> functionMap =
-          ImmutableMap.builder();
-      ImmutableMap.Builder<String, Object> objects = ImmutableMap.builder();
-      for (Class<?> moduleClass : MODULES) {
-        if (moduleClass.isAnnotationPresent(SkylarkModule.class)) {
-          objects.put(moduleClass.getAnnotation(SkylarkModule.class).name(),
-              moduleClass.newInstance());
-        }
-        ImmutableList.Builder<BaseFunction> functions = ImmutableList.builder();
-        collectSkylarkFunctionsAndObjectsFromFields(moduleClass, functions, objects);
-        functionMap.put(moduleClass, functions.build());
-      }
-      FUNCTION_MAP = functionMap.build();
-      OBJECTS = objects.build();
-    } catch (InstantiationException | IllegalAccessException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
   /**
    * Returns a new SkylarkEnvironment with the elements of the Skylark modules.
    */
@@ -96,21 +61,12 @@
 
   private static void setupEnvironment(Environment env) {
     MethodLibrary.setupMethodEnvironment(env);
-    for (Map.Entry<Class<?>, ImmutableList<BaseFunction>> entry : FUNCTION_MAP.entrySet()) {
-      for (BaseFunction function : entry.getValue()) {
-        if (function.getObjectType() != null) {
-          env.registerFunction(function.getObjectType(), function.getName(), function);
-        } else {
-          env.update(function.getName(), function);
-        }
-      }
-    }
-    for (Map.Entry<String, Object> entry : OBJECTS.entrySet()) {
-      env.update(entry.getKey(), entry.getValue());
+    for (Class<?> moduleClass : MODULES) {
+      Runtime.registerModuleGlobals(env, moduleClass);
     }
     // Even though PACKAGE_NAME has no value _now_ and will be bound later,
     // it needs to be visible for the ValidationEnvironment to be happy.
-    env.update(Environment.PKG_NAME, Environment.NONE);
+    env.update(Runtime.PKG_NAME, Runtime.NONE);
   }
 
   /**
@@ -125,31 +81,4 @@
     return EvaluationContext.newSkylarkContext(
         getNewEnvironment(eventHandler), getValidationEnvironment());
   }
-
-  /**
-   * Collects the BaseFunctions from the fields of the class of the object parameter
-   * and adds them into the builder.
-   */
-  private static void collectSkylarkFunctionsAndObjectsFromFields(Class<?> type,
-      ImmutableList.Builder<BaseFunction> functions, ImmutableMap.Builder<String, Object> objects) {
-    try {
-      for (Field field : type.getDeclaredFields()) {
-        if (field.isAnnotationPresent(SkylarkSignature.class)) {
-          // Fields in Skylark modules are sometimes private.
-          // Nevertheless they have to be annotated with SkylarkSignature.
-          field.setAccessible(true);
-          SkylarkSignature annotation = field.getAnnotation(SkylarkSignature.class);
-          Object value = field.get(null);
-          if (BaseFunction.class.isAssignableFrom(field.getType())) {
-            functions.add((BaseFunction) value);
-          } else {
-            objects.put(annotation.name(), value);
-          }
-        }
-      }
-    } catch (IllegalArgumentException | IllegalAccessException e) {
-      // This should never happen.
-      throw new RuntimeException(e);
-    }
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index 1ca229c..4c070b4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -68,6 +68,7 @@
 import com.google.devtools.build.lib.syntax.FuncallExpression;
 import com.google.devtools.build.lib.syntax.FunctionSignature;
 import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction;
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
 import com.google.devtools.build.lib.syntax.SkylarkList;
@@ -250,7 +251,7 @@
         // We'll set the name later, pass the empty string for now.
         RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent);
 
-        if (attrs != Environment.NONE) {
+        if (attrs != Runtime.NONE) {
           for (Map.Entry<String, Attribute.Builder> attr : castMap(
               attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) {
             Attribute.Builder<?> attrBuilder = (Attribute.Builder<?>) attr.getValue();
@@ -267,7 +268,7 @@
           builder.setOutputsDefaultExecutable();
         }
 
-        if (implicitOutputs != Environment.NONE) {
+        if (implicitOutputs != Runtime.NONE) {
           if (implicitOutputs instanceof BaseFunction) {
             BaseFunction func = (BaseFunction) implicitOutputs;
             final SkylarkCallbackFunction callback =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
index a7c9b4f..409b408 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleConfiguredTargetBuilder.java
@@ -34,10 +34,10 @@
 import com.google.devtools.build.lib.syntax.BaseFunction;
 import com.google.devtools.build.lib.syntax.ClassObject;
 import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
-import com.google.devtools.build.lib.syntax.Environment;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalExceptionWithStackTrace;
 import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
 import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 import com.google.devtools.build.lib.syntax.SkylarkType;
@@ -64,7 +64,7 @@
 
       if (ruleContext.hasErrors()) {
         return null;
-      } else if (!(target instanceof SkylarkClassObject) && target != Environment.NONE) {
+      } else if (!(target instanceof SkylarkClassObject) && target != Runtime.NONE) {
         ruleContext.ruleError("Rule implementation doesn't return a struct");
         return null;
       } else if (!expectFailure.isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index dbaf2c8..bf11515 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -44,10 +44,10 @@
 import com.google.devtools.build.lib.shell.ShellUtils;
 import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException;
 import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
-import com.google.devtools.build.lib.syntax.Environment;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.FuncallExpression.FuncallException;
 import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkCallable;
 import com.google.devtools.build.lib.syntax.SkylarkList;
 import com.google.devtools.build.lib.syntax.SkylarkModule;
@@ -159,7 +159,7 @@
         if (artifacts.size() == 1) {
           addOutput(outputsBuilder, attrName, Iterables.getOnlyElement(artifacts));
         } else {
-          addOutput(outputsBuilder, attrName, Environment.NONE);
+          addOutput(outputsBuilder, attrName, Runtime.NONE);
         }
       } else if (type == Type.OUTPUT_LIST) {
         addOutput(outputsBuilder, attrName,
@@ -182,7 +182,7 @@
       Type<?> type = a.getType();
       Object val = ruleContext.attributes().get(a.getName(), type);
       if (type != Type.LABEL && type != Type.LABEL_LIST) {
-        attrBuilder.put(a.getPublicName(), val == null ? Environment.NONE
+        attrBuilder.put(a.getPublicName(), val == null ? Runtime.NONE
             // Attribute values should be type safe
             : SkylarkType.convertToSkylark(val, null));
         continue;
@@ -197,7 +197,7 @@
           executableBuilder.put(skyname, executable);
           executableRunfilesbuilder.put(executable, provider);
         } else {
-          executableBuilder.put(skyname, Environment.NONE);
+          executableBuilder.put(skyname, Runtime.NONE);
         }
       }
       if (a.isSingleArtifact()) {
@@ -206,7 +206,7 @@
         if (artifact != null) {
           fileBuilder.put(skyname, artifact);
         } else {
-          fileBuilder.put(skyname, Environment.NONE);
+          fileBuilder.put(skyname, Runtime.NONE);
         }
       }
       filesBuilder.put(skyname, ruleContext.getPrerequisiteArtifacts(a.getName(), mode).list());
@@ -214,7 +214,7 @@
       if (type == Type.LABEL) {
         Object prereq = ruleContext.getPrerequisite(a.getName(), mode);
         if (prereq == null) {
-          prereq = Environment.NONE;
+          prereq = Runtime.NONE;
         }
         attrBuilder.put(skyname, prereq);
       } else {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
index fb53cfd..b6417d4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleImplementationFunctions.java
@@ -47,10 +47,10 @@
 import com.google.devtools.build.lib.packages.Type.ConversionException;
 import com.google.devtools.build.lib.syntax.BuiltinFunction;
 import com.google.devtools.build.lib.syntax.Environment;
-import com.google.devtools.build.lib.syntax.Environment.NoneType;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.EvalUtils;
 import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.Runtime;
 import com.google.devtools.build.lib.syntax.SkylarkList;
 import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
 import com.google.devtools.build.lib.syntax.SkylarkSignature;
@@ -90,7 +90,7 @@
       doc = "Creates an action that runs an executable or a shell command. You must specify either "
         + "<code>command</code> or <code>executable</code>.",
       objectType = SkylarkRuleContext.class,
-      returnType = Environment.NoneType.class,
+      returnType = Runtime.NoneType.class,
       mandatoryPositionals = {
         @Param(name = "self", type = SkylarkRuleContext.class, doc = "This RuleContext.")},
       mandatoryNamedOnly = {
@@ -128,7 +128,7 @@
             + "they are typicially generated by the command_helper")},
       useLocation = true)
   private static final BuiltinFunction createSpawnAction = new BuiltinFunction("action") {
-    public Environment.NoneType invoke(
+    public Runtime.NoneType invoke(
         SkylarkRuleContext ctx,
         SkylarkList outputs,
         SkylarkList inputs,
@@ -144,7 +144,7 @@
         Location loc) throws EvalException, ConversionException {
       SpawnAction.Builder builder = new SpawnAction.Builder();
       // TODO(bazel-team): builder still makes unnecessary copies of inputs, outputs and args.
-      boolean hasCommand = commandO != Environment.NONE;
+      boolean hasCommand = commandO != Runtime.NONE;
       Iterable<Artifact> actualInputs = castList(inputs, Artifact.class);
 
       builder.addInputs(actualInputs);
@@ -157,7 +157,7 @@
         builder.addArgument("");
       }
       builder.addArguments(castList(arguments, String.class));
-      if (executableO != Environment.NONE) {
+      if (executableO != Runtime.NONE) {
         if (executableO instanceof Artifact) {
           Artifact executable = (Artifact) executableO;
           builder.addInput(executable);
@@ -174,7 +174,7 @@
               + "executable but got " + EvalUtils.getDataTypeName(executableO) + " instead");
         }
       }
-      if ((commandO == Environment.NONE) == (executableO == Environment.NONE)) {
+      if ((commandO == Runtime.NONE) == (executableO == Runtime.NONE)) {
         throw new EvalException(loc, "You must specify either 'command' or 'executable' argument");
       }
       if (hasCommand) {
@@ -196,24 +196,24 @@
         // HOST configuration to the action as a precaution.
         addRequiredIndirectRunfiles(ctx, builder);
       }
-      if (mnemonicO != Environment.NONE) {
+      if (mnemonicO != Runtime.NONE) {
         builder.setMnemonic((String) mnemonicO);
       }
-      if (envO != Environment.NONE) {
+      if (envO != Runtime.NONE) {
         builder.setEnvironment(ImmutableMap.copyOf(
             castMap(envO, String.class, String.class, "env")));
       }
-      if (progressMessage != Environment.NONE) {
+      if (progressMessage != Runtime.NONE) {
         builder.setProgressMessage((String) progressMessage);
       }
       if (EvalUtils.toBoolean(useDefaultShellEnv)) {
         builder.useDefaultShellEnvironment();
       }
-      if (executionRequirementsO != Environment.NONE) {
+      if (executionRequirementsO != Runtime.NONE) {
         builder.setExecutionInfo(ImmutableMap.copyOf(castMap(
             executionRequirementsO, String.class, String.class, "execution_requirements")));
       }
-      if (inputManifestsO != Environment.NONE) {
+      if (inputManifestsO != Runtime.NONE) {
         for (Map.Entry<PathFragment, Artifact> entry : castMap(inputManifestsO,
             PathFragment.class, Artifact.class, "input manifest file map").entrySet()) {
           builder.addInputManifest(entry.getValue(), entry.getKey());
@@ -221,7 +221,7 @@
       }
       // Always register the action
       ctx.getRuleContext().registerAction(builder.build(ctx.getRuleContext()));
-      return Environment.NONE;
+      return Runtime.NONE;
     }
   };
 
@@ -322,7 +322,7 @@
       doc =
       "Creates an empty action that neither executes a command nor produces any "
       + "output, but that is useful for inserting 'extra actions'.",
-      objectType = SkylarkRuleContext.class, returnType = NoneType.class,
+      objectType = SkylarkRuleContext.class, returnType = Runtime.NoneType.class,
       mandatoryPositionals = {
           @Param(name = "self", type = SkylarkRuleContext.class, doc = "this context"),
       },
@@ -336,7 +336,7 @@
       })
   private static final BuiltinFunction createEmptyAction = new BuiltinFunction("empty_action") {
     @SuppressWarnings("unused")
-    public NoneType invoke(SkylarkRuleContext ctx, String mnemonic, SkylarkList inputs)
+    public Runtime.NoneType invoke(SkylarkRuleContext ctx, String mnemonic, SkylarkList inputs)
         throws EvalException, ConversionException {
       RuleContext ruleContext = ctx.getRuleContext();
       Action action = new PseudoAction<SpawnInfo>(generateUuid(ruleContext),
@@ -344,7 +344,7 @@
           mnemonic, SpawnInfo.spawnInfo, createEmptySpawnInfo());
       ruleContext.registerAction(action);
 
-      return Environment.NONE;
+      return Runtime.NONE;
     }
 
     private NestedSet<Artifact> convertInputs(SkylarkList inputs) {
@@ -436,7 +436,7 @@
         Class<? extends TransitiveInfoProvider> convertedClass =
             classType.asSubclass(TransitiveInfoProvider.class);
         Object result = target.getProvider(convertedClass);
-        return result == null ? Environment.NONE : result;
+        return result == null ? Runtime.NONE : result;
       } catch (ExecutionException e) {
         throw new EvalException(loc, "Unknown class type " + type);
       } catch (ClassCastException e) {
@@ -482,7 +482,7 @@
       if (!files.isEmpty()) {
         builder.addArtifacts(castList(files, Artifact.class));
       }
-      if (transitiveFiles != Environment.NONE) {
+      if (transitiveFiles != Runtime.NONE) {
         builder.addTransitiveArtifacts(((SkylarkNestedSet) transitiveFiles).getSet(Artifact.class));
       }
       return builder.build();