diff --git a/build.xml b/build.xml index 2f7880c1b..9c1b5027f 100644 --- a/build.xml +++ b/build.xml @@ -98,7 +98,7 @@ - diff --git a/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java b/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java index 3ce684f0c..7cc0451df 100755 --- a/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java +++ b/java/src/org/broadinstitute/sting/gatk/CommandLineGATK.java @@ -2,6 +2,7 @@ package org.broadinstitute.sting.gatk; import org.broadinstitute.sting.utils.GATKErrorReport; import org.broadinstitute.sting.utils.TextFormattingUtils; +import org.broadinstitute.sting.utils.help.ApplicationDetails; import org.broadinstitute.sting.utils.cmdLine.*; import org.broadinstitute.sting.gatk.walkers.Walker; diff --git a/java/src/org/broadinstitute/sting/gatk/WalkerManager.java b/java/src/org/broadinstitute/sting/gatk/WalkerManager.java index 6d633035f..4f5162697 100755 --- a/java/src/org/broadinstitute/sting/gatk/WalkerManager.java +++ b/java/src/org/broadinstitute/sting/gatk/WalkerManager.java @@ -35,7 +35,7 @@ import org.broadinstitute.sting.gatk.refdata.ReferenceOrderedData; import org.broadinstitute.sting.gatk.filters.FilterManager; import org.broadinstitute.sting.utils.StingException; import org.broadinstitute.sting.utils.PluginManager; -import org.broadinstitute.sting.utils.doc.DisplayNameTaglet; +import org.broadinstitute.sting.utils.help.DisplayNameTaglet; import org.apache.log4j.Logger; import net.sf.picard.filter.SamRecordFilter; diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitionGroup.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitionGroup.java new file mode 100644 index 000000000..8d2c761da --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitionGroup.java @@ -0,0 +1,64 @@ +package org.broadinstitute.sting.utils.cmdLine; + +import org.broadinstitute.sting.utils.StingException; + +import java.util.List; +import java.util.Collections; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * A group of argument definitions. + */ +public class ArgumentDefinitionGroup implements Iterable { + /** + * Name of this group. + */ + public final String groupName; + + /** + * The argument definitions associated with this group. + */ + public final List argumentDefinitions; + + public ArgumentDefinitionGroup( String groupName, List argumentDefinitions ) { + this.groupName = groupName; + this.argumentDefinitions = Collections.unmodifiableList( argumentDefinitions ); + } + + /** + * Does the name of this argument group match the name of another? + */ + public boolean groupNameMatches( ArgumentDefinitionGroup other ) { + if( this.groupName == null && other.groupName == null ) + return true; + if( this.groupName == null && other.groupName != null ) + return false; + return this.groupName.equals(other.groupName); + } + + /** + * Merges another argument group into this argument group. Return a new + * group since argument groups are supposed to be immutable. Asserts that + * both argument groups have the same name. + */ + public ArgumentDefinitionGroup merge( ArgumentDefinitionGroup other ) { + if( !groupNameMatches(other) ) + throw new StingException("Unable to merge two argument groups with differing names."); + + // Create a merged definition group. + List mergedDefinitions = new ArrayList(); + mergedDefinitions.addAll(this.argumentDefinitions); + mergedDefinitions.addAll(other.argumentDefinitions); + + return new ArgumentDefinitionGroup(groupName,mergedDefinitions); + } + + /** + * Iterate over the arguments in an argument definition group. + * @return + */ + public Iterator iterator() { + return argumentDefinitions.iterator(); + } +} diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java index 74cb6b6e3..591aac460 100755 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ArgumentDefinitions.java @@ -27,7 +27,7 @@ import java.util.Collections; /** * A collection of argument definitions. */ -class ArgumentDefinitions implements Iterable { +public class ArgumentDefinitions implements Iterable { /** * Backing data set of argument stored by short name and long name. */ @@ -117,7 +117,7 @@ class ArgumentDefinitions implements Iterable { * Return a list of the available argument groups. * @return All the argument groups that have been added. */ - Collection getArgumentDefinitionGroups() { + public Collection getArgumentDefinitionGroups() { return argumentDefinitionGroups; } @@ -171,62 +171,6 @@ class ArgumentDefinitions implements Iterable { }; } -/** - * A group of argument definitions. - */ -class ArgumentDefinitionGroup implements Iterable { - /** - * Name of this group. - */ - public final String groupName; - - /** - * The argument definitions associated with this group. - */ - public final List argumentDefinitions; - - public ArgumentDefinitionGroup( String groupName, List argumentDefinitions ) { - this.groupName = groupName; - this.argumentDefinitions = Collections.unmodifiableList( argumentDefinitions ); - } - - /** - * Does the name of this argument group match the name of another? - */ - public boolean groupNameMatches( ArgumentDefinitionGroup other ) { - if( this.groupName == null && other.groupName == null ) - return true; - if( this.groupName == null && other.groupName != null ) - return false; - return this.groupName.equals(other.groupName); - } - - /** - * Merges another argument group into this argument group. Return a new - * group since argument groups are supposed to be immutable. Asserts that - * both argument groups have the same name. - */ - public ArgumentDefinitionGroup merge( ArgumentDefinitionGroup other ) { - if( !groupNameMatches(other) ) - throw new StingException("Unable to merge two argument groups with differing names."); - - // Create a merged definition group. - List mergedDefinitions = new ArrayList(); - mergedDefinitions.addAll(this.argumentDefinitions); - mergedDefinitions.addAll(other.argumentDefinitions); - - return new ArgumentDefinitionGroup(groupName,mergedDefinitions); - } - - /** - * Iterate over the arguments in an argument definition group. - * @return - */ - public Iterator iterator() { - return argumentDefinitions.iterator(); - } -} - /** * A Comparator-esque interface for finding argument definitions within a collection. */ diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/CommandLineProgram.java b/java/src/org/broadinstitute/sting/utils/cmdLine/CommandLineProgram.java index 2f7e4e0ad..20ff5b309 100644 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/CommandLineProgram.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/CommandLineProgram.java @@ -1,12 +1,12 @@ package org.broadinstitute.sting.utils.cmdLine; import org.apache.log4j.*; +import org.broadinstitute.sting.utils.help.ApplicationDetails; +import org.broadinstitute.sting.utils.help.HelpFormatter; import java.io.File; import java.io.IOException; import java.io.PrintStream; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -224,7 +224,7 @@ public abstract class CommandLineProgram { clp.setupLoggerLevel(); // regardless of what happens next, generate the header information - generateHeaderInformation(clp, args); + HelpFormatter.generateHeaderInformation(clp.getApplicationDetails(), args); // call the execute CommandLineProgram.result = clp.execute(); @@ -284,32 +284,6 @@ public abstract class CommandLineProgram { parser.addArgumentSource(clp.getArgumentSourceName(cls), cls); } - /** - * generateHeaderInformation - *

- *

- * Generate a standard header for the logger - * - * @param clp the command line program to execute - * @param args the command line arguments passed in - */ - protected static void generateHeaderInformation(CommandLineProgram clp, String[] args) { - - DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); - java.util.Date date = new java.util.Date(); - - logger.info("-------------------------------------------------------"); - for (String headerLine : clp.getApplicationDetails().applicationHeader) - logger.info(headerLine); - String output = ""; - for (String str : args) { - output = output + str + " "; - } - logger.info("Program Args: " + output); - logger.info("Date/Time: " + dateFormat.format(date)); - logger.info("-------------------------------------------------------"); - } - /** * this function checks the logger level passed in on the command line, taking the lowest * level that was provided. diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java b/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java index 2eeefb29d..92d31ca25 100755 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java +++ b/java/src/org/broadinstitute/sting/utils/cmdLine/ParsingEngine.java @@ -3,6 +3,8 @@ package org.broadinstitute.sting.utils.cmdLine; import org.broadinstitute.sting.utils.StingException; import org.broadinstitute.sting.utils.Pair; import org.broadinstitute.sting.utils.JVMUtils; +import org.broadinstitute.sting.utils.help.ApplicationDetails; +import org.broadinstitute.sting.utils.help.HelpFormatter; import org.apache.log4j.Logger; import java.lang.reflect.*; diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/ApplicationDetails.java b/java/src/org/broadinstitute/sting/utils/help/ApplicationDetails.java similarity index 96% rename from java/src/org/broadinstitute/sting/utils/cmdLine/ApplicationDetails.java rename to java/src/org/broadinstitute/sting/utils/help/ApplicationDetails.java index c3f5fcb71..297ae1126 100644 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/ApplicationDetails.java +++ b/java/src/org/broadinstitute/sting/utils/help/ApplicationDetails.java @@ -23,10 +23,11 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -package org.broadinstitute.sting.utils.cmdLine; +package org.broadinstitute.sting.utils.help; import org.broadinstitute.sting.utils.JVMUtils; import org.broadinstitute.sting.utils.StingException; +import org.broadinstitute.sting.utils.cmdLine.CommandLineProgram; import java.util.List; import java.util.Collections; diff --git a/java/src/org/broadinstitute/sting/utils/help/DescriptionTaglet.java b/java/src/org/broadinstitute/sting/utils/help/DescriptionTaglet.java new file mode 100644 index 000000000..4f0459a08 --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/help/DescriptionTaglet.java @@ -0,0 +1,120 @@ +package org.broadinstitute.sting.utils.help; + +import com.sun.tools.doclets.Taglet; +import com.sun.javadoc.Tag; + +import java.util.Map; + +/** + * Provide an alternate description for the given help system. + * + * @author mhanna + * @version 0.1 + */ +public class DescriptionTaglet implements Taglet { + /** + * The key tag for this taglet. + */ + public static final String NAME = "help.description"; + + /** + * Return the name of this custom tag. + */ + public String getName() { + return NAME; + } + + /** + * Will return false since this tag cannot be applied + * to a field. + * @return false since this tag cannot be applied to a field. + */ + public boolean inField() { + return false; + } + + /** + * Will return false since this tag cannot be applied + * to a constructor. + * @return false since this tag cannot be applied to a constructor. + */ + public boolean inConstructor() { + return false; + } + + /** + * Will return false since this tag cannot be applied + * to a method. + * @return false since this tag cannot be applied to a method. + */ + public boolean inMethod() { + return false; + } + + /** + * Will return false since overviews are always named + * by the @WalkerName tag. + * @return false always + */ + public boolean inOverview() { + return true; + } + + /** + * Will return true to indicate that packages can be given useful + * description. + * @return true always + */ + public boolean inPackage() { + return true; + } + + /** + * Will return false indicating that types cannot be given + * alternate description. + * @return false always. + */ + public boolean inType() { + return false; + } + + /** + * Will return false since @todo + * is not an inline tag. + * @return false since @todo + * is not an inline tag. + */ + + public boolean isInlineTag() { + return false; + } + + /** + * Register this Taglet. + * @param tagletMap the map to register this tag to. + */ + public static void register(Map tagletMap) { + DescriptionTaglet tag = new DescriptionTaglet(); + Taglet t = (Taglet)tagletMap.get(tag.getName()); + if (t != null) { + tagletMap.remove(tag.getName()); + } + tagletMap.put(tag.getName(), tag); + } + + /** + * Create a string representation of this tag. Since this tag is only + * used by the help system, don't output any HTML. + */ + public String toString(Tag tag) { + return null; + } + + /** + * Create a string representation of this tag. Since this tag is only + * used by the help system, don't output any HTML. + */ + public String toString(Tag[] tags) { + return null; + } +} \ No newline at end of file diff --git a/java/src/org/broadinstitute/sting/utils/help/DisplayNameTaglet.java b/java/src/org/broadinstitute/sting/utils/help/DisplayNameTaglet.java new file mode 100644 index 000000000..d2bf948dc --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/help/DisplayNameTaglet.java @@ -0,0 +1,120 @@ +package org.broadinstitute.sting.utils.help; + +import com.sun.tools.doclets.Taglet; +import com.sun.javadoc.Tag; + +import java.util.Map; + +/** + * Provide a display name in the help for packages + * + * @author mhanna + * @version 0.1 + */ +public class DisplayNameTaglet implements Taglet { + /** + * The display name for this taglet. + */ + public static final String NAME = "help.display.name"; + + /** + * Return the name of this custom tag. + */ + public String getName() { + return NAME; + } + + /** + * Will return false since this tag cannot be applied + * to a field. + * @return false since this tag cannot be applied to a field. + */ + public boolean inField() { + return false; + } + + /** + * Will return false since this tag cannot be applied + * to a constructor. + * @return false since this tag cannot be applied to a constructor. + */ + public boolean inConstructor() { + return false; + } + + /** + * Will return false since this tag cannot be applied + * to a method. + * @return false since this tag cannot be applied to a method. + */ + public boolean inMethod() { + return false; + } + + /** + * Will return false since overviews are always named + * by the @WalkerName tag. + * @return false always + */ + public boolean inOverview() { + return false; + } + + /** + * Will return true to indicate that packages can be given useful + * display text. + * @return true always + */ + public boolean inPackage() { + return true; + } + + /** + * Will return false indicating that types cannot be given + * alternate display names. + * @return false always. + */ + public boolean inType() { + return false; + } + + /** + * Will return false since @todo + * is not an inline tag. + * @return false since @todo + * is not an inline tag. + */ + + public boolean isInlineTag() { + return false; + } + + /** + * Register this Taglet. + * @param tagletMap the map to register this tag to. + */ + public static void register(Map tagletMap) { + DisplayNameTaglet tag = new DisplayNameTaglet(); + Taglet t = (Taglet)tagletMap.get(tag.getName()); + if (t != null) { + tagletMap.remove(tag.getName()); + } + tagletMap.put(tag.getName(), tag); + } + + /** + * Create a string representation of this tag. Since this tag is only + * used by the help system, don't output any HTML. + */ + public String toString(Tag tag) { + return null; + } + + /** + * Create a string representation of this tag. Since this tag is only + * used by the help system, don't output any HTML. + */ + public String toString(Tag[] tags) { + return null; + } +} diff --git a/java/src/org/broadinstitute/sting/utils/help/HelpExtractorDoclet.java b/java/src/org/broadinstitute/sting/utils/help/HelpExtractorDoclet.java new file mode 100644 index 000000000..6a39144ae --- /dev/null +++ b/java/src/org/broadinstitute/sting/utils/help/HelpExtractorDoclet.java @@ -0,0 +1,113 @@ +package org.broadinstitute.sting.utils.help; + +import com.sun.javadoc.*; + +import java.util.HashSet; +import java.util.Set; +import java.util.Scanner; +import java.io.PrintStream; +import java.io.FileNotFoundException; + +import org.broadinstitute.sting.utils.StingException; + +/** + * Extracts certain types of javadoc (specifically package and class descriptions) and makes them available + * to applications at runtime. + * + * @author mhanna + * @version 0.1 + */ +public class HelpExtractorDoclet { + /** + * Extracts the contents of certain types of javadoc and adds them to an XML file. + * @param rootDoc The documentation root. + * @return Whether the JavaDoc run succeeded. + * @throws FileNotFoundException if output can't be written. + */ + public static boolean start(RootDoc rootDoc) throws FileNotFoundException { + PrintStream out = System.out; + + for(String[] options: rootDoc.options()) { + if(options[0].equals("-out")) + out = new PrintStream(options[1]); + } + + // Cache packages as we see them, since there's no direct way to iterate over packages. + Set packages = new HashSet(); + + for(ClassDoc currentClass: rootDoc.classes()) { + PackageDoc containingPackage = currentClass.containingPackage(); + packages.add(containingPackage); + String className = containingPackage.name().length() > 0 ? + String.format("%s.%s",containingPackage.name(),currentClass.name()) : + String.format("%s",currentClass.name()); + + renderHelpText(className,currentClass,out); + } + + for(PackageDoc currentPackage: packages) + renderHelpText(currentPackage.name(),currentPackage,out); + + return true; + } + + /** + * Validate the given options against options supported by this doclet. + * @param option Option to validate. + * @return Number of potential parameters; 0 if not supported. + */ + public static int optionLength(String option) { + if(option.equals("-out")) { + return 2; + } + return 0; + } + + /** + * Renders all the help text required for a given name. + * @param elementName element name to use as the key + * @param element Doc element to process. + * @param out Output stream to which to write. + */ + private static void renderHelpText(String elementName, Doc element, PrintStream out) { + // Extract overrides from the doc tags. + String overrideName = null; + String overrideDescription = element.commentText(); + for(Tag tag: element.tags()) { + if(tag.name().equals("@"+DisplayNameTaglet.NAME)) { + if(overrideName != null) + throw new StingException("Only one display name tag can be used per package / walker."); + overrideName = tag.text(); + } + else if(tag.name().equals("@"+DescriptionTaglet.NAME)) + overrideDescription = tag.text(); + } + + // Write out an alternate element name, if exists. + if(overrideName != null) + out.printf("%s.%s=%s%n",elementName,DisplayNameTaglet.NAME,overrideName); + + // Write out an alternate description, if present. + String description = formatText(overrideDescription); + if(description.length() > 0) + out.printf("%s=%s%n",elementName,description); + } + + /** + * Format text for consumption by the properties file. + * @param text Text to format. + * @return Formatted text; string trimmed, newlines removed. + */ + private static String formatText(String text) { + Scanner scanner = new Scanner(text); + StringBuilder output = new StringBuilder(); + + while(scanner.hasNextLine()) { + if(output.length() > 0) + output.append(' '); + output.append(scanner.nextLine().trim()); + } + + return output.toString(); + } +} diff --git a/java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java b/java/src/org/broadinstitute/sting/utils/help/HelpFormatter.java similarity index 86% rename from java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java rename to java/src/org/broadinstitute/sting/utils/help/HelpFormatter.java index b6f474fe7..905247bbb 100755 --- a/java/src/org/broadinstitute/sting/utils/cmdLine/HelpFormatter.java +++ b/java/src/org/broadinstitute/sting/utils/help/HelpFormatter.java @@ -1,6 +1,11 @@ -package org.broadinstitute.sting.utils.cmdLine; +package org.broadinstitute.sting.utils.help; +import org.broadinstitute.sting.utils.cmdLine.ArgumentDefinition; +import org.broadinstitute.sting.utils.cmdLine.ArgumentDefinitionGroup; +import org.broadinstitute.sting.utils.cmdLine.ArgumentDefinitions; +import org.broadinstitute.sting.utils.cmdLine.CommandLineProgram; import org.broadinstitute.sting.utils.TextFormattingUtils; +import org.apache.log4j.Logger; import java.util.Formatter; import java.util.List; @@ -9,6 +14,8 @@ import java.util.Iterator; import java.util.Comparator; import java.util.Collection; import java.util.Collections; +import java.text.DateFormat; +import java.text.SimpleDateFormat; /** * User: hanna * Date: May 6, 2009 @@ -27,6 +34,9 @@ import java.util.Collections; */ public class HelpFormatter { + /** our log, which we want to capture anything from org.broadinstitute.sting */ + private static Logger logger = Logger.getRootLogger(); + public static final int FIELD_SEPARATION_WIDTH = 3; /** @@ -209,4 +219,30 @@ public class HelpFormatter { return argumentGroups; } + + /** + * generateHeaderInformation + *

+ *

+ * Generate a standard header for the logger + * + * @param applicationDetails details of the application to run. + * @param args the command line arguments passed in + */ + public static void generateHeaderInformation(ApplicationDetails applicationDetails, String[] args) { + + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + java.util.Date date = new java.util.Date(); + + logger.info("-------------------------------------------------------"); + for (String headerLine : applicationDetails.applicationHeader) + logger.info(headerLine); + String output = ""; + for (String str : args) { + output = output + str + " "; + } + logger.info("Program Args: " + output); + logger.info("Date/Time: " + dateFormat.format(date)); + logger.info("-------------------------------------------------------"); + } }