Main类中main方法调用mainEntry方法,mainEntry中对命令行参数进行解析,再执行runCommandLineProgram(program, args); runCommandLineProgram方法中执行 program.instanceMain(mainArgs); program 是 CommandLineProgram 实例,方法调用关系为:instanceMain <- instanceMainPostParseArgs <- runTool <- doWork
Main类源码
package org.broadinstitute.hellbender;
import com.google.cloud.storage.StorageException;
import htsjdk.samtools.util.StringUtil;
import org.broadinstitute.barclay.argparser.*;
import org.broadinstitute.hellbender.cmdline.*;
import org.broadinstitute.hellbender.exceptions.PicardNonZeroExitException;
import org.broadinstitute.hellbender.exceptions.UserException;
import org.broadinstitute.hellbender.utils.ClassUtils;
import org.broadinstitute.hellbender.utils.Utils;
import org.broadinstitute.hellbender.utils.config.ConfigFactory;
import org.broadinstitute.hellbender.utils.runtime.RuntimeUtils;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* This is the main class of Hellbender and is the way of executing individual command line programs.
*
* CommandLinePrograms are listed in a single command line interface based on the java package specified to instanceMain.
*
* If you want your own single command line program, extend this class and override if required:
*
* - {@link #getPackageList()} to return a list of java packages in which to search for classes that extend CommandLineProgram.
* - {@link #getClassList()} to return a list of single classes to include (e.g. required input pre-processing tools).
* - {@link #getCommandLineName()} for the name of the toolkit.
* - {@link #handleResult(Object)} for handle the result of the tool.
* - {@link #handleNonUserException(Exception)} for handle non {@link UserException}.
* - {@link #parseArgsForConfigSetup(String[])} for pulling command-line configuration options out and initializing the {@link org.broadinstitute.hellbender.utils.config.GATKConfig}
*
* Note: If any of the previous methods was overrided, {@link #main(String[])} should be implemented to instantiate your class
* and call {@link #mainEntry(String[])} to make the changes effective.
*/
public class Main {
static {
/**
* The very first thing that any GATK application does is forces the JVM locale into US English, so that we don't have
* to think about number formatting issues.
*/
Utils.forceJVMLocaleToUSEnglish();
// Turn off the Picard legacy parser and opt in to Barclay syntax for Picard tools. This should be replaced
// with a config setting once PR https://github.com/broadinstitute/gatk/pull/3447 is merged.
System.setProperty("picard.useLegacyParser", "false");
}
/**
* Provides ANSI colors for the terminal output *
*/
private static final String KNRM = "\u001B[0m"; // reset
private static final String RED = "\u001B[31m";
private static final String GREEN = "\u001B[32m";
private static final String CYAN = "\u001B[36m";
private static final String WHITE = "\u001B[37m";
private static final String BOLDRED = "\u001B[1m\u001B[31m";
/**
* exit value when an issue with the commandline is detected, ie CommandLineException.
* This is the same value as picard uses.
*/
private static final int COMMANDLINE_EXCEPTION_EXIT_VALUE = 1;
/**
* Exit value when an unrecoverable {@link UserException} occurs.
*/
public static final int USER_EXCEPTION_EXIT_VALUE = 2;
/**
* Exit value used when a Picard tool returns a non-zero exit code (the actual value is displayed on the command line)
*/
public static final int PICARD_TOOL_EXCEPTION = 4;
/**
* exit value when any unrecoverable exception other than {@link UserException} occurs
*/
private static final int ANY_OTHER_EXCEPTION_EXIT_VALUE = 3;
/**
* exit value when an out of memory error occurs
*/
private static final int OUT_OF_MEMORY_EXIT_VALUE = 137;
private static final String STACK_TRACE_ON_USER_EXCEPTION_PROPERTY = "GATK_STACKTRACE_ON_USER_EXCEPTION";
/**
* Prints the given message (may be null) to the provided stream, adding adornments and formatting.
*/
protected static void printDecoratedExceptionMessage(final PrintStream ps, final Exception e, String prefix){
Utils.nonNull(ps, "stream");
Utils.nonNull(e, "exception");
ps.println("***********************************************************************");
ps.println();
ps.println(prefix + e.getMessage());
ps.println();
ps.println("***********************************************************************") ;
}
/**
* The packages we wish to include in our command line.
*/
protected List<String> getPackageList() {
final List<String> packageList = new ArrayList<>();
packageList.addAll(Arrays.asList("org.broadinstitute.hellbender"));
packageList.addAll(Arrays.asList("picard"));
return packageList;
}
/**
* Reads from the given command-line arguments, pulls out configuration options,
* and initializes the configuration for this instance of Main.
*
* Suggested use for this is to handle downstream project configuration options and overrides.
* For example this would allow:
*
* Custom command-line arguments for use in tools
* Custom config file loading and initialization
*/
protected void parseArgsForConfigSetup(final String[] args) {
ConfigFactory.getInstance().initializeConfigurationsFromCommandLineArgs(args, "--" + StandardArgumentDefinitions.GATK_CONFIG_FILE_OPTION);
}
/**
* The single classes we wish to include in our command line.
*/
protected List<Class<? extends CommandLineProgram>> getClassList() {
return Collections.emptyList();
}
/** Returns the command line that will appear in the usage. */
protected String getCommandLineName() {
return "";
}
/**
* The main method.
* <p/>
* Give a list of java packages in which to search for classes that extend CommandLineProgram and a list of single CommandLineProgram classes.
* Those will be included on the command line.
*
* This method is not intended to be used outside of the GATK framework and tests.
*
*/
public Object instanceMain(final String[] args, final List<String> packageList, final List<Class<? extends CommandLineProgram>> classList, final String commandLineName) {
final CommandLineProgram program = setupConfigAndExtractProgram(args, packageList, classList, commandLineName);
return runCommandLineProgram(program, args);
}
/**
* Run the given command line program with the raw arguments from the command line
* @param rawArgs these are the raw arguments from the command line, the first will be stripped off
* @return the result of running {program} with the given args, possibly null
*/
protected static Object runCommandLineProgram(final CommandLineProgram program, final String[] rawArgs) {
if (null == program) return null; // no program found! This will happen if help was specified with no other arguments
// we can lop off the first two arguments but it requires an array copy or alternatively we could update CLP to remove them
// in the constructor do the former in this implementation.
final String[] mainArgs = Arrays.copyOfRange(rawArgs, 1, rawArgs.length);
return program.instanceMain(mainArgs);
}
/**
* Set up the configuration file store and create the {@link CommandLineProgram} to run.
* @param args Argument array passed into this invocation of {@link Main}.
* @param packageList List of packages to include in the command-line.
* @param classList List of single classes to include in the command-line.
* @param commandLineName The command-line name as it appears in the usage.
* @return The {@link CommandLineProgram} to run from this invocation of {@link Main}.
*/
protected CommandLineProgram setupConfigAndExtractProgram(final String[] args,
final List<String> packageList,
final List<Class<? extends CommandLineProgram>> classList,
final String commandLineName ){
// Parse our config file path from our arguments and initialize the configuration file.
// Note: this must be here because the command-line invocation inserts into here:
parseArgsForConfigSetup(args);
// Get our command-line program:
return extractCommandLineProgram(args, packageList, classList, commandLineName);
}
/**
* This method is not intended to be used outside of the GATK framework and tests.
*/
public Object instanceMain(final String[] args) {
return instanceMain(args, getPackageList(), getClassList(), getCommandLineName());
}
/**
* The entry point to the toolkit from commandline: it uses {@link #instanceMain(String[])} to run the command line
* program and handle the returned object with {@link #handleResult(Object)}, and exit with 0.
* If any error occurs, it handles the exception (if non-user exception, through {@link #handleNonUserException(Exception)})
* and exit with the concrete error exit value.
*
* Note: this is the only method that is allowed to call System.exit (because gatk tools may be run from test harness etc)
*/
protected final void mainEntry(final String[] args) {
CommandLineProgram program = null;
try {
program = setupConfigAndExtractProgram(args, getPackageList(), getClassList(), getCommandLineName());
final Object result = runCommandLineProgram(program, args);
handleResult(result);
//no explicit System.exit(0) since that causes issues when running in Yarn containers
} catch (final CommandLineException e){
if (program != null) {
System.err.println(program.getUsage());
}
handleUserException(e);
System.exit(COMMANDLINE_EXCEPTION_EXIT_VALUE);
} catch (final PicardNonZeroExitException e) {