Support user-defined function documentation in Stardoc.
RELNOTES: None.
PiperOrigin-RevId: 220525539
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
index dfc7a4a..7a15a51 100644
--- a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -40,6 +40,7 @@
import com.google.devtools.build.lib.syntax.ParserInputSource;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkImport;
+import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.skydoc.fakebuildapi.FakeActionsInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.FakeBuildApiGlobals;
import com.google.devtools.build.skydoc.fakebuildapi.FakeConfigApi;
@@ -72,6 +73,8 @@
import com.google.devtools.build.skydoc.rendering.MarkdownRenderer;
import com.google.devtools.build.skydoc.rendering.ProviderInfo;
import com.google.devtools.build.skydoc.rendering.RuleInfo;
+import com.google.devtools.build.skydoc.rendering.UserDefinedFunctionInfo;
+import com.google.devtools.build.skydoc.rendering.UserDefinedFunctionInfo.DocstringParseException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.NoSuchFileException;
@@ -83,6 +86,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.TreeMap;
import java.util.stream.Collectors;
/**
@@ -132,9 +136,11 @@
ImmutableMap.Builder<String, RuleInfo> ruleInfoMap = ImmutableMap.builder();
ImmutableMap.Builder<String, ProviderInfo> providerInfoMap = ImmutableMap.builder();
ImmutableList.Builder<RuleInfo> unknownNamedRules = ImmutableList.builder();
+ ImmutableMap.Builder<String, UserDefinedFunction> userDefinedFunctions = ImmutableMap.builder();
new SkydocMain(new FilesystemFileAccessor())
- .eval(targetFileLabel, ruleInfoMap, unknownNamedRules, providerInfoMap);
+ .eval(
+ targetFileLabel, ruleInfoMap, unknownNamedRules, providerInfoMap, userDefinedFunctions);
MarkdownRenderer renderer = new MarkdownRenderer();
@@ -142,6 +148,7 @@
try (PrintWriter printWriter = new PrintWriter(outputPath, "UTF-8")) {
printRuleInfos(printWriter, renderer, ruleInfoMap.build(), unknownNamedRules.build());
printProviderInfos(printWriter, renderer, providerInfoMap.build());
+ printUserDefinedFunctions(printWriter, renderer, userDefinedFunctions.build());
}
} else {
Map<String, RuleInfo> filteredRuleInfos =
@@ -152,9 +159,14 @@
providerInfoMap.build().entrySet().stream()
.filter(entry -> symbolNames.contains(entry.getKey()))
.collect(ImmutableMap.toImmutableMap(Entry::getKey, Entry::getValue));
+ Map<String, UserDefinedFunction> filteredUserDefinedFunctions =
+ userDefinedFunctions.build().entrySet().stream()
+ .filter(entry -> symbolNames.contains(entry.getKey()))
+ .collect(ImmutableMap.toImmutableMap(Entry::getKey, Entry::getValue));
try (PrintWriter printWriter = new PrintWriter(outputPath, "UTF-8")) {
printRuleInfos(printWriter, renderer, filteredRuleInfos, ImmutableList.of());
printProviderInfos(printWriter, renderer, filteredProviderInfos);
+ printUserDefinedFunctions(printWriter, renderer, filteredUserDefinedFunctions);
}
}
}
@@ -192,6 +204,24 @@
}
}
+ private static void printUserDefinedFunctions(
+ PrintWriter printWriter,
+ MarkdownRenderer renderer,
+ Map<String, UserDefinedFunction> userDefinedFunctions)
+ throws IOException {
+ for (Entry<String, UserDefinedFunction> entry : userDefinedFunctions.entrySet()) {
+ try {
+ UserDefinedFunctionInfo functionInfo =
+ UserDefinedFunctionInfo.fromNameAndFunction(entry.getKey(), entry.getValue());
+ printUserDefinedFunctionInfo(printWriter, renderer, functionInfo);
+ printWriter.println();
+ } catch (DocstringParseException exception) {
+ System.err.println(exception.getMessage());
+ System.err.println();
+ }
+ }
+ }
+
private static void printRuleInfo(
PrintWriter printWriter, MarkdownRenderer renderer,
String exportedName, RuleInfo ruleInfo) throws IOException {
@@ -204,6 +234,12 @@
printWriter.println(renderer.render(exportedName, providerInfo));
}
+ private static void printUserDefinedFunctionInfo(
+ PrintWriter printWriter, MarkdownRenderer renderer, UserDefinedFunctionInfo functionInfo)
+ throws IOException {
+ printWriter.println(renderer.render(functionInfo));
+ }
+
/**
* Evaluates/interprets the skylark file at a given path and its transitive skylark dependencies
* using a fake build API and collects information about all rule definitions made in the root
@@ -216,16 +252,20 @@
* @param unknownNamedRules a list builder to be populated with rule definition information for
* rules which were not exported as top level symbols
* @param providerInfoMap a map builder to be populated with provider definition information for
- * named providers. Keys are exported names of providers, and values are their
- * {@link ProviderInfo} descriptions. For example, 'my_provider = provider(...)' has key
+ * named providers. Keys are exported names of providers, and values are their {@link
+ * ProviderInfo} descriptions. For example, 'my_provider = provider(...)' has key
* 'my_provider'
+ * @param userDefinedFunctionMap a map builder to be populated with user-defined functions. Keys
+ * are exported names of functions, and values are the {@link UserDefinedFunction} objects.
+ * For example, 'def my_function(foo):' is a function with key 'my_function'.
* @throws InterruptedException if evaluation is interrupted
*/
public Environment eval(
Label label,
ImmutableMap.Builder<String, RuleInfo> ruleInfoMap,
ImmutableList.Builder<RuleInfo> unknownNamedRules,
- ImmutableMap.Builder<String, ProviderInfo> providerInfoMap)
+ ImmutableMap.Builder<String, ProviderInfo> providerInfoMap,
+ ImmutableMap.Builder<String, UserDefinedFunction> userDefinedFunctionMap)
throws InterruptedException, IOException, LabelSyntaxException {
List<RuleInfo> ruleInfoList = new ArrayList<>();
@@ -242,7 +282,11 @@
Functions.identity()));
ImmutableSet.Builder<RuleInfo> handledRuleDefinitions = ImmutableSet.builder();
- for (Entry<String, Object> envEntry : env.getGlobals().getBindings().entrySet()) {
+
+ // Sort the bindings so their ordering is deterministic.
+ TreeMap<String, Object> sortedBindings = new TreeMap<>(env.getGlobals().getBindings());
+
+ for (Entry<String, Object> envEntry : sortedBindings.entrySet()) {
if (ruleFunctions.containsKey(envEntry.getValue())) {
RuleInfo ruleInfo = ruleFunctions.get(envEntry.getValue());
ruleInfoMap.put(envEntry.getKey(), ruleInfo);
@@ -252,6 +296,10 @@
ProviderInfo providerInfo = providerInfos.get(envEntry.getValue());
providerInfoMap.put(envEntry.getKey(), providerInfo);
}
+ if (envEntry.getValue() instanceof UserDefinedFunction) {
+ UserDefinedFunction userDefinedFunction = (UserDefinedFunction) envEntry.getValue();
+ userDefinedFunctionMap.put(envEntry.getKey(), userDefinedFunction);
+ }
}
unknownNamedRules.addAll(ruleFunctions.values().stream()