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/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
index d646b51..0f72512 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
@@ -181,7 +181,7 @@
             request.getMultiCpus(), request.getViewOptions().keepGoing);
 
       env.getEventBus().post(new ConfigurationsCreatedEvent(configurations));
-      runtime.throwPendingException();
+      env.throwPendingException();
       if (configurations.getTargetConfigurations().size() == 1) {
         // TODO(bazel-team): This is not optimal - we retain backwards compatibility in the case
         // where there's only a single configuration, but we don't send an event in the multi-config
@@ -376,7 +376,7 @@
           throws LoadingFailedException, TargetParsingException, InterruptedException,
           AbruptExitException {
     Profiler.instance().markPhase(ProfilePhase.LOAD);
-    runtime.throwPendingException();
+    env.throwPendingException();
 
     initializeOutputFilter(request);
 
@@ -400,7 +400,7 @@
         env.getEventBus(), request.getTargets(), request.getLoadingOptions(),
         runtime.createBuildOptions(request).getAllLabels(), keepGoing,
         isLoadingEnabled(request), request.shouldRunTests(), callback);
-    runtime.throwPendingException();
+    env.throwPendingException();
     return result;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index b43e0cea..4c6a57f 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -387,7 +387,7 @@
       }
 
       ExitCode outcome = command.exec(env, optionsParser);
-      outcome = runtime.precompleteCommand(env, outcome);
+      outcome = env.precompleteCommand(outcome);
       numericExitCode = outcome.getNumericExitCode();
       return numericExitCode;
     } catch (ShutdownBlazeServerException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index 40d4e88..9d77e80 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -46,21 +46,16 @@
 import com.google.devtools.build.lib.analysis.WorkspaceStatusAction;
 import com.google.devtools.build.lib.analysis.config.BinTools;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-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.ConfigurationFactory;
 import com.google.devtools.build.lib.analysis.config.DefaultsPackage;
-import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.OutputFilter;
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.exec.OutputService;
-import com.google.devtools.build.lib.packages.NoSuchThingException;
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.Preprocessor;
 import com.google.devtools.build.lib.packages.RuleClassProvider;
-import com.google.devtools.build.lib.packages.Target;
-import com.google.devtools.build.lib.pkgcache.LoadedPackageProvider;
 import com.google.devtools.build.lib.pkgcache.LoadingPhaseRunner;
 import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
 import com.google.devtools.build.lib.pkgcache.PackageManager;
@@ -95,7 +90,6 @@
 import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutorFactory;
-import com.google.devtools.build.lib.syntax.Label;
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.util.BlazeClock;
 import com.google.devtools.build.lib.util.Clock;
@@ -176,6 +170,7 @@
 
   private final SkyframeExecutor skyframeExecutor;
 
+  // Always null in production! Only non-null when tests inject a custom reporter.
   private final Reporter reporter;
   private final LoadingPhaseRunner loadingPhaseRunner;
   private final PackageFactory packageFactory;
@@ -190,7 +185,6 @@
   private OutputService outputService;
 
   private final Iterable<BlazeModule> blazeModules;
-  private final BlazeModule.ModuleEnvironment blazeModuleEnvironment;
 
   private UUID commandId;  // Unique identifier for the command being run
 
@@ -204,8 +198,6 @@
   private String outputFileSystem;
   private Map<String, BlazeCommand> commandMap;
 
-  private AbruptExitException pendingException;
-
   private final SubscriberExceptionHandler eventBusExceptionHandler;
 
   private final BinTools binTools;
@@ -214,23 +206,6 @@
 
   private final ProjectFile.Provider projectFileProvider;
 
-  private class BlazeModuleEnvironment implements BlazeModule.ModuleEnvironment {
-    @Override
-    public Path getFileFromDepot(Label label)
-        throws NoSuchThingException, InterruptedException, IOException {
-      Target target = getPackageManager().getTarget(reporter, label);
-      return (outputService != null)
-          ? outputService.stageTool(target)
-          : target.getPackage().getPackageDirectory().getRelative(target.getName());
-    }
-
-    @Override
-    public void exit(AbruptExitException exception) {
-      Preconditions.checkState(pendingException == null);
-      pendingException = exception;
-    }
-  }
-
   private BlazeRuntime(BlazeDirectories directories, Reporter reporter,
       WorkspaceStatusAction.Factory workspaceStatusActionFactory,
       final SkyframeExecutor skyframeExecutor,
@@ -267,7 +242,6 @@
     this.startupOptionsProvider = startupOptionsProvider;
 
     this.eventBusExceptionHandler = eventBusExceptionHandler;
-    this.blazeModuleEnvironment = new BlazeModuleEnvironment();
 
     if (inWorkspace()) {
       writeOutputBaseReadmeFile();
@@ -310,7 +284,7 @@
   public CommandEnvironment initCommand() {
     EventBus eventBus = new EventBus(eventBusExceptionHandler);
     skyframeExecutor.setEventBus(eventBus);
-    return new CommandEnvironment(this, eventBus);
+    return new CommandEnvironment(this, reporter, eventBus);
   }
 
   private void clearEventBus() {
@@ -502,13 +476,6 @@
     return directories.getExecRoot();
   }
 
-  /**
-   * Returns the reporter for events.
-   */
-  public Reporter getReporter() {
-    return reporter;
-  }
-
   public BinTools getBinTools() {
     return binTools;
   }
@@ -552,10 +519,6 @@
     return workspaceStatusActionFactory;
   }
 
-  public BlazeModule.ModuleEnvironment getBlazeModuleEnvironment() {
-    return blazeModuleEnvironment;
-  }
-
   /**
    * Returns the rule class provider.
    */
@@ -687,7 +650,7 @@
 
     env.getEventBus().post(new GotOptionsEvent(startupOptionsProvider,
         optionsParser));
-    throwPendingException();
+    env.throwPendingException();
 
     outputService = null;
     BlazeModule outputModule = null;
@@ -788,21 +751,6 @@
   }
 
   /**
-   * Hook method called by the BlazeCommandDispatcher right before the dispatch
-   * of each command ends (while its outcome can still be modified).
-   */
-  ExitCode precompleteCommand(CommandEnvironment env, ExitCode originalExit) {
-    env.getEventBus().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();
-    }
-    pendingException = null;
-    return exitCode;
-  }
-
-  /**
    * Posts the {@link CommandCompleteEvent}, so that listeners can tidy up. Called by {@link
    * #afterCommand}, and by BugReport when crashing from an exception in an async thread.
    */
@@ -954,26 +902,6 @@
   }
 
   /**
-   * 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 = createBuildOptions(optionsProvider);
-    boolean keepGoing = optionsProvider.getOptions(BuildView.Options.class).keepGoing;
-    LoadedPackageProvider loadedPackageProvider =
-        loadingPhaseRunner.loadForConfigurations(reporter,
-            ImmutableSet.copyOf(buildOptions.getAllLabels().values()),
-            keepGoing);
-    if (loadedPackageProvider == null) {
-      throw new InvalidConfigurationException("Configuration creation failed");
-    }
-    return skyframeExecutor.createConfigurations(configurationFactory,
-        buildOptions, directories, ImmutableSet.<String>of(), keepGoing);
-  }
-
-  /**
    * Initializes the package cache using the given options, and syncs the package cache. Also
    * injects a defaults package using the options for the {@link BuildConfiguration}.
    *
@@ -995,21 +923,6 @@
   }
 
   /**
-   * 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) {
-      AbruptExitException exception = pendingException;
-      pendingException = null;
-      throw exception;
-    }
-  }
-
-  /**
    * Returns the defaults package for the default settings. Should only be called by commands that
    * do <i>not</i> process {@link BuildOptions}, since build options can alter the contents of the
    * defaults package, which will not be reflected here.
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;
+    }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
index 38f913e..8347328 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
@@ -203,7 +203,7 @@
               optionsProvider.getOptions(PackageCacheOptions.class),
               runtime.getDefaultsPackageContent(optionsProvider));
           // TODO(bazel-team): What if there are multiple configurations? [multi-config]
-          configuration = runtime
+          configuration = env
               .getConfigurations(optionsProvider)
               .getTargetConfigurations().get(0);
           return configuration;