/*
 * Copyright 2019-present Facebook, Inc.
 *
 * 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.facebook.buck.cli;

import com.facebook.buck.cli.MainRunner.KnownRuleTypesFactoryFactory;
import com.facebook.buck.core.model.BuildId;
import com.facebook.buck.core.module.BuckModuleManager;
import com.facebook.buck.core.module.impl.BuckModuleJarHashProvider;
import com.facebook.buck.core.module.impl.DefaultBuckModuleManager;
import com.facebook.buck.core.plugin.impl.BuckPluginManagerFactory;
import com.facebook.buck.core.rules.knowntypes.DefaultKnownRuleTypesFactory;
import com.facebook.buck.support.bgtasks.BackgroundTaskManager;
import com.facebook.buck.util.Ansi;
import com.facebook.buck.util.AnsiEnvironmentChecking;
import com.facebook.buck.util.Console;
import com.facebook.buck.util.Verbosity;
import com.facebook.buck.util.environment.CommandMode;
import com.facebook.buck.util.environment.Platform;
import com.facebook.nailgun.NGContext;
import com.google.common.collect.ImmutableMap;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
import org.pf4j.PluginManager;

/**
 * The abstract entry point of Buck commands for both {@link MainWithoutNailgun} and {@link
 * MainWithNailgun}
 */
abstract class AbstractMain {

  private static final String BUCK_BUILD_ID_ENV_VAR = "BUCK_BUILD_ID";
  private static PluginManager pluginManager;
  private static BuckModuleManager moduleManager;

  static {
    pluginManager = BuckPluginManagerFactory.createPluginManager();
    moduleManager = new DefaultBuckModuleManager(pluginManager, new BuckModuleJarHashProvider());
  }

  protected final InputStream stdIn;

  protected final ImmutableMap<String, String> clientEnvironment;
  protected final Platform platform;

  private final Optional<NGContext> optionalNGContext; // TODO(bobyf): remove this dependency.
  private final Console defaultConsole;
  private final CommandMode commandMode;

  protected AbstractMain(
      PrintStream stdOut,
      PrintStream stdErr,
      InputStream stdIn,
      ImmutableMap<String, String> clientEnvironment,
      Platform platform,
      Optional<NGContext> ngContext) {
    this(
        new Console(
            Verbosity.STANDARD_INFORMATION,
            stdOut,
            stdErr,
            new Ansi(
                AnsiEnvironmentChecking.environmentSupportsAnsiEscapes(
                    platform, clientEnvironment))),
        stdIn,
        clientEnvironment,
        platform,
        CommandMode.RELEASE,
        ngContext);
  }

  protected AbstractMain(
      Console console,
      InputStream stdIn,
      ImmutableMap<String, String> clientEnvironment,
      Platform platform,
      CommandMode commandMode,
      Optional<NGContext> ngContext) {
    this.stdIn = stdIn;

    this.clientEnvironment = clientEnvironment;
    this.platform = platform;
    this.optionalNGContext = ngContext;
    this.commandMode = commandMode;
    this.defaultConsole = console;
  }

  /**
   * @return an initialized {@link MainRunner} for running the buck command, with all the base state
   *     setup.
   */
  protected MainRunner prepareMainRunner(BackgroundTaskManager bgTaskManager) {

    return new MainRunner(
        defaultConsole,
        stdIn,
        getKnownRuleTypesFactory(),
        getBuildId(),
        clientEnvironment,
        platform,
        pluginManager,
        moduleManager,
        bgTaskManager,
        commandMode,
        optionalNGContext);
  }

  protected KnownRuleTypesFactoryFactory getKnownRuleTypesFactory() {
    return DefaultKnownRuleTypesFactory::new;
  }

  protected BuildId getBuildId() {
    @Nullable String specifiedBuildId = clientEnvironment.get(BUCK_BUILD_ID_ENV_VAR);
    if (specifiedBuildId == null) {
      specifiedBuildId = UUID.randomUUID().toString();
    }
    return new BuildId(specifiedBuildId);
  }
}

@@ -2504,16 +2504,647 @@
 dMode;%0A%0A
+  /**%0A   * The constructor with certain defaults for use by %7B@link MainWithNailgun%7D and %7B@link%0A   * MainWithoutNailgun%7D. The default %7B@link Console%7D will be constructed from the streams, and the%0A   * command mode is default to %7B@link CommandMode#RELEASE%7D%0A   *%0A   * @param stdOut the output stream for which a %7B@link Console%7D is constructed%0A   * @param stdErr the error output stream for which a %7B@link Console%7D is constructed%0A   * @param stdIn the input stream%0A   * @param clientEnvironment the environment variable mapping for this command%0A   * @param platform the running platform%0A   * @param ngContext the nailgun context%0A   */%0A
   protec
@@ -3157,24 +3157,24 @@
 stractMain(%0A
-
       PrintS
@@ -3723,32 +3723,520 @@
 gContext);%0A  %7D%0A%0A
+  /**%0A   * Constructor without certain defaults for testing, so that the console, repo root can be%0A   * overridden.%0A   *%0A   * @param console the console to use%0A   * @param stdIn the input stream%0A   * @param clientEnvironment the environment variable mapping for this command%0A   * @param platform the current platform%0A   * @param commandMode the %7B@link CommandMode%7D of either %7B@link CommandMode#RELEASE%7D or %7B@link%0A   *     CommandMode#TEST%7D%0A   * @param ngContext the nailgun context%0A   */%0A
   protected Abst
@@ -5155,32 +5155,107 @@
 GContext);%0A  %7D%0A%0A
+  /** @return the %7B@link KnownRuleTypesFactoryFactory%7D for this command */%0A
   protected Know
@@ -5355,24 +5355,156 @@
 ::new;%0A  %7D%0A%0A
+  /**%0A   * @return the inferred %7B@link BuildId%7D from the environment variable or create a new random%0A   *     %7B@link BuildId%7D%0A   */%0A
   protected 

Add some more docs to AbstractMain