Rework Stardoc's command line processing to use @Option and accept semantic flags
For backward compatibility, both new and old arg processing remains briefly intact. stardoc.bzl (in the skydoc repository) will be updated subject to this change, and then Stardoc's integration tests can be updated to point to the new stardoc.bzl version.
Regression testing is thus excluded from this CL, but will be fixed with these followups.
RELNOTES: None.
PiperOrigin-RevId: 222466690
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index af2a42b..bbaef61 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -385,6 +385,19 @@
],
)
+java_library(
+ name = "skylark_semantics_options",
+ srcs = [
+ "packages/SkylarkSemanticsOptions.java",
+ ],
+ deps = [
+ ":skylark_semantics",
+ "//src/main/java/com/google/devtools/common/options",
+ "//third_party:auto_value",
+ "//third_party:guava",
+ ],
+)
+
# Provides core configuration transition abstractions and Blaze-common (i.e not
# rule-specific) transitions.
java_library(
diff --git a/src/main/java/com/google/devtools/build/skydoc/BUILD b/src/main/java/com/google/devtools/build/skydoc/BUILD
index 80db967..869ea9b 100644
--- a/src/main/java/com/google/devtools/build/skydoc/BUILD
+++ b/src/main/java/com/google/devtools/build/skydoc/BUILD
@@ -49,8 +49,11 @@
java_library(
name = "skydoc_lib",
srcs = glob(["*.java"]),
+ visibility = ["//src/test:__subpackages__"],
deps = [
"//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:skylark_semantics",
+ "//src/main/java/com/google/devtools/build/lib:skylark_semantics_options",
"//src/main/java/com/google/devtools/build/lib:syntax",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi",
@@ -73,6 +76,7 @@
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/repository",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi/test",
"//src/main/java/com/google/devtools/build/skydoc/rendering",
+ "//src/main/java/com/google/devtools/common/options",
"//third_party:guava",
],
)
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 53f22de..b86d1d0 100644
--- a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -15,12 +15,14 @@
package com.google.devtools.build.skydoc;
import com.google.common.base.Functions;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions;
import com.google.devtools.build.lib.skylarkbuildapi.TopLevelBootstrap;
import com.google.devtools.build.lib.skylarkbuildapi.android.AndroidAssetsInfoApi;
import com.google.devtools.build.lib.skylarkbuildapi.android.AndroidBinaryDataInfoApi;
@@ -56,6 +58,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.SkylarkSemantics;
import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.skydoc.fakebuildapi.FakeActionsInfoProvider;
import com.google.devtools.build.skydoc.fakebuildapi.FakeBuildApiGlobals;
@@ -91,6 +94,7 @@
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 com.google.devtools.common.options.OptionsParser;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.NoSuchFileException;
@@ -137,17 +141,37 @@
public static void main(String[] args)
throws IOException, InterruptedException, LabelSyntaxException {
- if (args.length < 2) {
- throw new IllegalArgumentException("Expected two or more arguments. Usage:\n"
- + "{skydoc_bin} {target_skylark_file_label} {output_file} [symbol_names]...");
- }
+ OptionsParser parser =
+ OptionsParser.newOptionsParser(SkylarkSemanticsOptions.class, SkydocOptions.class);
+ parser.parseAndExitUponError(args);
+ SkylarkSemanticsOptions semanticsOptions = parser.getOptions(SkylarkSemanticsOptions.class);
+ SkydocOptions skydocOptions = parser.getOptions(SkydocOptions.class);
- String targetFileLabelString = args[0];
- String outputPath = args[1];
+ String targetFileLabelString;
+ String outputPath;
+ ImmutableSet<String> symbolNames;
+
+ // TODO(cparsons): Remove optional positional arg parsing.
+ List<String> residualArgs = parser.getResidue();
+ if (Strings.isNullOrEmpty(skydocOptions.targetFileLabel)
+ || Strings.isNullOrEmpty(skydocOptions.outputFilePath)) {
+ if (residualArgs.size() < 2) {
+ throw new IllegalArgumentException(
+ "Expected two or more arguments. Usage:\n"
+ + "{skydoc_bin} {target_skylark_file_label} {output_file} [symbol_names]...");
+ }
+
+ targetFileLabelString = residualArgs.get(0);
+ outputPath = residualArgs.get(1);
+ symbolNames = getSymbolNames(residualArgs);
+ } else {
+ targetFileLabelString = skydocOptions.targetFileLabel;
+ outputPath = skydocOptions.outputFilePath;
+ symbolNames = ImmutableSet.copyOf(skydocOptions.symbolNames);
+ }
Label targetFileLabel =
Label.parseAbsolute(targetFileLabelString, ImmutableMap.of());
- ImmutableSet<String> symbolNames = getSymbolNames(args);
ImmutableMap.Builder<String, RuleInfo> ruleInfoMap = ImmutableMap.builder();
ImmutableMap.Builder<String, ProviderInfo> providerInfoMap = ImmutableMap.builder();
@@ -156,7 +180,12 @@
new SkydocMain(new FilesystemFileAccessor())
.eval(
- targetFileLabel, ruleInfoMap, unknownNamedRules, providerInfoMap, userDefinedFunctions);
+ semanticsOptions.toSkylarkSemantics(),
+ targetFileLabel,
+ ruleInfoMap,
+ unknownNamedRules,
+ providerInfoMap,
+ userDefinedFunctions);
MarkdownRenderer renderer = new MarkdownRenderer();
@@ -187,10 +216,10 @@
}
}
- private static ImmutableSet<String> getSymbolNames(String[] args) {
+ private static ImmutableSet<String> getSymbolNames(List<String> args) {
ImmutableSet.Builder<String> symbolNameSet = ImmutableSet.builder();
- for (int argi = 2; argi < args.length; argi++) {
- symbolNameSet.add(args[argi]);
+ for (int argi = 2; argi < args.size(); argi++) {
+ symbolNameSet.add(args.get(argi));
}
return symbolNameSet.build();
}
@@ -277,6 +306,7 @@
* @throws InterruptedException if evaluation is interrupted
*/
public Environment eval(
+ SkylarkSemantics semantics,
Label label,
ImmutableMap.Builder<String, RuleInfo> ruleInfoMap,
ImmutableList.Builder<RuleInfo> unknownNamedRules,
@@ -286,7 +316,7 @@
List<RuleInfo> ruleInfoList = new ArrayList<>();
List<ProviderInfo> providerInfoList = new ArrayList<>();
- Environment env = recursiveEval(label, ruleInfoList, providerInfoList);
+ Environment env = recursiveEval(semantics, label, ruleInfoList, providerInfoList);
Map<BaseFunction, RuleInfo> ruleFunctions = ruleInfoList.stream()
.collect(Collectors.toMap(
@@ -326,8 +356,8 @@
/**
* Recursively 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 those files.
+ * dependencies using a fake build API and collects information about all rule definitions made in
+ * those files.
*
* @param label the label of the skylark file to evaluate
* @param ruleInfoList a collection of all rule definitions made so far (using rule()); this
@@ -335,7 +365,10 @@
* @throws InterruptedException if evaluation is interrupted
*/
private Environment recursiveEval(
- Label label, List<RuleInfo> ruleInfoList, List<ProviderInfo> providerInfoList)
+ SkylarkSemantics semantics,
+ Label label,
+ List<RuleInfo> ruleInfoList,
+ List<ProviderInfo> providerInfoList)
throws InterruptedException, IOException, LabelSyntaxException {
Path path = pathOfLabel(label);
@@ -354,7 +387,8 @@
Label relativeLabel = label.getRelative(anImport.getImportString());
try {
- Environment importEnv = recursiveEval(relativeLabel, ruleInfoList, providerInfoList);
+ Environment importEnv =
+ recursiveEval(semantics, relativeLabel, ruleInfoList, providerInfoList);
imports.put(anImport.getImportString(), new Extension(importEnv));
} catch (NoSuchFileException noSuchFileException) {
throw new IllegalStateException(
@@ -363,7 +397,8 @@
}
}
- Environment env = evalSkylarkBody(buildFileAST, imports, ruleInfoList, providerInfoList);
+ Environment env =
+ evalSkylarkBody(semantics, buildFileAST, imports, ruleInfoList, providerInfoList);
pending.remove(path);
env.mutability().freeze();
@@ -379,19 +414,18 @@
return Paths.get(workspacePrefix + label.toPathFragment());
}
- /**
- * Evaluates the AST from a single skylark file, given the already-resolved imports.
- */
+ /** Evaluates the AST from a single skylark file, given the already-resolved imports. */
private Environment evalSkylarkBody(
+ SkylarkSemantics semantics,
BuildFileAST buildFileAST,
Map<String, Extension> imports,
List<RuleInfo> ruleInfoList,
- List<ProviderInfo> providerInfoList) throws InterruptedException {
+ List<ProviderInfo> providerInfoList)
+ throws InterruptedException {
- Environment env = createEnvironment(
- eventHandler,
- globalFrame(ruleInfoList, providerInfoList),
- imports);
+ Environment env =
+ createEnvironment(
+ semantics, eventHandler, globalFrame(ruleInfoList, providerInfoList), imports);
if (!buildFileAST.exec(env, eventHandler)) {
throw new RuntimeException("Error loading file");
@@ -485,10 +519,13 @@
}
}
- private static Environment createEnvironment(EventHandler eventHandler, GlobalFrame globals,
+ private static Environment createEnvironment(
+ SkylarkSemantics semantics,
+ EventHandler eventHandler,
+ GlobalFrame globals,
Map<String, Extension> imports) {
return Environment.builder(Mutability.create("Skydoc"))
- .useDefaultSemantics()
+ .setSemantics(semantics)
.setGlobals(globals)
.setImportedExtensions(imports)
.setEventHandler(eventHandler)
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java b/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java
new file mode 100644
index 0000000..aa561f5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocOptions.java
@@ -0,0 +1,50 @@
+// Copyright 2018 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;
+
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionDocumentationCategory;
+import com.google.devtools.common.options.OptionEffectTag;
+import com.google.devtools.common.options.OptionsBase;
+import java.util.List;
+
+/** Contains options for running {@link SkydocMain}. */
+public class SkydocOptions extends OptionsBase {
+
+ @Option(
+ name = "input",
+ defaultValue = "",
+ documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+ effectTags = OptionEffectTag.UNKNOWN,
+ help = "The label of the target file for which to generate documentation")
+ public String targetFileLabel;
+
+ @Option(
+ name = "output",
+ defaultValue = "",
+ documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+ effectTags = OptionEffectTag.UNKNOWN,
+ help = "The path of the file to output documentation into")
+ public String outputFilePath;
+
+ @Option(
+ name = "symbols",
+ allowMultiple = true,
+ defaultValue = "",
+ documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+ effectTags = OptionEffectTag.UNKNOWN,
+ help = "The path of the file to output documentation into")
+ public List<String> symbolNames;
+}
diff --git a/src/test/java/com/google/devtools/build/skydoc/BUILD b/src/test/java/com/google/devtools/build/skydoc/BUILD
index 67f68c1..05d9df3 100644
--- a/src/test/java/com/google/devtools/build/skydoc/BUILD
+++ b/src/test/java/com/google/devtools/build/skydoc/BUILD
@@ -21,6 +21,7 @@
shard_count = 1,
visibility = ["//devtools/blaze/main:__pkg__"],
deps = [
+ "//src/main/java/com/google/devtools/build/lib:skylark_semantics",
"//src/main/java/com/google/devtools/build/lib:syntax",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/vfs",
diff --git a/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java b/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java
index c0c98f7..e89f49a 100644
--- a/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java
+++ b/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java
@@ -23,6 +23,7 @@
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
import com.google.devtools.build.lib.syntax.ParserInputSource;
+import com.google.devtools.build.lib.syntax.SkylarkSemantics;
import com.google.devtools.build.lib.syntax.UserDefinedFunction;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
@@ -82,6 +83,7 @@
ImmutableList.Builder<RuleInfo> unexportedRuleInfos = ImmutableList.builder();
skydocMain.eval(
+ SkylarkSemantics.DEFAULT_SEMANTICS,
Label.parseAbsoluteUnchecked("//test:test.bzl"),
ruleInfoMap,
unexportedRuleInfos,
@@ -145,6 +147,7 @@
ImmutableList.Builder<RuleInfo> unexportedRuleInfos = ImmutableList.builder();
skydocMain.eval(
+ SkylarkSemantics.DEFAULT_SEMANTICS,
Label.parseAbsoluteUnchecked("//test:test.bzl"),
ruleInfoMap,
unexportedRuleInfos,
@@ -198,6 +201,7 @@
ImmutableMap.Builder<String, RuleInfo> ruleInfoMapBuilder = ImmutableMap.builder();
skydocMain.eval(
+ SkylarkSemantics.DEFAULT_SEMANTICS,
Label.parseAbsoluteUnchecked("//test:main.bzl"),
ruleInfoMapBuilder,
ImmutableList.builder(),
@@ -252,6 +256,7 @@
ImmutableMap.Builder<String, RuleInfo> ruleInfoMapBuilder = ImmutableMap.builder();
skydocMain.eval(
+ SkylarkSemantics.DEFAULT_SEMANTICS,
Label.parseAbsoluteUnchecked("//test:main.bzl"),
ruleInfoMapBuilder,
ImmutableList.builder(),
@@ -293,6 +298,7 @@
IllegalStateException.class,
() ->
skydocMain.eval(
+ SkylarkSemantics.DEFAULT_SEMANTICS,
Label.parseAbsoluteUnchecked("//test:main.bzl"),
ruleInfoMapBuilder,
ImmutableList.builder(),
@@ -325,6 +331,7 @@
ImmutableMap.Builder<String, UserDefinedFunction> functionInfoBuilder = ImmutableMap.builder();
skydocMain.eval(
+ SkylarkSemantics.DEFAULT_SEMANTICS,
Label.parseAbsoluteUnchecked("//test:main.bzl"),
ImmutableMap.builder(),
ImmutableList.builder(),