// Copyright 2014 The Bazel Authors. 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.runtime;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.base.Verify;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.io.Flushables;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Reporter;
import com.google.devtools.build.lib.flags.InvocationPolicyEnforcer;
import com.google.devtools.build.lib.runtime.commands.ProjectFileSupport;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.AnsiStrippingOutputStream;
import com.google.devtools.build.lib.util.BlazeClock;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.LoggingUtil;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.util.io.DelegatingOutErr;
import com.google.devtools.build.lib.util.io.OutErr;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.OpaqueOptionsData;
import com.google.devtools.common.options.OptionPriority;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import javax.annotation.Nullable;

/**
 * Dispatches to the Blaze commands; that is, given a command line, this
 * abstraction looks up the appropriate command object, parses the options
 * required by the object, and calls its exec method. Also, this object provides
 * the runtime state (BlazeRuntime) to the commands.
 */
public class BlazeCommandDispatcher {

  /**
   * What to do if the command lock is not available.
   */
  public enum LockingMode {
    WAIT,  // Wait until it is available
    ERROR_OUT,  // Return with an error
  }
  // Keep in sync with options added in OptionProcessor::AddRcfileArgsAndOptions()
  private static final ImmutableSet<String> INTERNAL_COMMAND_OPTIONS =
      ImmutableSet.of(
          "rc_source",
          "default_override",
          "isatty",
          "terminal_columns",
          "ignore_client_env",
          "client_env",
          "client_cwd");

  private static final ImmutableList<String> HELP_COMMAND = ImmutableList.of("help");

  private static final ImmutableSet<String> ALL_HELP_OPTIONS =
      ImmutableSet.of("--help", "-help", "-h");

  /**
   * By throwing this exception, a command indicates that it wants to shutdown
   * the Blaze server process.
   */
  public static class ShutdownBlazeServerException extends Exception {
    private final int exitStatus;

    public ShutdownBlazeServerException(int exitStatus, Throwable cause) {
      super(cause);
      this.exitStatus = exitStatus;
    }

    public ShutdownBlazeServerException(int exitStatus) {
      this.exitStatus = exitStatus;
    }

    public int getExitStatus() {
      return exitStatus;
    }
  }

  private final BlazeRuntime runtime;
  private final Object commandLock;
  private String currentClientDescription = null;
  private String shutdownReason = null;
  private OutputStream logOutputStream = null;
  private Level lastLogVerbosityLevel = null;
  private final LoadingCache<BlazeCommand, OpaqueOptionsData> optionsDataCache =
      CacheBuilder.newBuilder().build(
          new CacheLoader<BlazeCommand, OpaqueOptionsData>() {
            @Override
            public OpaqueOptionsData load(BlazeCommand command) {
              return OptionsParser.getOptionsData(BlazeCommandUtils.getOptions(
                  command.getClass(),
                  runtime.getBlazeModules(),
                  runtime.getRuleClassProvider()));
            }
          });

  /**
   * Create a Blaze dispatcher that uses the specified {@code BlazeRuntime} instance, but overrides
   * the command map with the given commands (plus any commands from modules).
   */
  @VisibleForTesting
  public BlazeCommandDispatcher(BlazeRuntime runtime, BlazeCommand... commands) {
    this(runtime);
    runtime.overrideCommands(Arrays.asList(commands));
  }

  /**
   * Create a Blaze dispatcher that uses the specified {@code BlazeRuntime} instance.
   */
  @VisibleForTesting
  public BlazeCommandDispatcher(BlazeRuntime runtime) {
    this.runtime = runtime;
    this.commandLock = new Object();
  }

  /**
   * Only some commands work if cwd != workspaceSuffix in Blaze. In that case, also check if Blaze
   * was called from the output directory and fail if it was.
   */
  private ExitCode checkCwdInWorkspace(CommandEnvironment env, Command commandAnnotation,
      String commandName, OutErr outErr) {
    if (!commandAnnotation.mustRunInWorkspace()) {
      return ExitCode.SUCCESS;
    }

    if (!env.inWorkspace()) {
      outErr.printErrLn(
          "The '" + commandName + "' command is only supported from within a workspace.");
      return ExitCode.COMMAND_LINE_ERROR;
    }

    Path workspace = env.getWorkspace();
    // TODO(kchodorow): Remove this once spaces are supported.
    if (workspace.getPathString().contains(" ")) {
      outErr.printErrLn(runtime.getProductName() + " does not currently work properly from paths "
          + "containing spaces (" + workspace + ").");
      return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
    }

    Path doNotBuild = workspace.getParentDirectory().getRelative(
        BlazeWorkspace.DO_NOT_BUILD_FILE_NAME);

    if (doNotBuild.exists()) {
      if (!commandAnnotation.canRunInOutputDirectory()) {
        outErr.printErrLn(getNotInRealWorkspaceError(doNotBuild));
        return ExitCode.COMMAND_LINE_ERROR;
      } else {
        outErr.printErrLn("WARNING: Blaze is run from output directory. This is unsound.");
      }
    }
    return ExitCode.SUCCESS;
  }

  private void parseArgsAndConfigs(CommandEnvironment env, OptionsParser optionsParser,
      Command commandAnnotation, List<String> args, List<String> rcfileNotes, OutErr outErr)
      throws OptionsParsingException {

    Function<String, String> commandOptionSourceFunction = new Function<String, String>() {
      @Override
      public String apply(String input) {
        if (INTERNAL_COMMAND_OPTIONS.contains(input)) {
          return "options generated by Blaze launcher";
        } else {
          return "command line options";
        }
      }
    };

    // Explicit command-line options:
    List<String> cmdLineAfterCommand = args.subList(1, args.size());
    optionsParser.parseWithSourceFunction(OptionPriority.COMMAND_LINE,
        commandOptionSourceFunction, cmdLineAfterCommand);

    // Command-specific options from .blazerc passed in via --default_override
    // and --rc_source. A no-op if none are provided.
    CommonCommandOptions rcFileOptions = optionsParser.getOptions(CommonCommandOptions.class);
    List<Pair<String, ListMultimap<String, String>>> optionsMap =
        getOptionsMap(outErr, rcFileOptions.rcSource, rcFileOptions.optionsOverrides,
            runtime.getCommandMap().keySet());

    parseOptionsForCommand(rcfileNotes, commandAnnotation, optionsParser, optionsMap, null, null);
    if (commandAnnotation.builds()) {
      ProjectFileSupport.handleProjectFiles(env, optionsParser, commandAnnotation.name());
    }

    // Fix-point iteration until all configs are loaded.
    List<String> configsLoaded = ImmutableList.of();
    Set<String> unknownConfigs = new LinkedHashSet<>();
    CommonCommandOptions commonOptions = optionsParser.getOptions(CommonCommandOptions.class);
    while (!commonOptions.configs.equals(configsLoaded)) {
      Set<String> missingConfigs = new LinkedHashSet<>(commonOptions.configs);
      missingConfigs.removeAll(configsLoaded);
      parseOptionsForCommand(rcfileNotes, commandAnnotation, optionsParser, optionsMap,
          missingConfigs, unknownConfigs);
      configsLoaded = commonOptions.configs;
      commonOptions = optionsParser.getOptions(CommonCommandOptions.class);
    }
    if (!unknownConfigs.isEmpty()) {
      outErr.printErrLn("WARNING: Config values are not defined in any .rc file: "
          + Joiner.on(", ").join(unknownConfigs));
    }
  }

  /**
   * Executes a single command. Returns the Unix exit status for the Blaze
   * client process, or throws {@link ShutdownBlazeServerException} to
   * indicate that a command wants to shutdown the Blaze server.
   */
  int exec(List<String> args, OutErr outErr, LockingMode lockingMode, String clientDescription,
      long firstContactTime) throws ShutdownBlazeServerException, InterruptedException {
    Preconditions.checkNotNull(clientDescription);
    if (args.isEmpty()) { // Default to help command if no arguments specified.
      args = HELP_COMMAND;
    }

    String commandName = args.get(0);

    // Be gentle to users who want to find out about Blaze invocation.
    if (ALL_HELP_OPTIONS.contains(commandName)) {
      commandName = "help";
    }

    BlazeCommand command = runtime.getCommandMap().get(commandName);
    if (command == null) {
      outErr.printErrLn(String.format(
          "Command '%s' not found. Try '%s help'.", commandName, runtime.getProductName()));
      return ExitCode.COMMAND_LINE_ERROR.getNumericExitCode();
    }


    long waitTimeInMs = 0;
    synchronized (commandLock) {
      boolean warningPrinted = false;
      while (currentClientDescription != null) {
        switch (lockingMode) {
          case WAIT:
            if (!warningPrinted) {
              outErr.printErrLn("Another command (" + currentClientDescription + ") is running. "
                  + " Waiting for it to complete...");
              warningPrinted = true;
            }
            long clockBefore = BlazeClock.nanoTime();
            commandLock.wait();
            waitTimeInMs = (BlazeClock.nanoTime() - clockBefore) / (1000L * 1000L);
            break;

          case ERROR_OUT:
            outErr.printErrLn(String.format("Another command (" + currentClientDescription + ") is "
                + "running. Exiting immediately."));
            return ExitCode.COMMAND_LINE_ERROR.getNumericExitCode();

          default:
            throw new IllegalStateException();
        }
      }
      Verify.verify(currentClientDescription == null);
      currentClientDescription = clientDescription;
    }

    try {
      if (shutdownReason != null) {
        outErr.printErrLn("Server shut down " + shutdownReason);
        return ExitCode.LOCAL_ENVIRONMENTAL_ERROR.getNumericExitCode();
      }
      return execExclusively(args, outErr, firstContactTime, commandName, command, waitTimeInMs);
    } catch (ShutdownBlazeServerException e) {
      shutdownReason = "explicitly by client " + currentClientDescription;
      throw e;
    } finally {
      synchronized (commandLock) {
        currentClientDescription = null;
        commandLock.notify();
      }
    }
  }

  private int execExclusively(List<String> args, OutErr outErr, long firstContactTime,
      String commandName, BlazeCommand command, long waitTimeInMs)
      throws ShutdownBlazeServerException {
    Command commandAnnotation = command.getClass().getAnnotation(Command.class);

    // Record the start time for the profiler. Do not put anything before this!
    long execStartTimeNanos = runtime.getClock().nanoTime();

    // The initCommand call also records the start time for the timestamp granularity monitor.
    CommandEnvironment env = runtime.getWorkspace().initCommand();
    // Record the command's starting time for use by the commands themselves.
    env.recordCommandStartTime(firstContactTime);

    AbruptExitException exitCausingException = null;
    for (BlazeModule module : runtime.getBlazeModules()) {
      try {
        module.beforeCommand(commandAnnotation, env);
      } catch (AbruptExitException e) {
        // Don't let one module's complaints prevent the other modules from doing necessary
        // setup. We promised to call beforeCommand exactly once per-module before each command
        // and will be calling afterCommand soon in the future - a module's afterCommand might
        // rightfully assume its beforeCommand has already been called.
        outErr.printErrLn(e.getMessage());
        // It's not ideal but we can only return one exit code, so we just pick the code of the
        // last exception.
        exitCausingException = e;
      }
    }
    if (exitCausingException != null) {
      return exitCausingException.getExitCode().getNumericExitCode();
    }

    try {
      Path commandLog = getCommandLogPath(env.getOutputBase());

      // Unlink old command log from previous build, if present, so scripts
      // reading it don't conflate it with the command log we're about to write.
      closeSilently(logOutputStream);
      logOutputStream = null;
      commandLog.delete();

      if (env.getRuntime().writeCommandLog() && commandAnnotation.writeCommandLog()) {
        logOutputStream = commandLog.getOutputStream();
        outErr = tee(outErr, OutErr.create(logOutputStream, logOutputStream));
      }
    } catch (IOException ioException) {
      LoggingUtil.logToRemote(Level.WARNING, "Unable to delete or open command.log", ioException);
    }

    ExitCode result = checkCwdInWorkspace(env, commandAnnotation, commandName, outErr);
    if (!result.equals(ExitCode.SUCCESS)) {
      return result.getNumericExitCode();
    }

    OptionsParser optionsParser;
    // Delay output of notes regarding the parsed rc file, so it's possible to disable this in the
    // rc file.
    List<String> rcfileNotes = new ArrayList<>();
    try {
      optionsParser = createOptionsParser(command);
      parseArgsAndConfigs(env, optionsParser, commandAnnotation, args, rcfileNotes, outErr);

      InvocationPolicyEnforcer optionsPolicyEnforcer =
          new InvocationPolicyEnforcer(runtime.getInvocationPolicy());
      optionsPolicyEnforcer.enforce(optionsParser, commandName);
      optionsPolicyEnforcer =
          InvocationPolicyEnforcer.create(
              getRuntime()
                  .getStartupOptionsProvider()
                  .getOptions(BlazeServerStartupOptions.class)
                  .invocationPolicy);
      optionsPolicyEnforcer.enforce(optionsParser, commandName);
    } catch (OptionsParsingException e) {
      for (String note : rcfileNotes) {
        outErr.printErrLn("INFO: " + note);
      }
      outErr.printErrLn(e.getMessage());
      return ExitCode.COMMAND_LINE_ERROR.getNumericExitCode();
    }

    // Setup log filtering
    BlazeCommandEventHandler.Options eventHandlerOptions =
        optionsParser.getOptions(BlazeCommandEventHandler.Options.class);
    OutErr colorfulOutErr = outErr;

    if (!eventHandlerOptions.useColor()) {
      outErr = ansiStripOut(ansiStripErr(outErr));
      if (!commandAnnotation.binaryStdOut()) {
        colorfulOutErr = ansiStripOut(colorfulOutErr);
      }
      if (!commandAnnotation.binaryStdErr()) {
        colorfulOutErr = ansiStripErr(colorfulOutErr);
      }
    }

    if (!commandAnnotation.binaryStdOut()) {
      outErr = lineBufferOut(outErr);
    }

    if (!commandAnnotation.binaryStdErr()) {
      outErr = lineBufferErr(outErr);
    }

    CommonCommandOptions commonOptions = optionsParser.getOptions(CommonCommandOptions.class);
    if (!commonOptions.verbosity.equals(lastLogVerbosityLevel)) {
      BlazeRuntime.setupLogging(commonOptions.verbosity);
      lastLogVerbosityLevel = commonOptions.verbosity;
    }

    // Do this before an actual crash so we don't have to worry about
    // allocating memory post-crash.
    String[] crashData = env.getCrashData();
    int numericExitCode = ExitCode.BLAZE_INTERNAL_ERROR.getNumericExitCode();
    PrintStream savedOut = System.out;
    PrintStream savedErr = System.err;

    EventHandler handler = createEventHandler(outErr, eventHandlerOptions);
    Reporter reporter = env.getReporter();
    reporter.addHandler(handler);
    env.getEventBus().register(handler);

    // We register an ANSI-allowing handler associated with {@code handler} so that ANSI control
    // codes can be re-introduced later even if blaze is invoked with --color=no. This is useful
    // for commands such as 'blaze run' where the output of the final executable shouldn't be
    // modified.
    EventHandler ansiAllowingHandler = null;
    if (!eventHandlerOptions.useColor()) {
      ansiAllowingHandler = createEventHandler(colorfulOutErr, eventHandlerOptions);
      reporter.registerAnsiAllowingHandler(handler, ansiAllowingHandler);
      if (ansiAllowingHandler instanceof ExperimentalEventHandler) {
        env.getEventBus()
            .register(
                new PassiveExperimentalEventHandler(
                    (ExperimentalEventHandler) ansiAllowingHandler));
      }
    }

    try {
      // While a Blaze command is active, direct all errors to the client's
      // event handler (and out/err streams).
      OutErr reporterOutErr = reporter.getOutErr();
      System.setOut(new PrintStream(reporterOutErr.getOutputStream(), /*autoflush=*/true));
      System.setErr(new PrintStream(reporterOutErr.getErrorStream(), /*autoflush=*/true));

      for (BlazeModule module : runtime.getBlazeModules()) {
        module.checkEnvironment(env);
      }

      if (commonOptions.announceRcOptions) {
        for (String note : rcfileNotes) {
          reporter.handle(Event.info(note));
        }
      }

      try {
        // Notify the BlazeRuntime, so it can do some initial setup.
        env.beforeCommand(commandAnnotation, optionsParser, commonOptions, execStartTimeNanos,
            waitTimeInMs);
        // Allow the command to edit options after parsing:
        command.editOptions(env, optionsParser);
      } catch (AbruptExitException e) {
        reporter.handle(Event.error(e.getMessage()));
        return e.getExitCode().getNumericExitCode();
      }
      for (BlazeModule module : runtime.getBlazeModules()) {
        module.handleOptions(optionsParser);
      }

      // Print warnings for odd options usage
      for (String warning : optionsParser.getWarnings()) {
        reporter.handle(Event.warn(warning));
      }

      ExitCode outcome = command.exec(env, optionsParser);
      outcome = env.precompleteCommand(outcome);
      numericExitCode = outcome.getNumericExitCode();
      return numericExitCode;
    } catch (ShutdownBlazeServerException e) {
      numericExitCode = e.getExitStatus();
      throw e;
    } catch (Throwable e) {
      e.printStackTrace();
      BugReport.printBug(outErr, e);
      BugReport.sendBugReport(e, args, crashData);
      numericExitCode = BugReport.getExitCodeForThrowable(e);
      throw new ShutdownBlazeServerException(numericExitCode, e);
    } finally {
      env.getEventBus().post(new AfterCommandEvent());
      runtime.afterCommand(env, numericExitCode);
      // Swallow IOException, as we are already in a finally clause
      Flushables.flushQuietly(outErr.getOutputStream());
      Flushables.flushQuietly(outErr.getErrorStream());

      System.setOut(savedOut);
      System.setErr(savedErr);
      reporter.removeHandler(handler);
      releaseHandler(handler);
      if (!eventHandlerOptions.useColor()) {
        reporter.removeHandler(ansiAllowingHandler);
        releaseHandler(ansiAllowingHandler);
      }
      env.getTimestampGranularityMonitor().waitForTimestampGranularity(outErr);
    }
  }

  /**
   * For testing ONLY. Same as {@link #exec(List, OutErr, boolean, String, long)}, but automatically
   * uses the current time.
   */
  @VisibleForTesting
  public int exec(List<String> args, LockingMode lockingMode, String clientDescription,
      OutErr originalOutErr) throws ShutdownBlazeServerException, InterruptedException {
    return exec(args, originalOutErr, LockingMode.ERROR_OUT, clientDescription,
        runtime.getClock().currentTimeMillis());
  }

  /**
   * Parses the options from .rc files for a command invocation. It works in one of two modes;
   * either it loads the non-config options, or the config options that are specified in the {@code
   * configs} parameter.
   *
   * <p>This method adds every option pertaining to the specified command to the options parser. To
   * do that, it needs the command -> option mapping that is generated from the .rc files.
   *
   * <p>It is not as trivial as simply taking the list of options for the specified command because
   * commands can inherit arguments from each other, and we have to respect that (e.g. if an option
   * is specified for 'build', it needs to take effect for the 'test' command, too).
   *
   * <p>Note that the order in which the options are parsed is well-defined: all options from the
   * same rc file are parsed at the same time, and the rc files are handled in the order in which
   * they were passed in from the client.
   *
   * @param rcfileNotes note message that would be printed during parsing
   * @param commandAnnotation the command for which options should be parsed.
   * @param optionsParser parser to receive parsed options.
   * @param optionsMap .rc files in structured format: a list of pairs, where the first part is the
   *     name of the rc file, and the second part is a multimap of command name (plus config, if
   *     present) to the list of options for that command
   * @param configs the configs for which to parse options; if {@code null}, non-config options are
   *     parsed
   * @param unknownConfigs optional; a collection that the method will populate with the config
   *     values in {@code configs} that none of the .rc files had entries for
   * @throws OptionsParsingException
   */
  protected static void parseOptionsForCommand(List<String> rcfileNotes, Command commandAnnotation,
      OptionsParser optionsParser, List<Pair<String, ListMultimap<String, String>>> optionsMap,
      @Nullable Collection<String> configs, @Nullable Collection<String> unknownConfigs)
      throws OptionsParsingException {
    Set<String> knownConfigs = new HashSet<>();
    for (String commandToParse : getCommandNamesToParse(commandAnnotation)) {
      for (Pair<String, ListMultimap<String, String>> entry : optionsMap) {
        List<String> allOptions = new ArrayList<>();
        if (configs == null) {
          allOptions.addAll(entry.second.get(commandToParse));
        } else {
          for (String config : configs) {
            Collection<String> values = entry.second.get(commandToParse + ":" + config);
            if (!values.isEmpty()) {
              allOptions.addAll(values);
              knownConfigs.add(config);
            }
          }
        }
        processOptionList(optionsParser, commandToParse,
            commandAnnotation.name(), rcfileNotes, entry.first, allOptions);
      }
    }
    if (unknownConfigs != null && configs != null && configs.size() > knownConfigs.size()) {
      Iterables.addAll(
          unknownConfigs,
          Iterables.filter(configs, Predicates.not(Predicates.in(knownConfigs))));
    }
  }

  // Processes the option list for an .rc file - command pair.
  private static void processOptionList(OptionsParser optionsParser, String commandToParse,
      String originalCommand, List<String> rcfileNotes, String rcfile, List<String> rcfileOptions)
      throws OptionsParsingException {
    if (!rcfileOptions.isEmpty()) {
      String inherited = commandToParse.equals(originalCommand) ? "" : "Inherited ";
      String source = rcfile.equals("client") ? "Options provided by the client"
          : "Reading options for '" + originalCommand + "' from " + rcfile;
      rcfileNotes.add(source + ":\n"
          + "  " + inherited + "'" + commandToParse + "' options: "
        + Joiner.on(' ').join(rcfileOptions));
      optionsParser.parse(OptionPriority.RC_FILE, rcfile, rcfileOptions);
    }
  }

  private static List<String> getCommandNamesToParse(Command commandAnnotation) {
    List<String> result = new ArrayList<>();
    result.add("common");
    getCommandNamesToParseHelper(commandAnnotation, result);
    return result;
  }

  private static void getCommandNamesToParseHelper(Command commandAnnotation,
      List<String> accumulator) {
    for (Class<? extends BlazeCommand> base : commandAnnotation.inherits()) {
      getCommandNamesToParseHelper(base.getAnnotation(Command.class), accumulator);
    }
    accumulator.add(commandAnnotation.name());
  }

  private OutErr lineBufferOut(OutErr outErr) {
    OutputStream wrappedOut = new LineBufferedOutputStream(outErr.getOutputStream());
    return OutErr.create(wrappedOut, outErr.getErrorStream());
  }

  private OutErr lineBufferErr(OutErr outErr) {
    OutputStream wrappedErr = new LineBufferedOutputStream(outErr.getErrorStream());
    return OutErr.create(outErr.getOutputStream(), wrappedErr);
  }

  private OutErr ansiStripOut(OutErr outErr) {
    OutputStream wrappedOut = new AnsiStrippingOutputStream(outErr.getOutputStream());
    return OutErr.create(wrappedOut, outErr.getErrorStream());
  }

  private OutErr ansiStripErr(OutErr outErr) {
    OutputStream wrappedErr = new AnsiStrippingOutputStream(outErr.getErrorStream());
    return OutErr.create(outErr.getOutputStream(), wrappedErr);
  }

  private String getNotInRealWorkspaceError(Path doNotBuildFile) {
    String message = "Blaze should not be called from a Blaze output directory. ";
    try {
      String realWorkspace =
          new String(FileSystemUtils.readContentAsLatin1(doNotBuildFile));
      message += String.format("The pertinent workspace directory is: '%s'",
          realWorkspace);
    } catch (IOException e) {
      // We are exiting anyway.
    }

    return message;
  }

  /**
   * For a given output_base directory, returns the command log file path.
   */
  public static Path getCommandLogPath(Path outputBase) {
    return outputBase.getRelative("command.log");
  }

  private OutErr tee(OutErr outErr1, OutErr outErr2) {
    DelegatingOutErr outErr = new DelegatingOutErr();
    outErr.addSink(outErr1);
    outErr.addSink(outErr2);
    return outErr;
  }

  private void closeSilently(OutputStream logOutputStream) {
    if (logOutputStream != null) {
      try {
        logOutputStream.close();
      } catch (IOException e) {
        LoggingUtil.logToRemote(Level.WARNING, "Unable to close command.log", e);
      }
    }
  }

  /**
   * Creates an option parser using the common options classes and the
   * command-specific options classes.
   *
   * <p>An overriding method should first call this method and can then
   * override default values directly or by calling {@link
   * #parseOptionsForCommand} for command-specific options.
   *
   * @throws OptionsParsingException
   */
  protected OptionsParser createOptionsParser(BlazeCommand command)
      throws OptionsParsingException {
    Command annotation = command.getClass().getAnnotation(Command.class);
    OptionsParser parser = OptionsParser.newOptionsParser(optionsDataCache.getUnchecked(command));
    parser.setAllowResidue(annotation.allowResidue());
    return parser;
  }

  /**
   * Convert a list of option override specifications to a more easily digestible
   * form.
   *
   * @param overrides list of option override specifications
   */
  @VisibleForTesting
  static List<Pair<String, ListMultimap<String, String>>> getOptionsMap(
      OutErr outErr,
      List<String> rcFiles,
      List<CommonCommandOptions.OptionOverride> overrides,
      Set<String> validCommands) {
    List<Pair<String, ListMultimap<String, String>>> result = new ArrayList<>();

    String lastRcFile = null;
    ListMultimap<String, String> lastMap = null;
    for (CommonCommandOptions.OptionOverride override : overrides) {
      if (override.blazeRc < 0 || override.blazeRc >= rcFiles.size()) {
        outErr.printErrLn("WARNING: inconsistency in generated command line "
            + "args. Ignoring bogus argument\n");
        continue;
      }
      String rcFile = rcFiles.get(override.blazeRc);

      String command = override.command;
      int index = command.indexOf(':');
      if (index > 0) {
        command = command.substring(0, index);
      }
      if (!validCommands.contains(command) && !command.equals("common")) {
        outErr.printErrLn("WARNING: while reading option defaults file '"
            + rcFile + "':\n"
            + "  invalid command name '" + override.command + "'.");
        continue;
      }

      if (!rcFile.equals(lastRcFile)) {
        if (lastRcFile != null) {
          result.add(Pair.of(lastRcFile, lastMap));
        }
        lastRcFile = rcFile;
        lastMap = ArrayListMultimap.create();
      }
      lastMap.put(override.command, override.option);
    }
    if (lastRcFile != null) {
      result.add(Pair.of(lastRcFile, lastMap));
    }

    return result;
  }

  /**
   * Returns the event handler to use for this Blaze command.
   */
  private EventHandler createEventHandler(OutErr outErr,
      BlazeCommandEventHandler.Options eventOptions) {
    EventHandler eventHandler;
    if (eventOptions.experimentalUi) {
      // The experimental event handler is not to be rate limited.
      return new ExperimentalEventHandler(outErr, eventOptions, runtime.getClock());
    } else if ((eventOptions.useColor() || eventOptions.useCursorControl())) {
      eventHandler = new FancyTerminalEventHandler(outErr, eventOptions);
    } else {
      eventHandler = new BlazeCommandEventHandler(outErr, eventOptions);
    }

    return RateLimitingEventHandler.create(eventHandler, eventOptions.showProgressRateLimit);
  }

  /**
   * Unsets the event handler.
   */
  private void releaseHandler(EventHandler eventHandler) {
    if (eventHandler instanceof FancyTerminalEventHandler) {
      // Make sure that the terminal state of the old event handler is clear
      // before creating a new one.
      ((FancyTerminalEventHandler) eventHandler).resetTerminal();
    }
    if (eventHandler instanceof ExperimentalEventHandler) {
      ((ExperimentalEventHandler) eventHandler).resetTerminal();
    }
  }

  /**
   * Returns the runtime instance shared by the commands that this dispatcher
   * dispatches to.
   */
  public BlazeRuntime getRuntime() {
    return runtime;
  }

  /**
   * Shuts down all the registered commands to give them a chance to cleanup or
   * close resources. Should be called by the owner of this command dispatcher
   * in all termination cases.
   */
  public void shutdown() {
    closeSilently(logOutputStream);
    logOutputStream = null;
  }
}
