Move several parts of BlazeRuntime to CommandEnvironment.

The main piece is the blaze module environment, which is only valid during
command execution. Also configuration creation and precompleteCommand.

--
MOS_MIGRATED_REVID=103186467
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
index 2bdc36b..1edd606 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
@@ -14,14 +14,26 @@
 
 package com.google.devtools.build.lib.runtime;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.actions.cache.ActionCache;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.BuildView;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
 import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.pkgcache.LoadedPackageProvider;
 import com.google.devtools.build.lib.pkgcache.PackageManager;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.util.AbruptExitException;
+import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.common.options.OptionsProvider;
 
 import java.io.IOException;
 import java.util.Map;
@@ -33,11 +45,34 @@
  */
 public final class CommandEnvironment {
   private final BlazeRuntime runtime;
+  private final Reporter reporter;
   private final EventBus eventBus;
+  private final BlazeModule.ModuleEnvironment blazeModuleEnvironment;
 
-  public CommandEnvironment(BlazeRuntime runtime, EventBus eventBus) {
+  private AbruptExitException pendingException;
+
+  private class BlazeModuleEnvironment implements BlazeModule.ModuleEnvironment {
+    @Override
+    public Path getFileFromDepot(Label label)
+        throws NoSuchThingException, InterruptedException, IOException {
+      Target target = getPackageManager().getTarget(reporter, label);
+      return (runtime.getOutputService() != null)
+          ? runtime.getOutputService().stageTool(target)
+          : target.getPackage().getPackageDirectory().getRelative(target.getName());
+    }
+
+    @Override
+    public void exit(AbruptExitException exception) {
+      Preconditions.checkState(pendingException == null);
+      pendingException = exception;
+    }
+  }
+
+  public CommandEnvironment(BlazeRuntime runtime, Reporter reporter, EventBus eventBus) {
     this.runtime = runtime;
+    this.reporter = reporter;
     this.eventBus = eventBus;
+    this.blazeModuleEnvironment = new BlazeModuleEnvironment();
   }
 
   public BlazeRuntime getRuntime() {
@@ -52,13 +87,17 @@
    * Returns the reporter for events.
    */
   public Reporter getReporter() {
-    return runtime.getReporter();
+    return reporter;
   }
 
   public EventBus getEventBus() {
     return eventBus;
   }
 
+  public BlazeModule.ModuleEnvironment getBlazeModuleEnvironment() {
+    return blazeModuleEnvironment;
+  }
+
   public Map<String, String> getClientEnv() {
     return runtime.getClientEnv();
   }
@@ -84,6 +123,53 @@
   }
 
   public ActionCache getPersistentActionCache() throws IOException {
-    return runtime.getPersistentActionCache(getReporter());
+    return runtime.getPersistentActionCache(reporter);
+  }
+
+  /**
+   * This method only exists for the benefit of InfoCommand, which needs to construct a {@link
+   * BuildConfigurationCollection} without running a full loading phase. Don't add any more clients;
+   * instead, we should change info so that it doesn't need the configuration.
+   */
+  public BuildConfigurationCollection getConfigurations(OptionsProvider optionsProvider)
+      throws InvalidConfigurationException, InterruptedException {
+    BuildOptions buildOptions = runtime.createBuildOptions(optionsProvider);
+    boolean keepGoing = optionsProvider.getOptions(BuildView.Options.class).keepGoing;
+    LoadedPackageProvider loadedPackageProvider =
+        runtime.getLoadingPhaseRunner().loadForConfigurations(reporter,
+            ImmutableSet.copyOf(buildOptions.getAllLabels().values()),
+            keepGoing);
+    if (loadedPackageProvider == null) {
+      throw new InvalidConfigurationException("Configuration creation failed");
+    }
+    return getSkyframeExecutor().createConfigurations(runtime.getConfigurationFactory(),
+        buildOptions, runtime.getDirectories(), ImmutableSet.<String>of(), keepGoing);
+  }
+
+  /**
+   * Hook method called by the BlazeCommandDispatcher right before the dispatch
+   * of each command ends (while its outcome can still be modified).
+   */
+  ExitCode precompleteCommand(ExitCode originalExit) {
+    eventBus.post(new CommandPrecompleteEvent(originalExit));
+    // If Blaze did not suffer an infrastructure failure, check for errors in modules.
+    ExitCode exitCode = originalExit;
+    if (!originalExit.isInfrastructureFailure() && pendingException != null) {
+      exitCode = pendingException.getExitCode();
+    }
+    return exitCode;
+  }
+
+  /**
+   * Throws the exception currently queued by a Blaze module.
+   *
+   * <p>This should be called as often as is practical so that errors are reported as soon as
+   * possible. Ideally, we'd not need this, but the event bus swallows exceptions so we raise
+   * the exception this way.
+   */
+  public void throwPendingException() throws AbruptExitException {
+    if (pendingException != null) {
+      throw pendingException;
+    }
   }
 }