// 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 static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
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.flogger.GoogleLogger;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
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.packages.Target;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.Command.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.common.options.Converters;
import com.google.devtools.common.options.InvocationPolicyEnforcer;
import com.google.devtools.common.options.OptionAndRawValue;
import com.google.devtools.common.options.OptionDefinition;
import com.google.devtools.common.options.OptionPriority.PriorityCategory;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import com.google.devtools.common.options.OptionsParsingResult;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
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, configs, default options, and invocation policy.
 */
public final class BlazeOptionHandler {
  private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();

  // 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");

  // All options set on this pseudo command are inherited by all commands, with unrecognized options
  // resulting in an error.
  private static final String ALWAYS_PSEUDO_COMMAND = "always";

  // All options set on this pseudo command are inherited by all commands, with unrecognized options
  // being ignored as long as they are recognized by at least one (other) command.
  private static final String COMMON_PSEUDO_COMMAND = "common";

  private static final ImmutableSet<String> BUILD_COMMAND_ANCESTORS =
      ImmutableSet.of("build", COMMON_PSEUDO_COMMAND, ALWAYS_PSEUDO_COMMAND);

  // Marks an event to indicate a parsing error.
  static final String BAD_OPTION_TAG = "invalidOption";
  // Separates the invalid tag from the full error message for easier parsing.
  static final String ERROR_SEPARATOR = " :: ";

  private final BlazeRuntime runtime;
  private final OptionsParser optionsParser;
  private final BlazeWorkspace workspace;
  private final BlazeCommand command;
  private final Command commandAnnotation;
  private final InvocationPolicy invocationPolicy;
  private final List<String> rcfileNotes = new ArrayList<>();
  private final ImmutableList<Class<? extends OptionsBase>> allOptionsClasses;

  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;
    this.allOptionsClasses =
        runtime.getCommandMap().values().stream()
            .map(BlazeCommand::getClass)
            .flatMap(
                cmd ->
                    BlazeCommandUtils.getOptions(
                        cmd, runtime.getBlazeModules(), runtime.getRuleClassProvider())
                        .stream())
            .distinct()
            .collect(toImmutableList());
  }

  /**
   * Return options as {@link OptionsParsingResult} so the options can't be easily modified after
   * we've applied the invocation policy.
   */
  OptionsParsingResult 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 DetailedExitCode checkCwdInWorkspace(EventHandler eventHandler) {
    if (!commandAnnotation.mustRunInWorkspace()) {
      return DetailedExitCode.success();
    }

    if (!workspace.getDirectories().inWorkspace()) {
      String message =
          "The '"
              + commandAnnotation.name()
              + "' command is only supported from within a workspace"
              + " (below a directory having a WORKSPACE file).\n"
              + "See documentation at"
              + " https://bazel.build/concepts/build-ref#workspace";
      eventHandler.handle(Event.error(message));
      return createDetailedExitCode(message, Code.NOT_IN_WORKSPACE);
    }

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

    if (workspacePath.getParentDirectory() != null) {
      Path doNotBuild =
          workspacePath.getParentDirectory().getRelative(BlazeWorkspace.DO_NOT_BUILD_FILE_NAME);

      if (doNotBuild.exists()) {
        String message = getNotInRealWorkspaceError(doNotBuild);
        eventHandler.handle(Event.error(message));
        return createDetailedExitCode(message, Code.IN_OUTPUT_DIRECTORY);
      }
    }
    return DetailedExitCode.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 primary rc file first,
   * and follows import statements. This is the order in which they were passed by the client.
   */
  @VisibleForTesting
  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.getArgs().isEmpty()) {
          String inherited = commandToParse.equals(commandAnnotation.name()) ? "" : "Inherited ";
          String source =
              rcArgs.getRcFile().equals("client")
                  ? "Options provided by the client"
                  : String.format(
                      "Reading rc options for '%s' from %s",
                      commandAnnotation.name(), rcArgs.getRcFile());
          rcfileNotes.add(
              String.format(
                  "%s:\n  %s'%s' options: %s",
                  source, inherited, commandToParse, Joiner.on(' ').join(rcArgs.getArgs())));
        }
        if (commandToParse.equals(COMMON_PSEUDO_COMMAND)) {
          // Pass in options data for all commands supported by the runtime so that options that
          // apply to some but not the current command can be ignored.
          //
          // Important note: The consistency checks performed by
          // OptionsParser#getFallbackOptionsData ensure that there aren't any two options across
          // all commands that have the same name but parse differently (e.g. because one accepts
          // a value and the other doesn't). This means that the options available on a command
          // limit the options available on other commands even without command inheritance. This
          // restriction is necessary to ensure that the options specified on the "common"
          // pseudo command can be parsed unambiguously.
          ImmutableList<String> ignoredArgs =
              optionsParser.parseWithSourceFunction(
                  PriorityCategory.RC_FILE,
                  o -> rcArgs.getRcFile(),
                  rcArgs.getArgs(),
                  OptionsParser.getFallbackOptionsData(allOptionsClasses));
          if (!ignoredArgs.isEmpty()) {
            // Append richer information to the note.
            int index = rcfileNotes.size() - 1;
            String note = rcfileNotes.get(index);
            note +=
                String.format(
                    "\n  Ignored as unsupported by '%s': %s",
                    commandAnnotation.name(), Joiner.on(' ').join(ignoredArgs));
            rcfileNotes.set(index, note);
          }
        } else {
          optionsParser.parse(PriorityCategory.RC_FILE, rcArgs.getRcFile(), rcArgs.getArgs());
        }
      }
    }
  }

  private void parseArgsAndConfigs(List<String> args, ExtendedEventHandler eventHandler)
      throws OptionsParsingException, InterruptedException, AbruptExitException {
    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());

    // Before parsing any rcfiles we need to first parse --rc_source so the parser can reference the
    // proper rcfiles. The --default_override options should be parsed with the --rc_source since
    // {@link #parseRcOptions} depends on the list populated by the {@link
    // ClientOptions#OptionOverrideConverter}.
    ImmutableList.Builder<String> defaultOverridesAndRcSources = new ImmutableList.Builder<>();
    ImmutableList.Builder<String> remainingCmdLine = new ImmutableList.Builder<>();
    partitionCommandLineArgs(cmdLineAfterCommand, defaultOverridesAndRcSources, remainingCmdLine);

    // Parses options needed to parse rcfiles properly.
    optionsParser.parseWithSourceFunction(
        PriorityCategory.COMMAND_LINE,
        commandOptionSourceFunction,
        defaultOverridesAndRcSources.build(),
        /* fallbackData= */ null);

    // 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);

    // Parses the remaining command-line options.
    optionsParser.parseWithSourceFunction(
        PriorityCategory.COMMAND_LINE,
        commandOptionSourceFunction,
        remainingCmdLine.build(),
        /* fallbackData= */ null);

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

    expandConfigOptions(eventHandler, commandToRcArgs);
  }

  /**
   * {@link ExtendedEventHandler} override that passes through "normal" events but not events that
   * would go to the build event proto.
   *
   * <p>Starlark flags are conceptually options but still need target pattern evaluation. If we pass
   * {@link #post}able events from that evaluation, that would produce "target loaded" and "target
   * configured" events in the build event proto output that consumers can confuse with actual
   * targets requested by the build.
   *
   * <p>This is important because downstream services (like a continuous integration tool or build
   * results dashboard) read these messages to reconcile which requested targets were built. If they
   * determine Blaze tried to build {@code //foo //bar} then see a "target configured" message for
   * some other target {@code //my_starlark_flag}, they might show misleading messages like "Built 3
   * of 2 requested targets.".
   *
   * <p>Hence this class. By dropping those events, we restrict all info and error reporting logic
   * to the options parsing pipeline.
   */
  private static class NonPostingEventHandler implements ExtendedEventHandler {
    private final ExtendedEventHandler delegate;

    NonPostingEventHandler(ExtendedEventHandler delegate) {
      this.delegate = delegate;
    }

    @Override
    public void handle(Event e) {
      delegate.handle(e);
    }

    @Override
    public void post(ExtendedEventHandler.Postable e) {}
  }

  /**
   * Lets {@link StarlarkOptionsParser} convert flag names to {@link Target}s through {@link
   * TargetPatternPhaseValue}.
   *
   * <p>This is used for top-level flag parsing, outside any {@link SkyFunction}.
   */
  public static class SkyframeExecutorTargetLoader
      implements StarlarkOptionsParser.BuildSettingLoader {
    private final SkyframeExecutor skyframeExecutor;
    private final PathFragment relativeWorkingDirectory;
    private final ExtendedEventHandler reporter;

    public SkyframeExecutorTargetLoader(CommandEnvironment env) {
      this.skyframeExecutor = env.getSkyframeExecutor();
      this.relativeWorkingDirectory = env.getRelativeWorkingDirectory();
      this.reporter = new NonPostingEventHandler(env.getReporter());
    }

    @VisibleForTesting
    public SkyframeExecutorTargetLoader(
        SkyframeExecutor skyframeExecutor,
        PathFragment relativeWorkingDirectory,
        ExtendedEventHandler reporter) {
      this.skyframeExecutor = skyframeExecutor;
      this.relativeWorkingDirectory = relativeWorkingDirectory;
      this.reporter = new NonPostingEventHandler(reporter);
    }

    @Override
    public Target loadBuildSetting(String targetLabel)
        throws InterruptedException, TargetParsingException {
      TargetPatternPhaseValue tpv =
          skyframeExecutor.loadTargetPatternsWithoutFilters(
              reporter,
              Collections.singletonList(targetLabel),
              relativeWorkingDirectory,
              SkyframeExecutor.DEFAULT_THREAD_COUNT,
              /* keepGoing= */ false);
      ImmutableSet<Target> result = tpv.getTargets(reporter, skyframeExecutor.getPackageManager());
      if (result.size() != 1) {
        throw new TargetParsingException(
            "user-defined flags must reference exactly one target",
            TargetPatterns.Code.TARGET_FORMAT_INVALID);
      }
      return Iterables.getOnlyElement(result);
    }
  }

  /**
   * TODO(bazel-team): When we move CoreOptions options to be defined in starlark, make sure they're
   * not passed in here during {@link #getOptionsResult}.
   */
  DetailedExitCode parseStarlarkOptions(CommandEnvironment env) {
    // For now, restrict starlark options to commands that already build to ensure that loading
    // will work. We may want to open this up to other commands in the future. The "info"
    // and "clean" commands have builds=true set in their annotation but don't actually do any
    // building (b/120041419).
    if (!commandAnnotation.builds()
        || commandAnnotation.name().equals("info")
        || commandAnnotation.name().equals("clean")) {
      return DetailedExitCode.success();
    }
    try {
      Preconditions.checkState(
          StarlarkOptionsParser.newStarlarkOptionsParser(
                  new SkyframeExecutorTargetLoader(env), optionsParser)
              .parse());
    } catch (OptionsParsingException e) {
      String logMessage = "Error parsing Starlark options";
      logger.atInfo().withCause(e).log("%s", logMessage);
      return processOptionsParsingException(
          env.getReporter(), e, logMessage, Code.STARLARK_OPTIONS_PARSE_FAILURE);
    }
    return DetailedExitCode.success();
  }

  /**
   * Parses the options, taking care not to generate any output to outErr, return, or throw an
   * exception.
   *
   * @return {@code DetailedExitCode.success()} if everything went well, or some other value if not
   */
  DetailedExitCode parseOptions(
      List<String> args,
      ExtendedEventHandler eventHandler,
      ImmutableList.Builder<OptionAndRawValue> invocationPolicyFlagListBuilder) {
    DetailedExitCode result =
        parseOptionsInternal(args, eventHandler, invocationPolicyFlagListBuilder);
    if (!result.isSuccess()) {
      optionsParser.setError();
    }
    return result;
  }

  private DetailedExitCode parseOptionsInternal(
      List<String> args,
      ExtendedEventHandler eventHandler,
      ImmutableList.Builder<OptionAndRawValue> invocationPolicyFlagListBuilder) {
    // 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.
    DetailedExitCode earlyExitCode = checkCwdInWorkspace(eventHandler);
    if (!earlyExitCode.isSuccess()) {
      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) {
        eventHandler.handle(
            Event.error(
                "--watchfs as startup option is deprecated, replace it with the equivalent command "
                    + "option. For example, instead of 'bazel --watchfs build //foo', run "
                    + "'bazel build --watchfs //foo'."));
        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, optionsParser.getConversionContext());
      // 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(), invocationPolicyFlagListBuilder);
      // 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) {
      String logMessage = "Error parsing options";
      logger.atInfo().withCause(e).log("%s", logMessage);
      return processOptionsParsingException(
          eventHandler, e, logMessage, Code.OPTIONS_PARSE_FAILURE);
    } catch (InterruptedException e) {
      return DetailedExitCode.of(
          FailureDetail.newBuilder()
              .setInterrupted(
                  FailureDetails.Interrupted.newBuilder()
                      .setCode(FailureDetails.Interrupted.Code.INTERRUPTED))
              .build());
    } catch (AbruptExitException e) {
      return e.getDetailedExitCode();
    }
    return DetailedExitCode.success();
  }

  /**
   * Expand the values of --config according to the definitions provided in the rc files and the
   * applicable command.
   */
  @VisibleForTesting
  void expandConfigOptions(
      EventHandler eventHandler, ListMultimap<String, RcChunkOfArgs> commandToRcArgs)
      throws OptionsParsingException {
    ConfigExpander.expandConfigOptions(
        eventHandler,
        commandToRcArgs,
        commandAnnotation.name(),
        getCommandNamesToParse(commandAnnotation),
        rcfileNotes::add,
        optionsParser,
        OptionsParser.getFallbackOptionsData(allOptionsClasses));
  }

  private static List<String> getCommandNamesToParse(Command commandAnnotation) {
    List<String> result = new ArrayList<>();
    result.add(ALWAYS_PSEUDO_COMMAND);
    result.add(COMMON_PSEUDO_COMMAND);
    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 static DetailedExitCode processOptionsParsingException(
      ExtendedEventHandler eventHandler,
      OptionsParsingException e,
      String logMessage,
      Code failureCode) {
    Event error;
    // Differentiates errors stemming from an invalid argument and errors from different parts of
    // the codebase.
    if (e.getInvalidArgument() != null) {
      error =
          Event.error(e.getInvalidArgument() + ERROR_SEPARATOR + e.getMessage())
              .withTag(BAD_OPTION_TAG);
    } else {
      error = Event.error(e.getMessage());
    }
    eventHandler.handle(error);
    return createDetailedExitCode(logMessage + ": " + e.getMessage(), failureCode);
  }

  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;
  }

  /**
   * 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)
      throws OptionsParsingException {
    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);
      // The canonicalize-flags command only inherits bazelrc "build" commands. Not "test", not
      // "build:foo". Restrict --flag_alias accordingly to prevent building with flags that
      // canonicalize-flags can't recognize.
      if ((override.option.startsWith("--" + Converters.BLAZE_ALIASING_FLAG + "=")
              || override.option.equals("--" + Converters.BLAZE_ALIASING_FLAG))
          && !BUILD_COMMAND_ANCESTORS.contains(override.command)) {
        throw new OptionsParsingException(
            String.format(
                "%s: \"%s %s\" disallowed. --%s only supports these commands: %s",
                rcFile,
                override.command,
                override.option,
                Converters.BLAZE_ALIASING_FLAG,
                String.join(", ", BUILD_COMMAND_ANCESTORS)));
      }
      String command = override.command;
      int index = command.indexOf(':');
      if (index > 0) {
        command = command.substring(0, index);
      }
      if (!validCommands.contains(command)
          && !command.equals(ALWAYS_PSEUDO_COMMAND)
          && !command.equals(COMMON_PSEUDO_COMMAND)) {
        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;
  }

  private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
    return DetailedExitCode.of(
        FailureDetail.newBuilder()
            .setMessage(message)
            .setCommand(FailureDetails.Command.newBuilder().setCode(detailedCode))
            .build());
  }

  private static void partitionCommandLineArgs(
      List<String> cmdLine,
      ImmutableList.Builder<String> defaultOverridesAndRcSources,
      ImmutableList.Builder<String> remainingCmdLine) {

    Iterator<String> cmdLineIterator = cmdLine.iterator();

    while (cmdLineIterator.hasNext()) {
      String option = cmdLineIterator.next();
      if (option.startsWith("--rc_source=") || option.startsWith("--default_override=")) {
        defaultOverridesAndRcSources.add(option);
      } else if (option.equals("--rc_source") || option.equals("--default_override")) {
        Optional<String> possibleArgument =
            cmdLineIterator.hasNext() ? Optional.of(cmdLineIterator.next()) : Optional.empty();
        defaultOverridesAndRcSources.add(option);
        if (possibleArgument.isPresent()) {
          defaultOverridesAndRcSources.add(possibleArgument.get());
        }
      } else {
        remainingCmdLine.add(option);
      }
    }
  }
}
