Output JSON version of docs for Galaxy

This commit is contained in:
Geraldine Van der Auwera 2014-08-18 17:35:51 -04:00
parent 1cbf37c539
commit 3f21f63161
10 changed files with 268 additions and 957 deletions

View File

@ -74,7 +74,7 @@ class GATKDocWorkUnit implements Comparable<GATKDocWorkUnit> {
// set by the handler
String summary;
Map<String, Object> forTemplate;
Map<String, Object> forTemplate; // this is where the actual doc content gets stored
public GATKDocWorkUnit(String name, String filename, String group, DocumentedGATKFeatureObject annotation,
DocumentedGATKFeatureHandler handler, ClassDoc classDoc, Class clazz,

View File

@ -25,6 +25,12 @@
package org.broadinstitute.gatk.utils.help;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.stream.JsonWriter;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.RootDoc;
import freemarker.template.Configuration;
@ -46,7 +52,7 @@ import java.util.*;
/**
* Javadoc Doclet that combines javadoc, GATK ParsingEngine annotations, and FreeMarker
* templates to produce html formatted GATKDocs for walkers
* templates to produce PHP formatted GATKDocs for walkers
* and other classes.
* <p/>
* This document has the following workflow:
@ -56,10 +62,11 @@ import java.util.*;
* static list of things to document, and are to be documented
* 2 -- construct for each a GATKDocWorkUnit, resulting in the complete
* set of things to document
* 3 -- for each unit, actually generate an html page documenting it
* 3 -- for each unit, actually generate a PHP page documenting it
* as well as links to related features via their units. Writing
* of a specific class HTML is accomplished by a generate DocumentationHandler
* of a specific class PHP is accomplished by a generate DocumentationHandler
* 4 -- write out an index of all units, organized by group
* 5 -- emit JSON version of GATKDocs using Google GSON (currently incomplete but workable)
* <p/>
* The documented classes are restricted to only those with @DocumentedGATKFeature
* annotation or are in the STATIC_DOCS class.
@ -73,7 +80,7 @@ public class GATKDoclet {
final protected static File SETTINGS_DIR = new File("settings/helpTemplates");
/**
* Where we write the GATKDoc html directory
* Where we write the GATKDoc PHP directory
*/
final protected static File DESTINATION_DIR = new File("gatkdocs");
@ -125,7 +132,6 @@ public class GATKDoclet {
"NA"));
}
/**
* Extracts the contents of certain types of javadoc and adds them to an XML file.
*
@ -162,7 +168,6 @@ public class GATKDoclet {
// process the docs
new GATKDoclet().processDocs(rootDoc);
return true;
}
@ -203,8 +208,6 @@ public class GATKDoclet {
this.rootDoc = rootDoc;
try {
// basic setup
destinationDir.mkdirs();
// print the Version number
FileUtils.writeByteArrayToFile(new File(destinationDir + "/current.version.txt"), getSimpleVersion(absoluteVersion).getBytes());
@ -413,6 +416,7 @@ public class GATKDoclet {
// -> groups -> group1, group2, etc.
Map<String, Object> root = new HashMap<String, Object>();
Collections.sort(indexData);
List<Map<String, String>> groups = new ArrayList<Map<String, String>>();
@ -503,7 +507,6 @@ public class GATKDoclet {
private void processDocWorkUnit(Configuration cfg, GATKDocWorkUnit unit, List<Map<String, String>> groups, List<Map<String, String>> data)
throws IOException {
//System.out.printf("Processing documentation for class %s%n", unit.classDoc);
unit.handler.processOne(unit);
unit.forTemplate.put("groups", groups);
unit.forTemplate.put("data", data);
@ -519,6 +522,43 @@ public class GATKDoclet {
} catch (TemplateException e) {
throw new ReviewedGATKException("Failed to create GATK documentation", e);
}
// Create GSON-friendly object from unit.forTemplate
GSONWorkUnit gsonworkunit = new GSONWorkUnit();
gsonworkunit.populate( unit.forTemplate.get("summary").toString(),
unit.forTemplate.get("parallel"),
unit.forTemplate.get("activeregion"),
unit.forTemplate.get("partitiontype").toString(),
unit.forTemplate.get("walkertype").toString(),
unit.forTemplate.get("gson-arguments"),
unit.forTemplate.get("refwindow"),
unit.forTemplate.get("description").toString(),
unit.forTemplate.get("name").toString(),
unit.forTemplate.get("annotinfo").toString(),
unit.forTemplate.get("readfilters"),
unit.forTemplate.get("downsampling"),
unit.forTemplate.get("group").toString(),
unit.forTemplate.get("annotfield").toString(),
unit.forTemplate.get("annotdescript")
);
// Prepare to write JSON entry to file
File outputPathForJSON = new File(destinationDir + "/" + unit.filename + ".json");
try {
BufferedWriter outJSON = new BufferedWriter(new FileWriter(outputPathForJSON));
// Convert object to JSON
Gson gson = new GsonBuilder()
.serializeSpecialFloatingPointValues()
.setPrettyPrinting()
.create();
String json = gson.toJson(gsonworkunit); // was run on unit.forTemplate
outJSON.write(json);
outJSON.close();
} catch (Exception e) {
throw new ReviewedGATKException("Failed to create JSON entry", e);
}
}
private static String getSimpleVersion(String absoluteVersion) {
@ -532,4 +572,5 @@ public class GATKDoclet {
return parts[0];
}
}

View File

@ -0,0 +1,58 @@
package org.broadinstitute.gatk.utils.help;
import java.util.List;
import java.util.Map;
/**
* GSON-friendly version of the argument bindings
*/
public class GSONArgument {
String summary;
String name;
String synonyms;
String type;
String required;
String fulltext;
String defaultValue;
String minValue;
String maxValue;
String minRecValue;
String maxRecValue;
String rodTypes;
String kind;
List<Map<String, Object>> options;
public void populate( String summary,
String name,
String synonyms,
String type,
String required,
String fulltext,
String defaultValue,
String minValue,
String maxValue,
String minRecValue,
String maxRecValue,
String rodTypes,
String kind,
List<Map<String, Object>> options
) {
this.summary = summary;
this.name = name;
this.synonyms = synonyms;
this.type = type;
this.required = required;
this.fulltext = fulltext;
this.defaultValue = defaultValue;
this.minValue = minValue;
this.maxValue = maxValue;
this.minRecValue = minRecValue;
this.maxRecValue = maxRecValue;
this.rodTypes = rodTypes;
this.kind = kind;
this.options = options;
}
}

View File

@ -0,0 +1,61 @@
package org.broadinstitute.gatk.utils.help;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* GSON-friendly version of the GATKDocWorkUnit
*/
public class GSONWorkUnit {
String summary;
Object parallel;
Object activeregion;
String partitiontype;
String walkertype;
Object arguments;
Object refwindow;
String description;
String name;
String annotinfo;
Object readfilters;
Object downsampling;
String group;
String annotfield;
Object annotdescript;
public void populate(String summary,
Object parallel,
Object activeregion,
String partitiontype,
String walkertype,
Object arguments,
Object refwindow,
String description,
String name,
String annotinfo,
Object readfilters,
Object downsampling,
String group,
String annotfield,
Object annotdescript
) {
this.summary = summary;
this.parallel = parallel;
this.activeregion = activeregion;
this.partitiontype = partitiontype;
this.walkertype = walkertype;
this.arguments = arguments;
this.refwindow = refwindow;
this.description = description;
this.name = name;
this.annotinfo = annotinfo;
this.readfilters = readfilters;
this.downsampling = downsampling;
this.group = group;
this.annotfield = annotfield;
this.annotdescript = annotdescript;
}
}

View File

@ -167,10 +167,14 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
Map<String, Object> argBindings = docForArgument(fieldDoc, argumentSource, argDef);
if (!argumentSource.isHidden() || getDoclet().showHiddenFeatures()) {
final String kind = docKindOfArg(argumentSource);
argBindings.put("kind", kind);
// Retrieve default value
final Object value = argumentValue(toProcess.clazz, argumentSource);
if (value != null)
if (value != null) {
argBindings.put("defaultValue", prettyPrintValueString(value));
} else {
argBindings.put("defaultValue", "NA");
}
// Retrieve min and max / hard and soft value thresholds for numeric args
if (value instanceof Number) {
if (argumentSource.field.isAnnotationPresent(Argument.class)) {
@ -178,11 +182,21 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
argBindings.put("maxValue", argumentSource.field.getAnnotation(Argument.class).maxValue());
if (argumentSource.field.getAnnotation(Argument.class).minRecommendedValue() != Double.NEGATIVE_INFINITY) {
argBindings.put("minRecValue", argumentSource.field.getAnnotation(Argument.class).minRecommendedValue());
} else {
argBindings.put("minRecValue", "NA");
}
if (argumentSource.field.getAnnotation(Argument.class).maxRecommendedValue() != Double.POSITIVE_INFINITY) {
argBindings.put("maxRecValue", argumentSource.field.getAnnotation(Argument.class).maxRecommendedValue());
} else {
argBindings.put("maxRecValue", "NA");
}
}
} else {
argBindings.put("minValue", "NA");
argBindings.put("maxValue", "NA");
argBindings.put("minRecValue", "NA");
argBindings.put("maxRecValue", "NA");
argBindings.put("defaultValue", "NA");
}
// Finalize argument bindings
args.get(kind).add(argBindings);
@ -194,6 +208,30 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
for (Map.Entry<String, List<Map<String, Object>>> entry : args.entrySet()) {
entry.setValue(sortArguments(entry.getValue()));
}
// make a GSON-friendly map of arguments -- uses some hacky casting
List<GSONArgument> allGSONArgs = new ArrayList<GSONArgument>();
for ( Map<String, Object> item : args.get("all")) {
GSONArgument itemGSONArg = new GSONArgument();
itemGSONArg.populate(item.get("summary").toString(),
item.get("name").toString(),
item.get("synonyms").toString(),
item.get("type").toString(),
item.get("required").toString(),
item.get("fulltext").toString(),
item.get("defaultValue").toString(),
item.get("minValue").toString(),
item.get("maxValue").toString(),
item.get("minRecValue").toString(),
item.get("maxRecValue").toString(),
item.get("rodTypes").toString(),
item.get("kind").toString(),
(List<Map<String, Object>>)item.get("options")
);
allGSONArgs.add(itemGSONArg);
}
root.put("gson-arguments", allGSONArgs);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
@ -353,6 +391,10 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
// Get ActiveRegion size settings
final HashMap<String, Object> activeRegion = getActiveRegion(myClass, new HashMap<String, Object>());
root.put("activeregion", activeRegion);
// Get annotation header line description if applicable
final Object annotDescriptLines = getAnnotDescript(instance, myClass);
root.put("annotdescript", annotDescriptLines);
// anything else?
} else {
// put empty items to avoid blowups
@ -365,9 +407,32 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
root.put("downsampling", new HashMap<String, Object>());
root.put("refwindow", new HashMap<String, Object>());
root.put("activeregion", new HashMap<String, Object>());
root.put("annotdescript", new ArrayList<HashMap<String, Object>>());
}
}
/**
* Utility function that looks up annotation descriptions if applicable.
*
* @param myClass the class to query
* @return a hash map of descriptions, otherwise an empty map
*/
private Object getAnnotDescript(Object instance, Class myClass) {
//
// Check if the class has the method we want
for (Method classMethod : myClass.getMethods()) {
if (classMethod.toString().contains("getDescriptions") && classMethod.toString().contains("annotator")) {
try {
return classMethod.invoke(instance);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
}
return null;
}
/**
* Utility function that checks which parallelism options are available for an instance of class c.
*
@ -848,8 +913,11 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
root.put("name", names.getFirst());
if (names.getSecond() != null)
if (names.getSecond() != null) {
root.put("synonyms", names.getSecond());
} else {
root.put("synonyms", "NA");
}
root.put("required", def.required ? "yes" : "no");
@ -868,6 +936,8 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
}
root.put("rodTypes", Utils.join(", ", rodTypes));
} else {
root.put("rodTypes", "NA");
}
// summary and fulltext
@ -875,16 +945,20 @@ public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
root.put("fulltext", fieldDoc.commentText());
// What are our enum options?
if (def.validOptions != null)
if (def.validOptions != null) {
root.put("options", docForEnumArgument(source.field.getType()));
} else {
root.put("options", new ArrayList());
}
// general attributes
List<String> attributes = new ArrayList<String>();
if (def.required) attributes.add("required");
if (source.isDeprecated()) attributes.add("deprecated");
if (attributes.size() > 0)
if (attributes.size() > 0) {
root.put("attributes", Utils.join(", ", attributes));
} else {
root.put("attributes", "NA");
}
return root;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -41,7 +41,7 @@
<#list myargs as arg>
<tr>
<td><a href="#${arg.name}">${arg.name}</a><br />
<#if arg.synonyms??>
<#if arg.synonyms != "NA">
<#if arg.name[2..] != arg.synonyms[1..]>
&nbsp;<em>${arg.synonyms}</em>
</#if>
@ -68,10 +68,10 @@
<!--<#if arg.attributes??>
<p>${arg.attributes}</p>
</#if>-->
<#if arg.rodTypes??>
<#if arg.rodTypes != "NA">
<p>${arg.name} binds reference ordered data. This argument supports ROD files of the following types: ${arg.rodTypes}</p>
</#if>
<#if arg.options??>
<#if arg.options?has_content>
<p>
The ${arg.name} argument is an enumerated type (${arg.type}), which can have one of the following values:
<dl class="enum">
@ -82,25 +82,25 @@
</dl>
</p>
</#if>
<p><#if arg.required??>
<p><#if arg.required != "NA">
<#if arg.required == "yes">
<span class="badge badge-important">R</span>
</#if>
</#if>
<span class="label label-info ">${arg.type}</span>
<#if arg.defaultValue??>
<#if arg.defaultValue?is_number>
&nbsp;<span class="label">${arg.defaultValue}</span>
</#if>
<#if arg.minValue??>
<#if arg.minValue?is_number>
&nbsp;<span class="label label-warning">[ [ ${arg.minValue}</span>
</#if>
<#if arg.minRecValue??>
<#if arg.minRecValue?is_number>
&nbsp;<span class="label label-success">[ ${arg.minRecValue}</span>
</#if>
<#if arg.maxRecValue??>
<#if arg.maxRecValue?is_number>
&nbsp;<span class="label label-success">${arg.maxRecValue} ]</span>
</#if>
<#if arg.maxValue??>
<#if arg.maxValue?is_number>
&nbsp;<span class="label label-warning">${arg.maxValue} ] ]</span>
</#if>
</p>
@ -171,6 +171,15 @@
<small>${annotinfo}</small>
</h3>
</#if>
<#if annotdescript?has_content >
<h3>Header info <br />
<small>
<#list annotdescript as line>
<li><pre>${line}</pre></li>
</#list>
</small>
</h3>
</#if>
<hr>
<h2>Overview</h2>

File diff suppressed because one or more lines are too long

View File

@ -1,194 +0,0 @@
body
{
background-color: #ffffff;
color: #202020;
}
body, p, ul, ol, dl
{
font-family: Corbel, Verdana, "Lucida Grande", "Lucida Sans Unicode", Sans-Serif;
}
p, ul, ol, dl, dt, dd, td
{
font-size: 12pt;
}
p
{
margin-left: 1em;
}
p.summary
{
margin-left: 2em;
margin-top: -20pt;
font-style: italic;
}
p.see-also
{
font-size: 10pt;
margin-left: 0em;
margin-top: 3em;
text-align: center;
}
p.version
{
font-size: 8pt;
margin-left: 0em;
margin-top: -8pt;
text-align: center;
}
p.args
{
margin-left: 3em;
}
h1, h2, h3, h4
{
font-family: Corbel, Arial, Helvetica, Sans-Serif;
font-weight: bold;
text-align: left;
}
h1
{
font-size: 32pt;
letter-spacing: -2px;
color: #669;
}
h2
{
font-size: 16pt;
font-weight: bold;
margin-top: 2em;
color: #669;
}
h3
{
font-size: 12pt;
margin-left: 1em;
color: #000;
}
hr
{
margin-top: 4em;
}
/*
* enum DT layout
*/
dl {
margin-left: 3em;
}
dl.enum {
margin-left: 3em;
border: 1px dashed #ccc;
}
dt, dt.enum {
font-weight: bold;
text-decoration: underline;
}
/*
dt, dd.enum {
padding: 0 0 0.5em 0;
}
*/
pre {
border: thin solid lightgray;
margin-left: 1em;
margin-right: 4em;
/*
background-color: #e0fdff;
*/
}
/*
* clean table layouts
*/
#hor-minimalist-b
{
font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
font-size: 12px;
background: #fff;
margin: 5px;
width: 100%;
border-collapse: collapse;
text-align: left;
}
#hor-minimalist-b th
{
font-size: 14px;
font-weight: normal;
color: #039;
padding: 10px 8px;
border-bottom: 2px solid #6678b1;
}
#hor-minimalist-b td
{
border-bottom: 1px solid #ccc;
color: #669;
padding: 6px 8px;
}
#hor-minimalist-b tbody tr:hover td
{
color: #009;
}
th#row-divider
{
font-weight: bolder;
font-size: larger;
}
/*
* Table design for input/ouptut description
*/
#description-table
{
font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
font-size: 12px;
background: #fff;
margin: 5px;
border-collapse: collapse;
text-align: left;
}
#description-table th
{
font-size: 16px;
font-weight: bold;
background-color: lightgray;
color: #039;
text-align: center;
padding: 10px 8px;
border-bottom: 2px solid #6678b1;
}
#description-table td
{
border-bottom: 1px solid #ccc;
color: #669;
padding: 6px 8px;
text-align: right;
}
#description-table tbody tr:hover td
{
color: #009;
}
th#row-divider
{
font-weight: bolder;
font-size: larger;
}