aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/docgen
diff options
context:
space:
mode:
authorGravatar David Chen <dzc@google.com>2016-08-29 10:25:17 +0000
committerGravatar Klaus Aehlig <aehlig@google.com>2016-08-29 12:59:49 +0000
commit915dbdf187d52fda5547b5336e21339dceeb8e37 (patch)
treecdf8f59e41abdd7cebfd1dab55c70aed26bad493 /src/main/java/com/google/devtools/build/docgen
parent3bae1defc1d6198a7d73a616e2c448011250782d (diff)
Implement generating single-page Build Encyclopedia.
* Adds a --single_page flag to the BE docgen for generating a single-page version of the Build Encyclopedia. * Refactor BuildEncyclopediaProcessor common logic into a base class and add subclasses for generating single- and multi-page BE respectively. * Enable RuleLinkExpander to expand rule references to single-page hrefs (headings on the current page). * Update docgen velocity templates to use RuleLinkExpander to ensure links are correct on both single- and multi-page versions of the BE. -- MOS_MIGRATED_REVID=131574793
Diffstat (limited to 'src/main/java/com/google/devtools/build/docgen')
-rw-r--r--src/main/java/com/google/devtools/build/docgen/BuildDocCollector.java88
-rw-r--r--src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaGenerator.java13
-rw-r--r--src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaOptions.java9
-rw-r--r--src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaProcessor.java154
-rw-r--r--src/main/java/com/google/devtools/build/docgen/DocgenConsts.java15
-rw-r--r--src/main/java/com/google/devtools/build/docgen/MultiPageBuildEncyclopediaProcessor.java118
-rw-r--r--src/main/java/com/google/devtools/build/docgen/RuleLinkExpander.java44
-rw-r--r--src/main/java/com/google/devtools/build/docgen/SinglePageBuildEncyclopediaProcessor.java73
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/be-nav.vm1
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/common-definitions.vm14
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/functions.vm8
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/make-variables.vm14
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/overview.vm60
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/predefined-python-variables.vm6
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/rules.vm6
-rw-r--r--src/main/java/com/google/devtools/build/docgen/templates/be/single-page.vm28
16 files changed, 502 insertions, 149 deletions
diff --git a/src/main/java/com/google/devtools/build/docgen/BuildDocCollector.java b/src/main/java/com/google/devtools/build/docgen/BuildDocCollector.java
index 00e1d50f30..69bad6c867 100644
--- a/src/main/java/com/google/devtools/build/docgen/BuildDocCollector.java
+++ b/src/main/java/com/google/devtools/build/docgen/BuildDocCollector.java
@@ -25,7 +25,6 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.RuleClass;
-
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
@@ -48,18 +47,17 @@ public class BuildDocCollector {
private ConfiguredRuleClassProvider ruleClassProvider;
private boolean printMessages;
- public BuildDocCollector(ConfiguredRuleClassProvider ruleClassProvider,
- boolean printMessages) {
+ public BuildDocCollector(ConfiguredRuleClassProvider ruleClassProvider, boolean printMessages) {
this.ruleClassProvider = ruleClassProvider;
this.printMessages = printMessages;
}
/**
- * Parse the file containing black-listed rules for documentation. The list is simply a list of
+ * Parse the file containing blacklisted rules for documentation. The list is simply a list of
* rules separated by new lines. Line comments can be added to the file by starting them with #.
*
- * @param blackList The name of the file containing the black list.
- * @return The set of black listed rules.
+ * @param blackList The name of the file containing the blacklist.
+ * @return The set of blacklisted rules.
* @throws IOException
*/
@VisibleForTesting
@@ -80,14 +78,27 @@ public class BuildDocCollector {
}
/**
- * Collects all the rule and attribute documentation present in inputDirs, integrates the
- * attribute documentation in the rule documentation and returns the rule documentation.
+ * Creates a map of rule names (keys) to rule documentation (values).
+ *
+ * <p>This method crawls the specified input directories for rule class definitions (as Java
+ * source files) which contain the rules' and attributes' definitions as comments in a
+ * specific format. The keys in the returned Map correspond to these rule classes.
+ *
+ * <p>In the Map's values, all references pointing to other rules, rule attributes, and general
+ * documentation (e.g. common definitions, make variables, etc.) are expanded into hyperlinks.
+ * The links generated follow either the multi-page or single-page Build Encyclopedia model
+ * depending on the mode set for the provided {@link RuleLinkExpander}.
*
* @param inputDirs list of directories to scan for documentation
- * @param blackList specify an optional black list file that list some rules that should
+ * @param blackList specify an optional blacklist file that list some rules that should
* not be listed in the output.
+ * @param expander The RuleLinkExpander, which is used for expanding links in the rule doc.
+ * @throws BuildEncyclopediaDocException
+ * @throws IOException
+ * @return Map of rule class to rule documentation.
*/
- public Map<String, RuleDocumentation> collect(List<String> inputDirs, String blackList)
+ public Map<String, RuleDocumentation> collect(
+ List<String> inputDirs, String blackList, RuleLinkExpander expander)
throws BuildEncyclopediaDocException, IOException {
// Read the blackList file
Set<String> blacklistedRules = readBlackList(blackList);
@@ -122,7 +133,7 @@ public class BuildDocCollector {
}
processAttributeDocs(ruleDocEntries.values(), attributeDocEntries);
- RuleLinkExpander expander = buildRuleLinkExpander(ruleDocEntries.values());
+ expander.addIndex(buildRuleIndex(ruleDocEntries.values()));
for (RuleDocumentation rule : ruleDocEntries.values()) {
rule.setRuleLinkExpander(expander);
}
@@ -130,14 +141,38 @@ public class BuildDocCollector {
}
/**
+ * Creates a map of rule names (keys) to rule documentation (values).
+ *
+ * <p>This method crawls the specified input directories for rule class definitions (as Java
+ * source files) which contain the rules' and attributes' definitions as comments in a
+ * specific format. The keys in the returned Map correspond to these rule classes.
+ *
+ * <p>In the Map's values, all references pointing to other rules, rule attributes, and general
+ * documentation (e.g. common definitions, make variables, etc.) are expanded into hyperlinks.
+ * The links generated follow the multi-page Build Encyclopedia model (one page per rule clas.).
+ *
+ * @param inputDirs list of directories to scan for documentation
+ * @param blackList specify an optional blacklist file that list some rules that should
+ * not be listed in the output.
+ * @throws BuildEncyclopediaDocException
+ * @throws IOException
+ * @return Map of rule class to rule documentation.
+ */
+ public Map<String, RuleDocumentation> collect(List<String> inputDirs, String blackList)
+ throws BuildEncyclopediaDocException, IOException {
+ RuleLinkExpander expander = new RuleLinkExpander(/* singlePage */ false);
+ return collect(inputDirs, blackList, expander);
+ }
+
+ /**
* Generates an index mapping rule name to its normalized rule family name.
*/
- private RuleLinkExpander buildRuleLinkExpander(Iterable<RuleDocumentation> rules) {
+ private Map<String, String> buildRuleIndex(Iterable<RuleDocumentation> rules) {
Map<String, String> index = new HashMap<>();
for (RuleDocumentation rule : rules) {
index.put(rule.getRuleName(), RuleFamily.normalize(rule.getRuleFamily()));
}
- return new RuleLinkExpander(index);
+ return index;
}
/**
@@ -200,8 +235,28 @@ public class BuildDocCollector {
}
/**
- * Goes through all the html files and subdirs under inputPath and collects the rule
- * and attribute documentations using the ruleDocEntries and attributeDocEntries variable.
+ * Crawls the specified inputPath and collects the raw rule and rule attribute documentation.
+ *
+ * <p>This method crawls the specified input directory (recursively calling itself for all
+ * subdirectories) and reads each Java source file using {@link SourceFileReader} to extract the
+ * raw rule and attribute documentation embedded in comments in a specific format. The extracted
+ * documentation is then further processed, such as by
+ * {@link BuildDocCollector#collect(List<String>, String, RuleLinkExpander), collect}, in order
+ * to associate each rule's documentation with its attribute documentation.
+ *
+ * <p>This method returns the following through its parameters: the set of Java source files
+ * processed, a map of rule name to the source file it was extracted from, a map of rule name
+ * to the documentation to the rule, and a multimap of attribute name to attribute documentation.
+ *
+ * @param processedFiles The set of Java source files files that have already been processed
+ * in order to avoid reprocessing the same file.
+ * @param ruleClassFiles Map of rule name to the source file it was extracted from.
+ * @param ruleDocEntries Map of rule name to rule documentation.
+ * @param blackList The set of blacklisted rules whose documentation should not be extracted.
+ * @param attributeDocEntries Multimap of rule attribute name to attribute documentation.
+ * @param inputPath The File representing the file or directory to read.
+ * @throws BuildEncyclopediaDocException
+ * @throws IOException
*/
public void collectDocs(
Set<File> processedFiles,
@@ -216,8 +271,7 @@ public class BuildDocCollector {
if (inputPath.isFile()) {
if (DocgenConsts.JAVA_SOURCE_FILE_SUFFIX.apply(inputPath.getName())) {
- SourceFileReader sfr = new SourceFileReader(
- ruleClassProvider, inputPath.getAbsolutePath());
+ SourceFileReader sfr = new SourceFileReader(ruleClassProvider, inputPath.getAbsolutePath());
sfr.readDocsFromComments();
for (RuleDocumentation d : sfr.getRuleDocEntries()) {
String ruleName = d.getRuleName();
diff --git a/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaGenerator.java b/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaGenerator.java
index 64c0584a7d..bc38cfc7e7 100644
--- a/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaGenerator.java
+++ b/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaGenerator.java
@@ -15,7 +15,6 @@ package com.google.devtools.build.docgen;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.common.options.OptionsParser;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
@@ -28,7 +27,7 @@ public class BuildEncyclopediaGenerator {
private static void printUsage(OptionsParser parser) {
System.err.println(
"Usage: docgen_bin -p rule_class_provider (-i input_dir)+\n"
- + " [-o outputdir] [-b blacklist] [-h]\n\n"
+ + " [-o outputdir] [-b blacklist] [-1] [-h]\n\n"
+ "Generates the Build Encyclopedia from embedded native rule documentation.\n"
+ "The rule class provider (-p) and at least one input_dir (-i) must be specified.\n");
System.err.println(
@@ -69,8 +68,14 @@ public class BuildEncyclopediaGenerator {
}
try {
- BuildEncyclopediaProcessor processor = new BuildEncyclopediaProcessor(
- createRuleClassProvider(options.provider));
+ BuildEncyclopediaProcessor processor = null;
+ if (options.singlePage) {
+ processor = new SinglePageBuildEncyclopediaProcessor(
+ createRuleClassProvider(options.provider));
+ } else {
+ processor = new MultiPageBuildEncyclopediaProcessor(
+ createRuleClassProvider(options.provider));
+ }
processor.generateDocumentation(
options.inputDirs, options.outputDir, options.blacklist);
} catch (BuildEncyclopediaDocException e) {
diff --git a/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaOptions.java b/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaOptions.java
index f75dc6a82b..92e51a219f 100644
--- a/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaOptions.java
+++ b/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaOptions.java
@@ -15,7 +15,6 @@ package com.google.devtools.build.docgen;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;
-
import java.util.List;
/**
@@ -56,6 +55,14 @@ public class BuildEncyclopediaOptions extends OptionsBase {
public String blacklist;
@Option(
+ name = "single_page",
+ abbrev = '1',
+ defaultValue = "false",
+ help = "Whether to generate the BE as a single HTML page or one page per rule family."
+ )
+ public boolean singlePage;
+
+ @Option(
name = "help",
abbrev = 'h',
defaultValue = "false",
diff --git a/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaProcessor.java b/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaProcessor.java
index c6bf396441..7abe7f12c1 100644
--- a/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaProcessor.java
+++ b/src/main/java/com/google/devtools/build/docgen/BuildEncyclopediaProcessor.java
@@ -21,11 +21,9 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Ordering;
-import com.google.common.collect.Sets;
import com.google.devtools.build.docgen.DocgenConsts.RuleType;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.packages.RuleClass;
-
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -33,22 +31,21 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeMap;
import java.util.TreeSet;
/**
* A class to assemble documentation for the Build Encyclopedia. This class uses
* {@link BuildDocCollector} to extract documentation fragments from rule classes.
*/
-public class BuildEncyclopediaProcessor {
- private static final Predicate<String> RULE_WORTH_DOCUMENTING = new Predicate<String>() {
+public abstract class BuildEncyclopediaProcessor {
+ protected static final Predicate<String> RULE_WORTH_DOCUMENTING = new Predicate<String>() {
@Override
public boolean apply(String name) {
return !name.contains("$");
}
};
- private ConfiguredRuleClassProvider ruleClassProvider;
+ protected ConfiguredRuleClassProvider ruleClassProvider;
/**
* Creates the BuildEncyclopediaProcessor instance. The ruleClassProvider parameter
@@ -67,49 +64,27 @@ public class BuildEncyclopediaProcessor {
* @param outputRootDir output directory where to write the build encyclopedia
* @param blackList optional path to a file listing rules to not document
*/
- public void generateDocumentation(List<String> inputDirs, String outputDir, String blackList)
- throws BuildEncyclopediaDocException, IOException {
- writeStaticPage(outputDir, "make-variables");
- writeStaticPage(outputDir, "predefined-python-variables");
- writeStaticPage(outputDir, "functions");
- writeCommonDefinitionsPage(outputDir);
-
- BuildDocCollector collector = new BuildDocCollector(ruleClassProvider, false);
- Map<String, RuleDocumentation> ruleDocEntries = collector.collect(inputDirs, blackList);
- warnAboutUndocumentedRules(
- Sets.difference(ruleClassProvider.getRuleClassMap().keySet(), ruleDocEntries.keySet()));
-
- writeRuleDocs(outputDir, ruleDocEntries.values());
- }
-
- private void writeStaticPage(String outputDir, String name) throws IOException {
- File file = new File(outputDir + "/" + name + ".html");
- Page page = TemplateEngine.newPage(
- "com/google/devtools/build/docgen/templates/be/" + name + ".vm");
- page.write(file);
- }
+ public abstract void generateDocumentation(List<String> inputDirs, String outputDir,
+ String blackList) throws BuildEncyclopediaDocException, IOException;
- private void writeCommonDefinitionsPage(String outputDir) throws IOException {
- File file = new File(outputDir + "/common-definitions.html");
- Page page = TemplateEngine.newPage(DocgenConsts.COMMON_DEFINITIONS_TEMPLATE);
- page.add("commonAttributes", PredefinedAttributes.COMMON_ATTRIBUTES);
- page.add("testAttributes", PredefinedAttributes.TEST_ATTRIBUTES);
- page.add("binaryAttributes", PredefinedAttributes.BINARY_ATTRIBUTES);
- page.write(file);
- }
-
- private List<RuleFamily> assembleRuleFamilies(
- Map<String, ListMultimap<RuleType, RuleDocumentation>> ruleMapping,
- Set<String> ruleFamilyNames) {
- List<RuleFamily> ruleFamilies = new ArrayList<>(ruleFamilyNames.size());
- for (String name : ruleFamilyNames) {
- ListMultimap<RuleType, RuleDocumentation> ruleTypeMap = ruleMapping.get(name);
- ruleFamilies.add(new RuleFamily(ruleTypeMap, name));
+ /**
+ * POD class for containing lists of rule families separated into language-specific and generic as
+ * returned by {@link #assembleRuleFamilies(Iterable<RuleDocumentation>) assembleRuleFamilies}.
+ */
+ protected static class RuleFamilies {
+ public List<RuleFamily> langSpecific;
+ public List<RuleFamily> generic;
+ public List<RuleFamily> all;
+
+ public RuleFamilies(List<RuleFamily> langSpecific, List<RuleFamily> generic,
+ List<RuleFamily> all) {
+ this.langSpecific = langSpecific;
+ this.generic = generic;
+ this.all = all;
}
- return ruleFamilies;
}
- private void writeRuleDocs(String outputDir, Iterable<RuleDocumentation> docEntries)
+ protected RuleFamilies assembleRuleFamilies(Iterable<RuleDocumentation> docEntries)
throws BuildEncyclopediaDocException, IOException {
// Separate rule families into language-specific and generic ones.
Set<String> langSpecificRuleFamilyNames = new TreeSet<>();
@@ -125,46 +100,23 @@ public class BuildEncyclopediaProcessor {
// the Overview page while the list containing all rule families will be used to
// generate all other documentation.
List<RuleFamily> langSpecificRuleFamilies =
- assembleRuleFamilies(ruleMapping, langSpecificRuleFamilyNames);
+ filterRuleFamilies(ruleMapping, langSpecificRuleFamilyNames);
List<RuleFamily> genericRuleFamilies =
- assembleRuleFamilies(ruleMapping, genericRuleFamilyNames);
+ filterRuleFamilies(ruleMapping, genericRuleFamilyNames);
List<RuleFamily> allRuleFamilies = new ArrayList<>(langSpecificRuleFamilies);
allRuleFamilies.addAll(genericRuleFamilies);
-
- // Generate documentation.
- writeOverviewPage(outputDir, langSpecificRuleFamilies, genericRuleFamilies);
- writeBeNav(outputDir, allRuleFamilies);
- for (RuleFamily ruleFamily : allRuleFamilies) {
- if (ruleFamily.size() > 0) {
- writeRuleDoc(outputDir, ruleFamily);
- }
- }
- }
-
- private void writeOverviewPage(String outputDir,
- List<RuleFamily> langSpecificRuleFamilies,
- List<RuleFamily> genericRuleFamilies)
- throws BuildEncyclopediaDocException, IOException {
- File file = new File(outputDir + "/overview.html");
- Page page = TemplateEngine.newPage(DocgenConsts.OVERVIEW_TEMPLATE);
- page.add("langSpecificRuleFamilies", langSpecificRuleFamilies);
- page.add("genericRuleFamilies", genericRuleFamilies);
- page.write(file);
- }
-
- private void writeRuleDoc(String outputDir, RuleFamily ruleFamily)
- throws BuildEncyclopediaDocException, IOException {
- File file = new File(outputDir + "/" + ruleFamily.getId() + ".html");
- Page page = TemplateEngine.newPage(DocgenConsts.RULES_TEMPLATE);
- page.add("ruleFamily", ruleFamily);
- page.write(file);
+ return new RuleFamilies(langSpecificRuleFamilies, genericRuleFamilies, allRuleFamilies);
}
- private void writeBeNav(String outputDir, List<RuleFamily> ruleFamilies) throws IOException {
- File file = new File(outputDir + "/be-nav.html");
- Page page = TemplateEngine.newPage(DocgenConsts.BE_NAV_TEMPLATE);
- page.add("ruleFamilies", ruleFamilies);
- page.write(file);
+ private List<RuleFamily> filterRuleFamilies(
+ Map<String, ListMultimap<RuleType, RuleDocumentation>> ruleMapping,
+ Set<String> ruleFamilyNames) {
+ List<RuleFamily> ruleFamilies = new ArrayList<>(ruleFamilyNames.size());
+ for (String name : ruleFamilyNames) {
+ ListMultimap<RuleType, RuleDocumentation> ruleTypeMap = ruleMapping.get(name);
+ ruleFamilies.add(new RuleFamily(ruleTypeMap, name));
+ }
+ return ruleFamilies;
}
/**
@@ -212,10 +164,50 @@ public class BuildEncyclopediaProcessor {
}
}
- private static void warnAboutUndocumentedRules(Iterable<String> rulesWithoutDocumentation) {
+ /**
+ * Helper method for displaying an warning message about undocumented rules.
+ *
+ * @param rulesWithoutDocumentation Undocumented rules to list in the warning message.
+ */
+ protected static void warnAboutUndocumentedRules(Iterable<String> rulesWithoutDocumentation) {
Iterable<String> undocumentedRules = Iterables.filter(rulesWithoutDocumentation,
RULE_WORTH_DOCUMENTING);
System.err.printf("WARNING: The following rules are undocumented: [%s]\n",
Joiner.on(", ").join(Ordering.<String>natural().immutableSortedCopy(undocumentedRules)));
}
+
+ /**
+ * Sets the {@link RuleLinkExpander} for the provided {@link RuleDocumentationAttributes}.
+ *
+ * <p>This method is used to set the {@link RuleLinkExpander} for common attributes, such as
+ * those defined in {@link PredefinedAttributes}, so that rule references in the docs for those
+ * attributes can be expanded.
+ *
+ * @param attributes The map containing the RuleDocumentationAttributes, keyed by attribute name.
+ * @param expander The RuleLinkExpander to set in each of the RuleDocumentationAttributes.
+ * @return A map of name to RuleDocumentationAttribute with the RuleLinkExpander set for each
+ * attribute.
+ */
+ protected static Map<String, RuleDocumentationAttribute> expandCommonAttributes(
+ Map<String, RuleDocumentationAttribute> attributes, RuleLinkExpander expander) {
+ Map<String, RuleDocumentationAttribute> expanded = new HashMap<>(attributes.size());
+ for (Map.Entry<String, RuleDocumentationAttribute> entry : attributes.entrySet()) {
+ RuleDocumentationAttribute attribute = entry.getValue();
+ attribute.setRuleLinkExpander(expander);
+ expanded.put(entry.getKey(), attribute);
+ }
+ return expanded;
+ }
+
+ /**
+ * Writes the {@link Page} using the provided file name in the specified output directory.
+ *
+ * @param page The page to write.
+ * @param outputDir The output directory to write the file.
+ * @param fileName The name of the file to write the page to.
+ * @throws IOException
+ */
+ protected static void writePage(Page page, String outputDir, String fileName) throws IOException {
+ page.write(new File(outputDir + "/" + fileName));
+ }
}
diff --git a/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java b/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java
index 610c15c6dd..5209d4f35b 100644
--- a/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java
+++ b/src/main/java/com/google/devtools/build/docgen/DocgenConsts.java
@@ -18,7 +18,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.util.FileTypeSet;
-
import java.util.Map;
import java.util.regex.Pattern;
@@ -29,14 +28,14 @@ public class DocgenConsts {
public static final String LS = "\n";
+ public static final String BE_TEMPLATE_DIR =
+ "com/google/devtools/build/docgen/templates/be";
+ public static final String SINGLE_BE_TEMPLATE = BE_TEMPLATE_DIR + "/single-page.vm";
public static final String COMMON_DEFINITIONS_TEMPLATE =
- "com/google/devtools/build/docgen/templates/be/common-definitions.vm";
- public static final String OVERVIEW_TEMPLATE =
- "com/google/devtools/build/docgen/templates/be/overview.vm";
- public static final String RULES_TEMPLATE =
- "com/google/devtools/build/docgen/templates/be/rules.vm";
- public static final String BE_NAV_TEMPLATE =
- "com/google/devtools/build/docgen/templates/be/be-nav.vm";
+ BE_TEMPLATE_DIR + "/common-definitions.vm";
+ public static final String OVERVIEW_TEMPLATE = BE_TEMPLATE_DIR + "/overview.vm";
+ public static final String RULES_TEMPLATE = BE_TEMPLATE_DIR + "/rules.vm";
+ public static final String BE_NAV_TEMPLATE = BE_TEMPLATE_DIR + "/be-nav.vm";
public static final String SKYLARK_LIBRARY_TEMPLATE =
"com/google/devtools/build/docgen/templates/skylark-library.vm";
diff --git a/src/main/java/com/google/devtools/build/docgen/MultiPageBuildEncyclopediaProcessor.java b/src/main/java/com/google/devtools/build/docgen/MultiPageBuildEncyclopediaProcessor.java
new file mode 100644
index 0000000000..9c3a95153f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/MultiPageBuildEncyclopediaProcessor.java
@@ -0,0 +1,118 @@
+// 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.docgen;
+
+import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Assembles the multi-page version of the Build Encyclopedia with one page per rule family.
+ */
+public class MultiPageBuildEncyclopediaProcessor extends BuildEncyclopediaProcessor {
+ public MultiPageBuildEncyclopediaProcessor(ConfiguredRuleClassProvider ruleClassProvider) {
+ super(ruleClassProvider);
+ }
+
+ /**
+ * Collects and processes all the rule and attribute documentation in inputDirs and
+ * generates the Build Encyclopedia into the outputDir.
+ *
+ * @param inputDirs list of directory to scan for document in the source code
+ * @param outputDir output directory where to write the build encyclopedia
+ * @param blackList optional path to a file listing rules to not document
+ */
+ @Override
+ public void generateDocumentation(List<String> inputDirs, String outputDir, String blackList)
+ throws BuildEncyclopediaDocException, IOException {
+ BuildDocCollector collector = new BuildDocCollector(ruleClassProvider, false);
+ RuleLinkExpander expander = new RuleLinkExpander(false);
+ Map<String, RuleDocumentation> ruleDocEntries = collector.collect(
+ inputDirs, blackList, expander);
+ warnAboutUndocumentedRules(
+ Sets.difference(ruleClassProvider.getRuleClassMap().keySet(), ruleDocEntries.keySet()));
+
+ writeStaticDoc(outputDir, expander, "make-variables");
+ writeStaticDoc(outputDir, expander, "predefined-python-variables");
+ writeStaticDoc(outputDir, expander, "functions");
+ writeCommonDefinitionsPage(outputDir, expander);
+
+ writeRuleDocs(outputDir, expander, ruleDocEntries.values());
+ }
+
+ private void writeStaticDoc(String outputDir, RuleLinkExpander expander, String name)
+ throws IOException {
+ // TODO(dzc): Consider splitting out the call to writePage so that this method only creates the
+ // Page object and adding docgen tests that test the state of Page objects constructed by
+ // this method, and similar methods in this class.
+ Page page = TemplateEngine.newPage(DocgenConsts.BE_TEMPLATE_DIR + "/" + name + ".vm");
+ page.add("expander", expander);
+ writePage(page, outputDir, name + ".html");
+ }
+
+ private void writeCommonDefinitionsPage(String outputDir, RuleLinkExpander expander)
+ throws IOException {
+ Page page = TemplateEngine.newPage(DocgenConsts.COMMON_DEFINITIONS_TEMPLATE);
+ page.add("expander", expander);
+ page.add("commonAttributes",
+ expandCommonAttributes(PredefinedAttributes.COMMON_ATTRIBUTES, expander));
+ page.add("testAttributes",
+ expandCommonAttributes(PredefinedAttributes.TEST_ATTRIBUTES, expander));
+ page.add("binaryAttributes",
+ expandCommonAttributes(PredefinedAttributes.BINARY_ATTRIBUTES, expander));
+ writePage(page, outputDir, "common-definitions.html");
+ }
+
+ private void writeRuleDocs(String outputDir, RuleLinkExpander expander,
+ Iterable<RuleDocumentation> docEntries) throws BuildEncyclopediaDocException, IOException {
+ RuleFamilies ruleFamilies = assembleRuleFamilies(docEntries);
+
+ // Generate documentation.
+ writeOverviewPage(outputDir, expander, ruleFamilies.langSpecific, ruleFamilies.generic);
+ writeBeNav(outputDir, ruleFamilies.all);
+ for (RuleFamily ruleFamily : ruleFamilies.all) {
+ if (ruleFamily.size() > 0) {
+ writeRuleDoc(outputDir, ruleFamily);
+ }
+ }
+ }
+
+ private void writeOverviewPage(String outputDir,
+ RuleLinkExpander expander,
+ List<RuleFamily> langSpecificRuleFamilies,
+ List<RuleFamily> genericRuleFamilies)
+ throws BuildEncyclopediaDocException, IOException {
+ Page page = TemplateEngine.newPage(DocgenConsts.OVERVIEW_TEMPLATE);
+ page.add("expander", expander);
+ page.add("langSpecificRuleFamilies", langSpecificRuleFamilies);
+ page.add("genericRuleFamilies", genericRuleFamilies);
+ writePage(page, outputDir, "overview.html");
+ }
+
+ private void writeRuleDoc(String outputDir, RuleFamily ruleFamily)
+ throws BuildEncyclopediaDocException, IOException {
+ Page page = TemplateEngine.newPage(DocgenConsts.RULES_TEMPLATE);
+ page.add("ruleFamily", ruleFamily);
+ writePage(page, outputDir, ruleFamily.getId() + ".html");
+ }
+
+ private void writeBeNav(String outputDir, List<RuleFamily> ruleFamilies) throws IOException {
+ Page page = TemplateEngine.newPage(DocgenConsts.BE_NAV_TEMPLATE);
+ page.add("ruleFamilies", ruleFamilies);
+ writePage(page, outputDir, "be-nav.html");
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/RuleLinkExpander.java b/src/main/java/com/google/devtools/build/docgen/RuleLinkExpander.java
index d73bf5305e..4f74054fe1 100644
--- a/src/main/java/com/google/devtools/build/docgen/RuleLinkExpander.java
+++ b/src/main/java/com/google/devtools/build/docgen/RuleLinkExpander.java
@@ -15,7 +15,6 @@ package com.google.devtools.build.docgen;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -27,7 +26,7 @@ import java.util.regex.Matcher;
* <p>See {@link com.google.devtools.build.docgen.DocgenConsts.BLAZE_RULE_LINK} for the regex used
* to match link references.
*/
-class RuleLinkExpander {
+public class RuleLinkExpander {
private static final String EXAMPLES_SUFFIX = "_examples";
private static final String ARGS_SUFFIX = "_args";
private static final String IMPLICIT_OUTPUTS_SUFFIX = "_implicit_outputs";
@@ -53,15 +52,28 @@ class RuleLinkExpander {
.build();
private final Map<String, String> ruleIndex = new HashMap<>();
+ private final boolean singlePage;
- RuleLinkExpander(Map<String, String> ruleIndex) {
+ RuleLinkExpander(Map<String, String> ruleIndex, boolean singlePage) {
this.ruleIndex.putAll(ruleIndex);
this.ruleIndex.putAll(FUNCTIONS);
+ this.singlePage = singlePage;
+ }
+
+ RuleLinkExpander(boolean singlePage) {
+ this.ruleIndex.putAll(FUNCTIONS);
+ this.singlePage = singlePage;
+ }
+
+ public void addIndex(Map<String, String> ruleIndex) {
+ this.ruleIndex.putAll(ruleIndex);
}
private void appendRuleLink(Matcher matcher, StringBuffer sb, String ruleName, String ref) {
String ruleFamily = ruleIndex.get(ruleName);
- String link = ruleFamily + ".html#" + ref;
+ String link = singlePage
+ ? "#" + ref
+ : ruleFamily + ".html#" + ref;
matcher.appendReplacement(sb, Matcher.quoteReplacement(link));
}
@@ -109,7 +121,9 @@ class RuleLinkExpander {
// The name is not the name of a rule but is the name of a static page, such as
// common-definitions. Generate a link to that page.
if (STATIC_PAGES.contains(name)) {
- String link = name + ".html";
+ String link = singlePage
+ ? "#" + name
+ : name + ".html";
// For referencing headings on a static page, use the following syntax:
// ${link static_page_name#heading_name}, example: ${link make-variables#gendir}
String pageHeading = matcher.group(4);
@@ -150,7 +164,9 @@ class RuleLinkExpander {
// this include custom <a name="heading"> tags in the description or examples for the rule.
if (ruleIndex.containsKey(name)) {
String ruleFamily = ruleIndex.get(name);
- String link = ruleFamily + ".html#" + heading;
+ String link = singlePage
+ ? "#" + heading
+ : ruleFamily + ".html#" + heading;
matcher.appendReplacement(sb, Matcher.quoteReplacement(link));
continue;
}
@@ -159,7 +175,9 @@ class RuleLinkExpander {
// append the page heading. For example, ${link common-definitions#label-expansion} expands to
// common-definitions.html#label-expansion.
if (STATIC_PAGES.contains(name)) {
- String link = name + ".html#" + heading;
+ String link = singlePage
+ ? "#" + heading
+ : name + ".html#" + heading;
matcher.appendReplacement(sb, Matcher.quoteReplacement(link));
continue;
}
@@ -183,4 +201,16 @@ class RuleLinkExpander {
String expanded = expandRuleLinks(htmlDoc);
return expandRuleHeadingLinks(expanded);
}
+
+ /**
+ * Expands the rule reference.
+ *
+ * <p>This method is used to expand references in the BE velocity templates.
+ *
+ * @param ref The rule reference to expand.
+ * @return The expanded rule reference.
+ */
+ public String expandRef(String ref) throws IllegalArgumentException {
+ return expand("${link " + ref + "}");
+ }
}
diff --git a/src/main/java/com/google/devtools/build/docgen/SinglePageBuildEncyclopediaProcessor.java b/src/main/java/com/google/devtools/build/docgen/SinglePageBuildEncyclopediaProcessor.java
new file mode 100644
index 0000000000..ccacd2fbc0
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/SinglePageBuildEncyclopediaProcessor.java
@@ -0,0 +1,73 @@
+// 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.docgen;
+
+import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Assembles the single-page version of the Build Encyclopedia.
+ */
+public class SinglePageBuildEncyclopediaProcessor extends BuildEncyclopediaProcessor {
+ public SinglePageBuildEncyclopediaProcessor(ConfiguredRuleClassProvider ruleClassProvider) {
+ super(ruleClassProvider);
+ }
+
+ /**
+ * Collects and processes all the rule and attribute documentation in inputDirs and
+ * generates the Build Encyclopedia into the outputDir.
+ *
+ * @param inputDirs list of directory to scan for document in the source code
+ * @param outputDir output directory where to write the build encyclopedia
+ * @param blackList optional path to a file listing rules to not document
+ */
+ @Override
+ public void generateDocumentation(List<String> inputDirs, String outputDir, String blackList)
+ throws BuildEncyclopediaDocException, IOException {
+ BuildDocCollector collector = new BuildDocCollector(ruleClassProvider, false);
+ RuleLinkExpander expander = new RuleLinkExpander(true);
+ Map<String, RuleDocumentation> ruleDocEntries = collector.collect(
+ inputDirs, blackList, expander);
+ warnAboutUndocumentedRules(
+ Sets.difference(ruleClassProvider.getRuleClassMap().keySet(), ruleDocEntries.keySet()));
+ RuleFamilies ruleFamilies = assembleRuleFamilies(ruleDocEntries.values());
+
+ Page page = TemplateEngine.newPage(DocgenConsts.SINGLE_BE_TEMPLATE);
+
+ // Add the rule link expander.
+ page.add("expander", expander);
+
+ // Populate variables for Common Definitions section.
+ page.add("commonAttributes",
+ expandCommonAttributes(PredefinedAttributes.COMMON_ATTRIBUTES, expander));
+ page.add("testAttributes",
+ expandCommonAttributes(PredefinedAttributes.TEST_ATTRIBUTES, expander));
+ page.add("binaryAttributes",
+ expandCommonAttributes(PredefinedAttributes.BINARY_ATTRIBUTES, expander));
+
+ // Popualte variables for Overview section.
+ page.add("langSpecificRuleFamilies", ruleFamilies.langSpecific);
+ page.add("genericRuleFamilies", ruleFamilies.generic);
+
+ // Populate variables for Rules section.
+ page.add("ruleFamilies", ruleFamilies.all);
+ page.add("singlePage", true);
+
+ writePage(page, outputDir, "build-encyclopedia.html");
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/be-nav.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/be-nav.vm
index c8951e6c3c..3ac6e5c25d 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/be-nav.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/be-nav.vm
@@ -2,6 +2,7 @@
#set ($bazelbuildGithub = "https://github.com/bazelbuild")
<h3>Build Encyclopedia</h3>
+
<ul class="sidebar-nav">
<li><a href="${path}/overview.html">Overview</a></li>
<li>
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/common-definitions.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/common-definitions.vm
index ff9e2a5875..94f5ac80a1 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/common-definitions.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/common-definitions.vm
@@ -1,15 +1,20 @@
+#if (!$singlePage)
---
layout: documentation
title: Common Definitions
---
+#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+#end
-<h1>Common definitions</h1>
+<h1 id="common-definitions">Common definitions</h1>
<p>This section defines various terms and concepts that are common to
many functions or build rules below.
</p>
+#if (!$singlePage)
<div class="toc">
<h1>Contents</h1>
<ul>
@@ -22,6 +27,7 @@ many functions or build rules below.
<li><a href="#implicit-outputs">Implicit output targets</a></li>
</ul>
</div>
+#end
<h2 id='sh-tokenization'>Bourne shell tokenization</h2>
<p>
Certain string attributes of some rules are split into multiple
@@ -147,8 +153,8 @@ config_setting(
<p>
See the definitions of
- <a href="functions.html#select">select</a> and
- <a href="general.html#config_setting">config_setting</a> for more details.
+ <a href="$expander.expandRef("select")">select</a> and
+ <a href="$expander.expandRef("config_setting")">config_setting</a> for more details.
Attributes marked <code>nonconfigurable</code> in their documentation cannot
use this feature (usually because Bazel has to know their values before flags
have been parsed).
@@ -204,4 +210,6 @@ config_setting(
the <a href="../build-ref.html">BUILD Concept Reference</a>.
</p>
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/footer.vm")
+#end
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/functions.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/functions.vm
index 8a87358ef8..4b7ddfa3f3 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/functions.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/functions.vm
@@ -1,11 +1,16 @@
+#if (!$singlePage)
---
layout: documentation
title: Functions
---
+#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+#end
<h1>Functions</h1>
+#if (!$singlePage)
<div class="toc">
<h1>Contents</h1>
<ul>
@@ -19,6 +24,7 @@ title: Functions
<li><a href="#workspace">workspace</a></li>
</ul>
</div>
+#end
<!-- =================================================================
load()
=================================================================
@@ -692,4 +698,6 @@ sh_binary(
<code>workspace(name = "foo.bar")</code>.
</p>
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/footer.vm")
+#end
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/make-variables.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/make-variables.vm
index 2f5b9075e9..35448ed4a9 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/make-variables.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/make-variables.vm
@@ -1,15 +1,20 @@
+#if (!$singlePage)
---
layout: documentation
title: Make Variables
---
+#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+#end
<!-- ============================================
variables
============================================
-->
-<h1>"Make" Variables</h1>
+<h1 id="make-variables">"Make" Variables</h1>
+#if (!$singlePage)
<div class="toc">
<ul>
<li><a href="#make-var-substitution">"Make" variable subsitution</a></li>
@@ -17,6 +22,7 @@ title: Make Variables
<li><a href="#location">"$(location)" substitution</a></li>
</ul>
</div>
+#end
<p>
This section describes how to use a special class of built-in string variables
that are called the "Make" environment.
@@ -33,7 +39,7 @@ title: Make Variables
</p>
<p>Build rules can introduce additional rule specific variables. One example is
- the <a href="general.html#genrule.cmd"><code>cmd</code> attribute of a genrule</a>.
+ the <a href="$expander.expandRef("genrule.cmd")"><code>cmd</code> attribute of a genrule</a>.
</p>
<h2 id='make-var-substitution'>"Make" variable substitution</h2>
@@ -142,7 +148,7 @@ in your genrule's cmd attribute.
<p id="predefined_variables.genrule.cmd">
<strong>
- Other Variables available to <a href="general.html#genrule.cmd">the cmd
+ Other Variables available to <a href="$expander.expandRef("genrule.cmd")">the cmd
attribute of a genrule</a>
</strong>
</p>
@@ -197,4 +203,6 @@ in your genrule's cmd attribute.
<code>*_test</code> or <code>*_binary</code> rule.
</p>
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/footer.vm")
+#end
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/overview.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/overview.vm
index a6c0e50af2..b1c299fb80 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/overview.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/overview.vm
@@ -1,8 +1,12 @@
+#if (!$singlePage)
---
layout: documentation
title: Build Encyclopedia
---
+#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+#end
<h1>Bazel BUILD Encyclopedia of Functions</h1>
<h2>Contents</h2>
@@ -11,47 +15,51 @@ title: Build Encyclopedia
<ul>
<li>
- <a href="common-definitions.html">Common definitions</a>
+ <a href="$expander.expandRef("common-definitions")">Common definitions</a>
<ul>
- <li><a href="common-definitions.html#sh-tokenization">Bourne shell tokenization</a></li>
- <li><a href="common-definitions.html#label-expansion">Label expansion</a></li>
- <li><a href="common-definitions.html#common-attributes">Common attributes</a></li>
- <li><a href="common-definitions.html#common-attributes-tests">Common attributes for tests</a></li>
- <li><a href="common-definitions.html#common-attributes-binaries">Common attributes for binaries</a></li>
- <li><a href="common-definitions.html#configurable-attributes">Configurable attributes</a></li>
- <li><a href="common-definitions.html#implicit-outputs">Implicit output targets</a></li>
+ <li><a href="$expander.expandRef("common-definitions#sh-tokenization")">Bourne shell tokenization</a></li>
+ <li><a href="$expander.expandRef("common-definitions#label-expansion")">Label expansion</a></li>
+ <li><a href="$expander.expandRef("common-definitions#common-attributes")">Common attributes</a></li>
+ <li><a href="$expander.expandRef("common-definitions#common-attributes-tests")">Common attributes for tests</a></li>
+ <li><a href="$expander.expandRef("common-definitions#common-attributes-binaries")">Common attributes for binaries</a></li>
+ <li><a href="$expander.expandRef("common-definitions#configurable-attributes")">Configurable attributes</a></li>
+ <li><a href="$expander.expandRef("common-definitions#implicit-outputs")">Implicit output targets</a></li>
</ul>
</li>
<li>
- <a href="make-variables.html">"Make" variables</a>
+ <a href="$expander.expandRef("make-variables")">"Make" variables</a>
<ul class="be-toc">
- <li><a href="make-variables.html#make-var-substitution">"Make" variable substitution</a></li>
- <li><a href="make-variables.html#predefined_variables">Predefined variables</a></li>
+ <li><a href="$expander.expandRef("make-variables#make-var-substitution")">"Make" variable substitution</a></li>
+ <li><a href="$expander.expandRef("make-variables#predefined_variables")">Predefined variables</a></li>
</ul>
</li>
- <li><a href="predefined-python-variables.html">Predefined Python Variables</a></li>
+ <li><a href="$expander.expandRef("predefined-python-variables")">Predefined Python Variables</a></li>
</ul>
<h3>Functions</h3>
<ul class="be-toc">
- <li><a href="functions.html#load">load</a></li>
+ <li><a href="$expander.expandRef("load")">load</a></li>
- <li><a href="functions.html#package">package</a></li>
- <li><a href="functions.html#package_group">package_group</a></li>
+ <li><a href="$expander.expandRef("package")">package</a></li>
+ <li><a href="$expander.expandRef("package_group")">package_group</a></li>
- <li><a href="functions.html#licenses">licenses</a></li>
- <li><a href="functions.html#exports_files">exports_files</a></li>
- <li><a href="functions.html#glob">glob</a></li>
- <li><a href="functions.html#select">select</a></li>
- <li><a href="functions.html#workspace">workspace</a></li>
+ <li><a href="$expander.expandRef("licenses")">licenses</a></li>
+ <li><a href="$expander.expandRef("exports_files")">exports_files</a></li>
+ <li><a href="$expander.expandRef("glob")">glob</a></li>
+ <li><a href="$expander.expandRef("select")">select</a></li>
+ <li><a href="$expander.expandRef("workspace")">workspace</a></li>
</ul>
<h3>Rules</h3>
<h4>Language-specific Rules</h4>
+#macro(summaryLink $page $heading)
+ #if ($singlePage)#${heading}#else${page}.html#${heading}#end
+#end
+
#macro(summaryTable $ruleFamilies)
<tbody>
#foreach($ruleFamily in $ruleFamilies)
@@ -60,7 +68,7 @@ title: Build Encyclopedia
<td class="lang">${ruleFamily.name}</td>
<td>
#foreach($ruleDoc in $ruleFamily.binaryRules)
- <a href="${ruleFamily.id}.html#${ruleDoc.ruleName}"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
+ <a href="#summaryLink(${ruleFamily.id}, ${ruleDoc.ruleName})"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
${ruleDoc.ruleName}
</a>
<br />
@@ -68,7 +76,7 @@ title: Build Encyclopedia
</td>
<td>
#foreach($ruleDoc in $ruleFamily.libraryRules)
- <a href="${ruleFamily.id}.html#${ruleDoc.ruleName}"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
+ <a href="#summaryLink(${ruleFamily.id}, ${ruleDoc.ruleName})"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
${ruleDoc.ruleName}
</a>
<br />
@@ -76,7 +84,7 @@ title: Build Encyclopedia
</td>
<td>
#foreach($ruleDoc in $ruleFamily.testRules)
- <a href="${ruleFamily.id}.html#${ruleDoc.ruleName}"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
+ <a href="#summaryLink(${ruleFamily.id}, ${ruleDoc.ruleName})"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
${ruleDoc.ruleName}
</a>
<br />
@@ -84,7 +92,7 @@ title: Build Encyclopedia
</td>
<td>
#foreach($ruleDoc in $ruleFamily.otherRules1)
- <a href="${ruleFamily.id}.html#${ruleDoc.ruleName}"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
+ <a href="#summaryLink(${ruleFamily.id}, ${ruleDoc.ruleName})"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
${ruleDoc.ruleName}
</a>
<br />
@@ -92,7 +100,7 @@ title: Build Encyclopedia
</td>
<td>
#foreach($ruleDoc in $ruleFamily.otherRules2)
- <a href="${ruleFamily.id}.html#${ruleDoc.ruleName}"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
+ <a href="#summaryLink(${ruleFamily.id}, ${ruleDoc.ruleName})"#if($ruleDoc.isDeprecated()) class="deprecated"#end>
${ruleDoc.ruleName}
</a>
<br />
@@ -126,4 +134,6 @@ title: Build Encyclopedia
#summaryTable($genericRuleFamilies)
</table>
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/footer.vm")
+#end
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/predefined-python-variables.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/predefined-python-variables.vm
index c50fb8a2ba..bc285fec50 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/predefined-python-variables.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/predefined-python-variables.vm
@@ -1,17 +1,23 @@
+#if (!$singlePage)
---
layout: documentation
title: Predefined Python Variables
---
+#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+#end
<h2 id="predefined-python-variables">Predefined Python Variables</h2>
+#if (!$singlePage)
<div class="toc">
<h1>Contents</h1>
<ul>
<li><a href="#packagename">packagename</a></li>
</ul>
</div>
+#end
<h3 id="packagename">PACKAGE_NAME</h3>
<p>
This is a string variable with the name
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/rules.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/rules.vm
index 9e9345cf62..9958a6f2f9 100644
--- a/src/main/java/com/google/devtools/build/docgen/templates/be/rules.vm
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/rules.vm
@@ -1,8 +1,12 @@
+#if (!$singlePage)
---
layout: documentation
title: ${ruleFamily.name} Rules
---
+#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+#end
<h1>${ruleFamily.name} Rules</h1>
@@ -70,4 +74,6 @@ title: ${ruleFamily.name} Rules
#end
#end
+#if (!$singlePage)
#parse("com/google/devtools/build/docgen/templates/be/footer.vm")
+#end
diff --git a/src/main/java/com/google/devtools/build/docgen/templates/be/single-page.vm b/src/main/java/com/google/devtools/build/docgen/templates/be/single-page.vm
new file mode 100644
index 0000000000..23cb684b00
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/docgen/templates/be/single-page.vm
@@ -0,0 +1,28 @@
+#parse("com/google/devtools/build/docgen/templates/be/header.vm")
+
+#parse("com/google/devtools/build/docgen/templates/be/overview.vm")
+
+<hr>
+
+#parse("com/google/devtools/build/docgen/templates/be/common-definitions.vm")
+
+<hr>
+
+#parse("com/google/devtools/build/docgen/templates/be/make-variables.vm")
+
+<hr>
+
+#parse("com/google/devtools/build/docgen/templates/be/predefined-python-variables.vm")
+
+<hr>
+
+#parse("com/google/devtools/build/docgen/templates/be/functions.vm")
+
+#foreach ($ruleFamily in $ruleFamilies)
+<hr>
+
+#parse("com/google/devtools/build/docgen/templates/be/rules.vm")
+
+#end
+
+#parse("com/google/devtools/build/docgen/templates/be/footer.vm")