// 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.Joiner;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
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.runtime.commands.ProjectFileSupport;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.InvocationPolicyEnforcer;
import com.google.devtools.common.options.OptionDefinition;
import com.google.devtools.common.options.OptionPriority.PriorityCategory;
import com.google.devtools.common.options.OptionValueDescription;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import com.google.devtools.common.options.OptionsProvider;
import com.google.devtools.common.options.ParsedOptionDescription;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.logging.Level;

/**
 * Handles parsing the blaze command arguments.
 *
 * <p>This class manages rc options, default options, and invocation policy.
 */
public abstract class BlazeOptionHandler {
  // 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");

  protected final BlazeRuntime runtime;
  protected final OptionsParser optionsParser;
  protected final BlazeWorkspace workspace;
  protected final BlazeCommand command;
  protected final Command commandAnnotation;
  protected final InvocationPolicy invocationPolicy;
  protected final List<String> rcfileNotes = new ArrayList<>();

  private BlazeOptionHandler(
      BlazeRuntime runtime,
      BlazeWorkspace workspace,
      BlazeCommand command,
      Command commandAnnotation,
      OptionsParser optionsParser,
      InvocationPolicy invocationPolicy) {
    this.runtime = runtime;
    this.workspace = workspace;
    this.command = command;
    this.commandAnnotation = commandAnnotation;
    this.optionsParser = optionsParser;
    this.invocationPolicy = invocationPolicy;
  }

  public static BlazeOptionHandler getHandler(
      BlazeRuntime runtime,
      BlazeWorkspace workspace,
      BlazeCommand command,
      Command commandAnnotation,
      OptionsParser optionsParser,
      InvocationPolicy invocationPolicy,
      boolean expandConfigsInPlace) {
    if (expandConfigsInPlace) {
      return new InPlaceConfigExpansionRcHandler(
          runtime, workspace, command, commandAnnotation, optionsParser, invocationPolicy);
    } else {
      return new FixPointConfigExpansionRcHandler(
          runtime, workspace, command, commandAnnotation, optionsParser, invocationPolicy);
    }
  }

  // Return options as OptionsProvider so the options can't be easily modified after we've
  // applied the invocation policy.
  OptionsProvider getOptionsResult() {
    return optionsParser;
  }

  public List<String> getRcfileNotes() {
    return rcfileNotes;
  }

  /**
   * 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(EventHandler eventHandler) {
    if (!commandAnnotation.mustRunInWorkspace()) {
      return ExitCode.SUCCESS;
    }

    if (!workspace.getDirectories().inWorkspace()) {
      eventHandler.handle(
          Event.error(
              "The '"
                  + commandAnnotation.name()
                  + "' command is only supported from within a workspace."));
      return ExitCode.COMMAND_LINE_ERROR;
    }

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

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

    if (doNotBuild.exists()) {
      if (!commandAnnotation.canRunInOutputDirectory()) {
        eventHandler.handle(Event.error(getNotInRealWorkspaceError(doNotBuild)));
        return ExitCode.COMMAND_LINE_ERROR;
      } else {
        eventHandler.handle(
            Event.warn(
                runtime.getProductName() + " is run from output directory. This is unsound."));
      }
    }
    return ExitCode.SUCCESS;
  }

  /**
   * Parses the unconditional options from .rc files for the current command.
   *
   * <p>This 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). More
   * specific commands should have priority over the broader commands (say a "build" option that
   * conflicts with a "common" option should override the common one regardless of order.)
   *
   * <p>For each command, the options are parsed in rc order. This uses the master rc file first,
   * and follows import statements. This is the order in which they were passed by the client.
   */
  void parseRcOptions(
      EventHandler eventHandler, ListMultimap<String, RcChunkOfArgs> commandToRcArgs)
      throws OptionsParsingException {
    for (String commandToParse : getCommandNamesToParse(commandAnnotation)) {
      // Get all args defined for this command (or "common"), grouped by rc chunk.
      for (RcChunkOfArgs rcArgs : commandToRcArgs.get(commandToParse)) {
        if (!rcArgs.args.isEmpty()) {
          String inherited = commandToParse.equals(commandAnnotation.name()) ? "" : "Inherited ";
          String source =
              rcArgs.rcFile.equals("client")
                  ? "Options provided by the client"
                  : String.format(
                      "Reading rc options for '%s' from %s",
                      commandAnnotation.name(), rcArgs.rcFile);
          rcfileNotes.add(
              String.format(
                  "%s:\n  %s'%s' options: %s",
                  source, inherited, commandToParse, Joiner.on(' ').join(rcArgs.args)));
        }
        optionsParser.parse(PriorityCategory.RC_FILE, rcArgs.rcFile, rcArgs.args);
      }
    }
  }

  /**
   * Expand the values of --config according to the definitions provided in the rc files and the
   * applicable command.
   */
  abstract void expandConfigOptions(
      EventHandler eventHandler, ListMultimap<String, RcChunkOfArgs> commandToRcArgs)
      throws OptionsParsingException;

  private void parseArgsAndConfigs(List<String> args, ExtendedEventHandler eventHandler)
      throws OptionsParsingException {
    Path workspaceDirectory = workspace.getWorkspace();
    // TODO(ulfjack): The working directory is passed by the client as part of CommonCommandOptions,
    // and we can't know it until after we've parsed the options, so use the workspace for now.
    Path workingDirectory = workspace.getWorkspace();

    Function<OptionDefinition, String> commandOptionSourceFunction =
        option -> {
          if (INTERNAL_COMMAND_OPTIONS.contains(option.getOptionName())) {
            return "options generated by " + runtime.getProductName() + " launcher";
          } else {
            return "command line options";
          }
        };

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

    // Command-specific options from .blazerc passed in via --default_override and --rc_source.
    ClientOptions rcFileOptions = optionsParser.getOptions(ClientOptions.class);
    ListMultimap<String, RcChunkOfArgs> commandToRcArgs =
        structureRcOptionsAndConfigs(
            eventHandler,
            rcFileOptions.rcSource,
            rcFileOptions.optionsOverrides,
            runtime.getCommandMap().keySet());
    parseRcOptions(eventHandler, commandToRcArgs);

    if (commandAnnotation.builds()) {
      // splits project files from targets in the traditional sense
      ProjectFileSupport.handleProjectFiles(
          eventHandler,
          runtime.getProjectFileProvider(),
          workspaceDirectory,
          workingDirectory,
          optionsParser,
          commandAnnotation.name());
    }

    expandConfigOptions(eventHandler, commandToRcArgs);
  }

  /**
   * Parses the options, taking care not to generate any output to outErr, return, or throw an
   * exception.
   *
   * @return ExitCode.SUCCESS if everything went well, or some other value if not
   */
  ExitCode parseOptions(List<String> args, ExtendedEventHandler eventHandler) {
    // The initialization code here was carefully written to parse the options early before we call
    // into the BlazeModule APIs, which means we must not generate any output to outErr, return, or
    // throw an exception. All the events happening here are instead stored in a temporary event
    // handler, and later replayed.
    ExitCode earlyExitCode = checkCwdInWorkspace(eventHandler);
    if (!earlyExitCode.equals(ExitCode.SUCCESS)) {
      return earlyExitCode;
    }

    try {
      parseArgsAndConfigs(args, eventHandler);
      // Allow the command to edit the options.
      command.editOptions(optionsParser);
      // Migration of --watchfs to a command option.
      // TODO(ulfjack): Get rid of the startup option and drop this code.
      if (runtime.getStartupOptionsProvider().getOptions(BlazeServerStartupOptions.class).watchFS) {
        try {
          optionsParser.parse("--watchfs");
        } catch (OptionsParsingException e) {
          // This should never happen.
          throw new IllegalStateException(e);
        }
      }
      // Merge the invocation policy that is user-supplied, from the command line, and any
      // invocation policy that was added by a module. The module one goes 'first,' so the user
      // one has priority.
      InvocationPolicy combinedPolicy =
          InvocationPolicy.newBuilder()
              .mergeFrom(runtime.getModuleInvocationPolicy())
              .mergeFrom(invocationPolicy)
              .build();
      InvocationPolicyEnforcer optionsPolicyEnforcer =
          new InvocationPolicyEnforcer(combinedPolicy, Level.INFO);
      // Enforce the invocation policy. It is intentional that this is the last step in preparing
      // the options. The invocation policy is used in security-critical contexts, and may be used
      // as a last resort to override flags. That means that the policy can override flags set in
      // BlazeCommand.editOptions, so the code needs to be safe regardless of the actual flag
      // values. At the time of this writing, editOptions was only used as a convenience feature or
      // to improve the user experience, but not required for safety or correctness.
      optionsPolicyEnforcer.enforce(optionsParser, commandAnnotation.name());
      // Print warnings for odd options usage
      for (String warning : optionsParser.getWarnings()) {
        eventHandler.handle(Event.warn(warning));
      }
      CommonCommandOptions commonOptions = optionsParser.getOptions(CommonCommandOptions.class);
      for (String warning : commonOptions.deprecationWarnings) {
        eventHandler.handle(Event.warn(warning));
      }
    } catch (OptionsParsingException e) {
      eventHandler.handle(Event.error(e.getMessage()));
      return ExitCode.COMMAND_LINE_ERROR;
    }
    return ExitCode.SUCCESS;
  }

  /**
   * Implements the legacy way of expanding blazerc and config expansions.
   *
   * <p>--config options are expanded in a fixed point expansion at the end of the rc option block.
   * Their expansion is defined in the rc file, and is triggered by the presence of a {@code
   * --config=someConfigName} option somewhere in the user's options. The resulting option order is
   * {@code <rc options> <config expansions> <command line options>}, where all of the config values
   * mentioned are in the mid segment, regardless of whether they were defined in an rc file, on the
   * command line, or in the expansion of other config values that were triggered earlier. If the
   * same config value is provided twice (say, once on the command line and once in another config
   * expansion) it will only be expanded once.
   *
   * <p>This behavior is relatively well-defined, but the final order of options is not intuitive.
   * As a simple example, consider a user specified command line with --config=foo last. Most users
   * expect the expansion of --config=foo to override earlier flags in their command line if
   * necessary, but this is not the case. This is why we are phasing out this behavior. We will
   * maintain the old behavior to avoid breaking users during a transition period.
   */
  static final class FixPointConfigExpansionRcHandler extends BlazeOptionHandler {

    private FixPointConfigExpansionRcHandler(
        BlazeRuntime runtime,
        BlazeWorkspace workspace,
        BlazeCommand command,
        Command commandAnnotation,
        OptionsParser optionsParser,
        InvocationPolicy invocationPolicy) {
      super(runtime, workspace, command, commandAnnotation, optionsParser, invocationPolicy);
    }

    @Override
    void expandConfigOptions(
        EventHandler eventHandler, ListMultimap<String, RcChunkOfArgs> commandToRcArgs)
        throws OptionsParsingException {
      // 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)) {
        // Parse the configs we have not seen yet.
        Set<String> missingConfigs = new LinkedHashSet<>(commonOptions.configs);
        missingConfigs.removeAll(configsLoaded);
        parseConfigOptionsForCommand(commandToRcArgs, missingConfigs, unknownConfigs);
        // Refresh the list of config values we've processed to be the list of config values we had
        // before the call to parseConfigOptionsForCommand.
        configsLoaded = commonOptions.configs;
        commonOptions = optionsParser.getOptions(CommonCommandOptions.class);
      }
      if (!unknownConfigs.isEmpty()) {
        if (commonOptions.allowUndefinedConfigs) {
          eventHandler.handle(
              Event.warn(
                  "Config values are not defined in any .rc file: "
                      + Joiner.on(", ").join(unknownConfigs)));
        } else {
          throw new OptionsParsingException(
              "Config values are not defined in any .rc file: "
                  + Joiner.on(", ").join(unknownConfigs));
        }
      }
    }

    /**
     * Go through the configs given and parse their expansion if a definition was found.
     *
     * @param configs the configs for which to parse options.
     * @param unknownConfigs a collection that the method will populate with the config values in
     *     {@code configs} that none of the .rc files had entries for.
     */
    private void parseConfigOptionsForCommand(
        ListMultimap<String, RcChunkOfArgs> commandToRcArgs,
        Collection<String> configs,
        Collection<String> unknownConfigs)
        throws OptionsParsingException {
      Set<String> knownConfigs = new HashSet<>();
      for (String commandToParse : getCommandNamesToParse(commandAnnotation)) {
        for (String config : configs) {
          String configDef = commandToParse + ":" + config;
          for (RcChunkOfArgs rcArgs : commandToRcArgs.get(configDef)) {
            // Track that we've found at least 1 definition for this config value.
            knownConfigs.add(config);
            rcfileNotes.add(
                String.format(
                    "Found applicable config definition %s in file %s: %s",
                    configDef, rcArgs.rcFile, String.join(" ", rcArgs.args)));
            optionsParser.parse(PriorityCategory.RC_FILE, rcArgs.rcFile, rcArgs.args);
          }
        }
      }
      if (configs.size() > knownConfigs.size()) {
        configs
            .stream()
            .filter(Predicates.not(Predicates.in(knownConfigs)))
            .forEachOrdered(unknownConfigs::add);
      }
    }
  }

  /**
   * Expands the rc's options in {@code <rc options> <command line>} order, with config options
   * expanded wherever the --config option was mentioned.
   *
   * <p>This requires a bit more care than the in-place expansion. We need to be wary of potential
   * cycles in the definitions of config values, and should warn when a single --config expansion
   * contradicts itself.
   */
  static final class InPlaceConfigExpansionRcHandler extends BlazeOptionHandler {

    private InPlaceConfigExpansionRcHandler(
        BlazeRuntime runtime,
        BlazeWorkspace workspace,
        BlazeCommand command,
        Command commandAnnotation,
        OptionsParser optionsParser,
        InvocationPolicy invocationPolicy) {
      super(runtime, workspace, command, commandAnnotation, optionsParser, invocationPolicy);
    }

    @Override
    void expandConfigOptions(
        EventHandler eventHandler, ListMultimap<String, RcChunkOfArgs> commandToRcArgs)
        throws OptionsParsingException {

      OptionValueDescription configValueDescription =
          optionsParser.getOptionValueDescription("config");
      if (configValueDescription == null
          || configValueDescription.getCanonicalInstances() == null) {
        // No --config values were set, we can avoid this whole thing.
        return;
      }

      // Find the base set of configs. This does not include the config options that might be
      // recursively incuded.
      ImmutableList<ParsedOptionDescription> configInstances =
          ImmutableList.copyOf(configValueDescription.getCanonicalInstances());

      // Expand the configs that are mentioned in the input. Flatten these expansions before parsing
      // them, to preserve order.
      for (ParsedOptionDescription configInstance : configInstances) {
        String configValueToExpand = (String) configInstance.getConvertedValue();
        List<String> expansion = getExpansion(eventHandler, commandToRcArgs, configValueToExpand);
        optionsParser.parseArgsFixedAsExpansionOfOption(
            configInstance, String.format("expanded from --%s", configValueToExpand), expansion);
      }

      // At this point, we've expanded everything, identify duplicates, if any, to warn about
      // re-application.
      List<String> configs = optionsParser.getOptions(CommonCommandOptions.class).configs;
      Set<String> configSet = new HashSet<>();
      LinkedHashSet<String> duplicateConfigs = new LinkedHashSet<>();
      for (String configValue : configs) {
        if (!configSet.add(configValue)) {
          duplicateConfigs.add(configValue);
        }
      }
      if (!duplicateConfigs.isEmpty()) {
        eventHandler.handle(Event.warn(
            String.format(
                "The following configs were expanded more than once: %s. For repeatable flags, "
                    + "repeats are counted twice and may lead to unexpected behavior.",
                duplicateConfigs)));
      }
    }

    private List<String> getExpansion(
        EventHandler eventHandler,
        ListMultimap<String, RcChunkOfArgs> commandToRcArgs,
        String configToExpand)
        throws OptionsParsingException {
      LinkedHashSet<String> configAncestorSet = new LinkedHashSet<>();
      configAncestorSet.add(configToExpand);
      List<String> longestChain = new ArrayList<>();
      List<String> finalExpansion =
          getExpansion(
              eventHandler, commandToRcArgs, configAncestorSet, configToExpand, longestChain);

      // In order to prevent warning about a long chain of 13 configs at the 10, 11, 12, and 13
      // point, we identify the longest chain for this 'high-level' --config found and only warn
      // about it once. This may mean we missed a fork where each branch was independently long
      // enough to warn, but the single warning should convey the message reasonably.
      if (longestChain.size() >= 10) {
        eventHandler.handle(
            Event.warn(
                String.format(
                    "There is a recursive chain of configs %s configs long: %s. This seems "
                        + "excessive, and might be hiding errors.",
                    longestChain.size(), longestChain)));
      }
      return finalExpansion;
    }

    /**
     * @param configAncestorSet is the chain of configs that have led to this one getting expanded.
     *     This should only contain the configs that expanded, recursively, to this one, and should
     *     not contain "siblings," as it is used to detect cycles. {@code build:foo --config=bar},
     *     {@code build:bar --config=foo}, is a cycle, detected because this list will be [foo, bar]
     *     when we find another 'foo' to expand. However, {@code build:foo --config=bar}, {@code
     *     build:foo --config=bar} is not a cycle just because bar is expanded twice, and the 1st
     *     bar should not be in the parents list of the second bar.
     * @param longestChain will be populated with the longest inheritance chain of configs.
     */
    private List<String> getExpansion(
        EventHandler eventHandler,
        ListMultimap<String, RcChunkOfArgs> commandToRcArgs,
        LinkedHashSet<String> configAncestorSet,
        String configToExpand,
        List<String> longestChain)
        throws OptionsParsingException {
      List<String> expansion = new ArrayList<>();
      boolean foundDefinition = false;
      // The expansion order of rc files is first by command priority, and then in the order the
      // rc files were read, respecting import statement placement.
      for (String commandToParse : getCommandNamesToParse(commandAnnotation)) {
        String configDef = commandToParse + ":" + configToExpand;
        for (RcChunkOfArgs rcArgs : commandToRcArgs.get(configDef)) {
          foundDefinition = true;
          rcfileNotes.add(
              String.format(
                  "Found applicable config definition %s in file %s: %s",
                  configDef, rcArgs.rcFile, String.join(" ", rcArgs.args)));

          // For each arg in the rcARgs chunk, we first check if it is a config, and if so, expand
          // it in place. We avoid cycles by tracking the parents of this config.
          for (String arg : rcArgs.args) {
            expansion.add(arg);
            if (arg.length() >= 8 && arg.substring(0, 8).equals("--config")) {
              // We have a config. For sanity, because we don't want to worry about formatting,
              // we will only accept --config=value, and will not accept value on a following line.
              int charOfConfigValue = arg.indexOf('=');
              if (charOfConfigValue < 0) {
                throw new OptionsParsingException("Config flag was provided without a value.");
              }
              String newConfigValue = arg.substring(charOfConfigValue + 1);
              LinkedHashSet<String> extendedConfigAncestorSet =
                  new LinkedHashSet<>(configAncestorSet);
              if (!extendedConfigAncestorSet.add(newConfigValue)) {
                throw new OptionsParsingException(
                    String.format(
                        "Config expansion has a cycle: config value %s expands to itself, "
                            + "see inheritance chain %s",
                        newConfigValue, extendedConfigAncestorSet));
              }
              if (extendedConfigAncestorSet.size() > longestChain.size()) {
                longestChain.clear();
                longestChain.addAll(extendedConfigAncestorSet);
              }

              expansion.addAll(
                  getExpansion(
                      eventHandler,
                      commandToRcArgs,
                      extendedConfigAncestorSet,
                      newConfigValue,
                      longestChain));
            }
          }
        }
      }

      if (!foundDefinition) {
        String warning = "Config value " + configToExpand + " is not defined in any .rc file";
        CommonCommandOptions commonOptions = optionsParser.getOptions(CommonCommandOptions.class);
        if (commonOptions.allowUndefinedConfigs) {
          eventHandler.handle(Event.warn(warning));
        } else {
          throw new OptionsParsingException(warning);
        }
      }
      return expansion;
    }
  }

  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 String getNotInRealWorkspaceError(Path doNotBuildFile) {
    String message =
        String.format(
            "%1$s should not be called from a %1$s output directory. ", runtime.getProductName());
    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;
  }

  /**
   * We receive the rc file arguments from the client in an order that maintains the location of
   * "import" statements, expanding the imported rc file in place so that its args override previous
   * args in the file and are overridden by later arguments. We cannot group the args by rc file for
   * parsing, as we would lose this ordering, so we store them in these "chunks."
   *
   * <p>Each chunk comes from a single rc file, but the args stored here may not contain the entire
   * file if its contents were interrupted by an import statement.
   */
  static class RcChunkOfArgs {
    public RcChunkOfArgs(String rcFile, List<String> args) {
      this.rcFile = rcFile;
      this.args = args;
    }

    // The name of the rc file, usually a path.
    String rcFile;
    // The list of arguments specified in this rc "chunk". This is all for a single command (or
    // command:config definition), as different commands will be grouped together, so this list of
    // arguments can all be parsed as a continuous group.
    List<String> args;

    @Override
    public boolean equals(Object o) {
      if (o instanceof RcChunkOfArgs) {
        RcChunkOfArgs other = (RcChunkOfArgs) o;
        return rcFile.equals(other.rcFile) && args.equals(other.args);
      }
      return false;
    }

    @Override
    public int hashCode() {
      return rcFile.hashCode() + args.hashCode();
    }
  }

  /**
   * The rc options are passed via {@link ClientOptions#optionsOverrides} and {@link
   * ClientOptions#rcSource}, which is basically a line-by-line transfer of the rc files read by the
   * client. This is not a particularly useful format for expanding the options, so this method
   * structures the list so that it is easier to find the arguments that apply to a command, or to
   * find the definitions of a config value.
   */
  @VisibleForTesting
  static ListMultimap<String, RcChunkOfArgs> structureRcOptionsAndConfigs(
      EventHandler eventHandler,
      List<String> rcFiles,
      List<ClientOptions.OptionOverride> rawOverrides,
      Set<String> validCommands) {
    ListMultimap<String, RcChunkOfArgs> commandToRcArgs = ArrayListMultimap.create();

    String lastRcFile = null;
    ListMultimap<String, String> commandToArgMapForLastRc = null;
    for (ClientOptions.OptionOverride override : rawOverrides) {
      if (override.blazeRc < 0 || override.blazeRc >= rcFiles.size()) {
        eventHandler.handle(
            Event.warn("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")) {
        eventHandler.handle(
            Event.warn(
                "while reading option defaults file '"
                    + rcFile
                    + "':\n"
                    + "  invalid command name '"
                    + override.command
                    + "'."));
        continue;
      }

      // We've moved on to another rc file "chunk," store the accumulated args from the last one.
      if (!rcFile.equals(lastRcFile)) {
        if (lastRcFile != null) {
          // Go through the various commands identified in this rc file (or chunk of file) and
          // store them grouped first by command, then by rc chunk.
          for (String commandKey : commandToArgMapForLastRc.keySet()) {
            commandToRcArgs.put(
                commandKey,
                new RcChunkOfArgs(lastRcFile, commandToArgMapForLastRc.get(commandKey)));
          }
        }
        lastRcFile = rcFile;
        commandToArgMapForLastRc = ArrayListMultimap.create();
      }

      commandToArgMapForLastRc.put(override.command, override.option);
    }
    if (lastRcFile != null) {
      // Once again, for this last rc file chunk, store them grouped by command.
      for (String commandKey : commandToArgMapForLastRc.keySet()) {
        commandToRcArgs.put(
            commandKey, new RcChunkOfArgs(lastRcFile, commandToArgMapForLastRc.get(commandKey)));
      }
    }

    return commandToRcArgs;
  }
}
