Add new flag to Stardoc and allows Stardoc to output raw serialized proto. Progress toward https://github.com/bazelbuild/skydoc/issues/189 PiperOrigin-RevId: 253128175
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 325716d..900f613 100644 --- a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java +++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -66,6 +66,7 @@ import com.google.devtools.build.lib.syntax.SkylarkImport; import com.google.devtools.build.lib.syntax.StarlarkSemantics; import com.google.devtools.build.lib.syntax.UserDefinedFunction; +import com.google.devtools.build.skydoc.SkydocOptions.OutputFormat; import com.google.devtools.build.skydoc.fakebuildapi.FakeActionsInfoProvider; import com.google.devtools.build.skydoc.fakebuildapi.FakeBuildApiGlobals; import com.google.devtools.build.skydoc.fakebuildapi.FakeConfigApi; @@ -110,12 +111,15 @@ import com.google.devtools.build.skydoc.rendering.DocstringParseException; import com.google.devtools.build.skydoc.rendering.FunctionUtil; import com.google.devtools.build.skydoc.rendering.MarkdownRenderer; +import com.google.devtools.build.skydoc.rendering.ProtoRenderer; import com.google.devtools.build.skydoc.rendering.ProviderInfoWrapper; import com.google.devtools.build.skydoc.rendering.RuleInfoWrapper; import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderInfo; import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo; import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.UserDefinedFunctionInfo; import com.google.devtools.common.options.OptionsParser; +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.NoSuchFileException; @@ -171,7 +175,8 @@ } public static void main(String[] args) - throws IOException, InterruptedException, LabelSyntaxException, EvalException { + throws IOException, InterruptedException, LabelSyntaxException, EvalException, + DocstringParseException { OptionsParser parser = OptionsParser.newOptionsParser(StarlarkSemanticsOptions.class, SkydocOptions.class); parser.parseAndExitUponError(args); @@ -226,8 +231,6 @@ System.exit(1); } - MarkdownRenderer renderer = new MarkdownRenderer(); - Map<String, RuleInfo> filteredRuleInfos = ruleInfoMap.build().entrySet().stream() .filter(entry -> validSymbolName(symbolNames, entry.getKey())) @@ -240,11 +243,23 @@ userDefinedFunctions.build().entrySet().stream() .filter(entry -> validSymbolName(symbolNames, entry.getKey())) .collect(ImmutableMap.toImmutableMap(Entry::getKey, Entry::getValue)); - try (PrintWriter printWriter = new PrintWriter(outputPath, "UTF-8")) { - printWriter.println(renderer.renderMarkdownHeader()); - printRuleInfos(printWriter, renderer, filteredRuleInfos); - printProviderInfos(printWriter, renderer, filteredProviderInfos); - printUserDefinedFunctions(printWriter, renderer, filteredUserDefinedFunctions); + + if (skydocOptions.outputFormat == OutputFormat.PROTO) { + try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outputPath))) { + new ProtoRenderer() + .appendRuleInfos(filteredRuleInfos.values()) + .appendProviderInfos(filteredProviderInfos.values()) + .appendUserDefinedFunctionInfos(filteredUserDefinedFunctions) + .writeModuleInfo(out); + } + } else if (skydocOptions.outputFormat == OutputFormat.MARKDOWN) { + MarkdownRenderer renderer = new MarkdownRenderer(); + try (PrintWriter printWriter = new PrintWriter(outputPath, "UTF-8")) { + printWriter.println(renderer.renderMarkdownHeader()); + printRuleInfos(printWriter, renderer, filteredRuleInfos); + printProviderInfos(printWriter, renderer, filteredProviderInfos); + printUserDefinedFunctions(printWriter, renderer, filteredUserDefinedFunctions); + } } }
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java b/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java index d223e8c..8408bf8 100644 --- a/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java +++ b/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java
@@ -14,6 +14,7 @@ package com.google.devtools.build.skydoc; +import com.google.devtools.common.options.EnumConverter; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionDocumentationCategory; import com.google.devtools.common.options.OptionEffectTag; @@ -48,6 +49,15 @@ public String outputFilePath; @Option( + name = "output_format", + defaultValue = "markdown", + converter = OutputFormatConverter.class, + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = OptionEffectTag.UNKNOWN, + help = "The format choice for the output file (\"markdown\" or \"proto\").") + public OutputFormat outputFormat; + + @Option( name = "symbols", allowMultiple = true, defaultValue = "", @@ -64,4 +74,21 @@ effectTags = OptionEffectTag.UNKNOWN, help = "File path roots to search when resolving transitive bzl dependencies") public List<String> depRoots; + + /** Converter for {@link OutputFormat} */ + public static class OutputFormatConverter extends EnumConverter<OutputFormat> { + + public OutputFormatConverter() { + super(OutputFormat.class, "output format"); + } + } + + /** + * The possible values for the --output_format flag, which controls the format of Stardoc's output + * file. + */ + public enum OutputFormat { + MARKDOWN, + PROTO + } }
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/ProtoRenderer.java b/src/main/java/com/google/devtools/build/skydoc/rendering/ProtoRenderer.java new file mode 100644 index 0000000..1d42833 --- /dev/null +++ b/src/main/java/com/google/devtools/build/skydoc/rendering/ProtoRenderer.java
@@ -0,0 +1,69 @@ +// Copyright 2019 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.skydoc.rendering; + +import com.google.devtools.build.lib.syntax.UserDefinedFunction; +import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ModuleInfo; +import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderInfo; +import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo; +import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.UserDefinedFunctionInfo; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +/** Produces skydoc output in proto form. */ +public class ProtoRenderer { + + private final ModuleInfo.Builder moduleInfo; + + public ProtoRenderer() { + this.moduleInfo = ModuleInfo.newBuilder(); + } + + /** Appends {@link RuleInfo} protos to a {@link ModuleInfo.Builder}. */ + public ProtoRenderer appendRuleInfos(Collection<RuleInfo> ruleInfos) { + for (RuleInfo ruleInfo : ruleInfos) { + moduleInfo.addRuleInfo(ruleInfo); + } + return this; + } + + /** Appends {@link ProviderInfo} protos to a {@link ModuleInfo.Builder}. */ + public ProtoRenderer appendProviderInfos(Collection<ProviderInfoWrapper> providerInfoWrappers) { + for (ProviderInfoWrapper providerInfoWrapper : providerInfoWrappers) { + ProviderInfo providerInfo = providerInfoWrapper.getProviderInfo(); + moduleInfo.addProviderInfo(providerInfo); + } + return this; + } + + /** Appends {@link UserDefinedFunctionInfo} protos to a {@link ModuleInfo.Builder}. */ + public ProtoRenderer appendUserDefinedFunctionInfos(Map<String, UserDefinedFunction> funcInfosMap) + throws DocstringParseException { + for (Map.Entry<String, UserDefinedFunction> entry : funcInfosMap.entrySet()) { + UserDefinedFunctionInfo funcInfo = + FunctionUtil.fromNameAndFunction(entry.getKey(), entry.getValue()); + moduleInfo.addFuncInfo(funcInfo); + } + return this; + } + + /** Outputs the raw form of a {@link ModuleInfo} proto. */ + public void writeModuleInfo(BufferedOutputStream outputStream) throws IOException { + ModuleInfo build = moduleInfo.build(); + build.writeTo(outputStream); + } +}
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto b/src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto index 539245a..b567484 100644 --- a/src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto +++ b/src/main/java/com/google/devtools/build/skydoc/rendering/proto/stardoc_output.proto
@@ -23,6 +23,17 @@ option java_package = "com.google.devtools.build.skydoc.rendering.proto"; option java_outer_classname = "StardocOutputProtos"; +// The root output proto of Stardoc. A single invocation of Stardoc will output +// exactly one instance of this proto, representing all documentation for +// the input Starlark file. +message ModuleInfo { + repeated RuleInfo rule_info = 1; + + repeated ProviderInfo provider_info = 2; + + repeated UserDefinedFunctionInfo func_info = 3; +} + // Representation of a Starlark rule attribute type. These generally // have a one-to-one correspondence with functions defined at // https://docs.bazel.build/versions/master/skylark/lib/attr.html.