BlazeCommandDispatcher: make parseArgsAndConfigs not take a CommandEnvironment

Accept an ExtendedEventHandler in ProjectFileSupport, and use an
ExtendedEventHandler in BlazeCommandDispatcher that captures the posts, and
delay posting the GotProjectFileEvent until the initialization is complete.

This is a small step towards simplifying the BlazeModule API - the plan is to
merge beforeCommand, checkEnvironment, and handleOptions into a single method,
but introduce a new method (commandInit) to participate in the early command
initialization.

PiperOrigin-RevId: 160259628
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 330a69d..3182376 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
@@ -32,6 +32,8 @@
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
 import com.google.devtools.build.lib.events.PrintingEventHandler;
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.runtime.commands.ProjectFileSupport;
@@ -198,9 +200,9 @@
     return ExitCode.SUCCESS;
   }
 
-  private void parseArgsAndConfigs(CommandEnvironment env, OptionsParser optionsParser,
-      Command commandAnnotation, List<String> args, List<String> rcfileNotes,
-      EventHandler eventHandler)
+  private void parseArgsAndConfigs(Path workspaceDirectory, Path workingDirectory,
+      OptionsParser optionsParser, Command commandAnnotation, List<String> args,
+      List<String> rcfileNotes, ExtendedEventHandler eventHandler)
           throws OptionsParsingException {
     Function<String, String> commandOptionSourceFunction =
         new Function<String, String>() {
@@ -229,8 +231,8 @@
     parseOptionsForCommand(rcfileNotes, commandAnnotation, optionsParser, optionsMap, null, null);
     if (commandAnnotation.builds()) {
       ProjectFileSupport.handleProjectFiles(
-          eventHandler, env.getEventBus(), runtime.getProjectFileProvider(), env.getWorkspace(),
-          env.getWorkingDirectory(), optionsParser, commandAnnotation.name());
+          eventHandler, runtime.getProjectFileProvider(), workspaceDirectory, workingDirectory,
+          optionsParser, commandAnnotation.name());
     }
 
     // Fix-point iteration until all configs are loaded.
@@ -386,7 +388,9 @@
       }
     }
 
-    EventHandler eventHandler = new PrintingEventHandler(outErr, EventKind.ALL_EVENTS);
+    // Print any normal events, but store all event bus events.
+    ExtendedPrintingEventHandler eventHandler =
+        new ExtendedPrintingEventHandler(outErr, EventKind.ALL_EVENTS);
     ExitCode result = checkCwdInWorkspace(workspace, commandAnnotation, commandName, eventHandler);
     if (!result.equals(ExitCode.SUCCESS)) {
       return result.getNumericExitCode();
@@ -400,10 +404,11 @@
     List<String> rcfileNotes = new ArrayList<>();
     try {
       OptionsParser optionsParser = createOptionsParser(command);
-      // TODO(ulfjack): parseArgsAndConfigs calls env.getWorkingDirectory, which isn't set correctly
-      // at this point in the code - it's initialized to the workspace root, which usually works.
+      // TODO(ulfjack): env.getWorkingDirectory isn't set correctly at this point in the code - it's
+      // initialized to the workspace root, which usually works.
       parseArgsAndConfigs(
-          env, optionsParser, commandAnnotation, args, rcfileNotes, eventHandler);
+          env.getWorkspace(), env.getWorkingDirectory(), optionsParser, commandAnnotation, args,
+          rcfileNotes, eventHandler);
       // Allow the command to edit the options.
       command.editOptions(optionsParser);
       // Migration of --watchfs to a command option.
@@ -513,6 +518,10 @@
       System.setOut(new PrintStream(reporterOutErr.getOutputStream(), /*autoflush=*/true));
       System.setErr(new PrintStream(reporterOutErr.getErrorStream(), /*autoflush=*/true));
 
+      for (Postable post : eventHandler.posts) {
+        env.getEventBus().post(post);
+      }
+
       for (BlazeModule module : runtime.getBlazeModules()) {
         module.checkEnvironment(env);
       }
@@ -855,5 +864,21 @@
     closeSilently(logOutputStream);
     logOutputStream = null;
   }
-}
 
+  /**
+   * A printing event handler that also stores posts.
+   */
+  private static final class ExtendedPrintingEventHandler extends PrintingEventHandler
+      implements ExtendedEventHandler {
+    private final List<Postable> posts = new ArrayList<>();
+
+    public ExtendedPrintingEventHandler(OutErr outErr, Set<EventKind> mask) {
+      super(outErr, mask);
+    }
+
+    @Override
+    public void post(Postable p) {
+      posts.add(p);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/ProjectFileSupport.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/ProjectFileSupport.java
index 69b00fd..9d775df 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/ProjectFileSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/ProjectFileSupport.java
@@ -13,9 +13,8 @@
 // limitations under the License.
 package com.google.devtools.build.lib.runtime.commands;
 
-import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.runtime.BlazeCommand;
@@ -43,7 +42,7 @@
    * are not enabled, then it throws an exception instead.
    */
   public static void handleProjectFiles(
-      EventHandler eventHandler, EventBus eventBus, ProjectFile.Provider projectFileProvider,
+      ExtendedEventHandler eventHandler, ProjectFile.Provider projectFileProvider,
       Path workspaceDir, Path workingDir, OptionsParser optionsParser, String command)
           throws OptionsParsingException {
     List<String> targets = optionsParser.getResidue();
@@ -73,7 +72,7 @@
 
       optionsParser.parse(
           OptionPriority.RC_FILE, projectFile.getName(), projectFile.getCommandLineFor(command));
-      eventBus.post(new GotProjectFileEvent(projectFile.getName()));
+      eventHandler.post(new GotProjectFileEvent(projectFile.getName()));
     }
   }