aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar cparsons <cparsons@google.com>2018-06-26 13:47:28 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-06-26 13:49:42 -0700
commit5d85e75601b1c82bbc1358d399afa3e07e87a766 (patch)
tree33a4b7a558e517f3abfa81bd081999758fabd6b1
parent06b4928a5d005f6738f1ad43783c1167c2ab20a3 (diff)
Initial check-in of skydoc rewrite.
This skydoc rewrite uses an actual skylark interpreter with a faked build API (implementing the actual build API that Bazel uses). There's a lot left to do here, this is a barebones start. For example, this does not yet handle: - load() statements - non-global build API elements (e.g. apple_common) - output of any rule information other than attribute names - markdown output format RELNOTES: None. PiperOrigin-RevId: 202187207
-rw-r--r--src/BUILD2
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleFunctionsApi.java10
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/BUILD44
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/SkydocMain.java190
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/SystemOutEventHandler.java50
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/BUILD25
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeActionsInfoProvider.java27
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeBuildApiGlobals.java33
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDefaultInfoProvider.java38
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDescriptor.java30
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeOutputGroupInfo.java57
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkAttrApi.java121
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkCommandLineApi.java29
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkNativeModuleApi.java72
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java103
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStructApi.java88
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/rendering/BUILD21
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java58
-rw-r--r--src/test/java/com/google/devtools/build/skydoc/BUILD83
-rw-r--r--src/test/java/com/google/devtools/build/skydoc/SkydocTest.java67
-rw-r--r--src/test/java/com/google/devtools/build/skydoc/simple_test/golden.txt3
-rw-r--r--src/test/java/com/google/devtools/build/skydoc/simple_test/input.txt13
-rwxr-xr-xsrc/test/java/com/google/devtools/build/skydoc/skydoc_e2e_test_runner.sh38
-rw-r--r--src/test/java/com/google/devtools/build/skydoc/unknown_name_test/golden.txt2
-rw-r--r--src/test/java/com/google/devtools/build/skydoc/unknown_name_test/input.txt12
27 files changed, 1217 insertions, 11 deletions
diff --git a/src/BUILD b/src/BUILD
index c6f81377b1..7062b4df5d 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -324,6 +324,7 @@ filegroup(
"//src/main/cpp:srcs",
"//src/main/java/com/google/devtools/build/docgen:srcs",
"//src/main/java/com/google/devtools/build/lib:srcs",
+ "//src/main/java/com/google/devtools/build/skydoc:srcs",
"//src/main/java/com/google/devtools/build/skyframe:srcs",
"//src/main/java/com/google/devtools/common/options:srcs",
"//src/main/java/com/google/devtools/skylark:srcs",
@@ -340,6 +341,7 @@ filegroup(
"//src/test/java/com/google/devtools/build/docgen:srcs",
"//src/test/java/com/google/devtools/build/lib:srcs",
"//src/test/java/com/google/devtools/build/lib/shell:srcs",
+ "//src/test/java/com/google/devtools/build/skydoc:srcs",
"//src/test/java/com/google/devtools/build/skyframe:srcs",
"//src/test/java/com/google/devtools/common/options:srcs",
"//src/test/py/bazel:srcs",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
index e85915f3b9..85e3b9786e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
@@ -415,12 +415,12 @@ public class SkylarkRuleClassFunctions implements SkylarkRuleFunctionsApi<Artifa
@Override
public SkylarkAspect aspect(
BaseFunction implementation,
- SkylarkList attributeAspects,
+ SkylarkList<?> attributeAspects,
Object attrs,
- SkylarkList requiredAspectProvidersArg,
- SkylarkList providesArg,
- SkylarkList fragments,
- SkylarkList hostFragments,
+ SkylarkList<?> requiredAspectProvidersArg,
+ SkylarkList<?> providesArg,
+ SkylarkList<?> fragments,
+ SkylarkList<?> hostFragments,
SkylarkList<?> toolchains,
String doc,
FuncallExpression ast,
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java
index d9e0bebba5..edc3fb8165 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java
@@ -792,7 +792,7 @@ public interface SkylarkAttrApi extends SkylarkValue {
useEnvironment = true)
public Descriptor outputListAttribute(
Boolean allowEmpty,
- SkylarkList defaultList,
+ SkylarkList<?> defaultList,
String doc,
Boolean mandatory,
Boolean nonEmpty,
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleFunctionsApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleFunctionsApi.java
index 1f7a7e0dd6..84abfe1bce 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleFunctionsApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleFunctionsApi.java
@@ -429,12 +429,12 @@ public interface SkylarkRuleFunctionsApi<FileApiT extends FileApi> {
)
public SkylarkAspectApi aspect(
BaseFunction implementation,
- SkylarkList attributeAspects,
+ SkylarkList<?> attributeAspects,
Object attrs,
- SkylarkList requiredAspectProvidersArg,
- SkylarkList providesArg,
- SkylarkList fragments,
- SkylarkList hostFragments,
+ SkylarkList<?> requiredAspectProvidersArg,
+ SkylarkList<?> providesArg,
+ SkylarkList<?> fragments,
+ SkylarkList<?> hostFragments,
SkylarkList<?> toolchains,
String doc,
FuncallExpression ast,
diff --git a/src/main/java/com/google/devtools/build/skydoc/BUILD b/src/main/java/com/google/devtools/build/skydoc/BUILD
new file mode 100644
index 0000000000..d3bcf4b101
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/BUILD
@@ -0,0 +1,44 @@
+# Description:
+# Skydoc is a documentation generator for skylark files.
+#
+# It is currently experimental and in development.
+#
+# Usage:
+# skydoc <target_file> <output_file>
+
+package(
+ default_visibility = ["//src:__subpackages__"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]) + [
+ "//src/main/java/com/google/devtools/build/skydoc/fakebuildapi:srcs",
+ "//src/main/java/com/google/devtools/build/skydoc/rendering:srcs",
+ ],
+)
+
+java_binary(
+ name = "skydoc",
+ main_class = "com.google.devtools.build.skydoc.SkydocMain",
+ runtime_deps = [
+ ":skydoc_lib",
+ ],
+)
+
+java_library(
+ name = "skydoc_lib",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:syntax",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi",
+ "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
+ "//src/main/java/com/google/devtools/build/skydoc/fakebuildapi",
+ "//src/main/java/com/google/devtools/build/skydoc/rendering",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
new file mode 100644
index 0000000000..1e14cc1a16
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/SkydocMain.java
@@ -0,0 +1,190 @@
+// 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 static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.TopLevelBootstrap;
+import com.google.devtools.build.lib.syntax.BuildFileAST;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.Environment.Extension;
+import com.google.devtools.build.lib.syntax.Environment.GlobalFrame;
+import com.google.devtools.build.lib.syntax.MethodLibrary;
+import com.google.devtools.build.lib.syntax.Mutability;
+import com.google.devtools.build.lib.syntax.ParserInputSource;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeActionsInfoProvider;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeBuildApiGlobals;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeDefaultInfoProvider;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeOutputGroupInfo.FakeOutputGroupInfoProvider;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeSkylarkAttrApi;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeSkylarkCommandLineApi;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeSkylarkNativeModuleApi;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeSkylarkRuleFunctionsApi;
+import com.google.devtools.build.skydoc.fakebuildapi.FakeStructApi.FakeStructProviderApi;
+import com.google.devtools.build.skydoc.rendering.RuleInfo;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main entry point for the Skydoc binary.
+ *
+ * <p>Skydoc generates human-readable documentation for relevant details of skylark files by
+ * running a skylark interpreter with a fake implementation of the build API.</p>
+ *
+ * <p>Currently, Skydoc generates documentation for skylark rule definitions (discovered by
+ * invocations of the build API function {@code rule()}.</p>
+ *
+ * <p>Usage:</p>
+ * <pre>
+ * skydoc {target_skylark_file} {output_file}
+ * </pre>
+ */
+public class SkydocMain {
+
+ // Pattern to match the assignment of a variable to a rule definition
+ // For example, 'my_rule = rule(' will match and have 'my_rule' available as group(1).
+ private static final Pattern ruleDefinitionLinePattern =
+ Pattern.compile("([^\\s]+) = rule\\(");
+
+ private final EventHandler eventHandler = new SystemOutEventHandler();
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+ if (args.length != 2) {
+ throw new IllegalArgumentException("Expected two arguments. Usage:\n"
+ + "{skydoc_bin} {target_skylark_file} {output_file}");
+ }
+
+ String bzlPath = args[0];
+ String outputPath = args[1];
+
+ Path path = Paths.get(bzlPath);
+ byte[] content = Files.readAllBytes(path);
+
+ ParserInputSource parserInputSource =
+ ParserInputSource.create(content, PathFragment.create(path.toString()));
+
+ List<RuleInfo> ruleInfoList = new SkydocMain().eval(parserInputSource);
+
+ try (PrintWriter printWriter = new PrintWriter(outputPath, "UTF-8")) {
+ printRuleInfos(printWriter, ruleInfoList);
+ }
+ }
+
+ // TODO(cparsons): Improve output (markdown or HTML).
+ private static void printRuleInfos(
+ PrintWriter printWriter, List<RuleInfo> ruleInfos) throws IOException {
+ for (RuleInfo ruleInfo : ruleInfos) {
+ Location location = ruleInfo.getLocation();
+ Path filePath = Paths.get(location.getPath().getPathString());
+ List<String> lines = Files.readAllLines(filePath, UTF_8);
+ String definingString = lines.get(location.getStartLine() - 1);
+ // Rule definitions don't specify their own visible name directly. Instead, the name of
+ // a rule is dependent on the name of the variable assigend to the return value of rule().
+ // This attempts to find a line of the form 'foo = rule(' and thus label the rule as
+ // named 'foo'.
+ // TODO(cparsons): Inspect the global bindings of the environment instead of using string
+ // matching.
+ Matcher matcher = ruleDefinitionLinePattern.matcher(definingString);
+ if (matcher.matches()) {
+ printWriter.println(matcher.group(1));
+ } else {
+ printWriter.println("<unknown name>");
+ }
+ printWriter.println(ruleInfo.getDescription());
+ }
+ }
+
+ /**
+ * Evaluates/interprets the skylark file at the given input source using a fake build API and
+ * collects information about all rule definitions made in that file.
+ *
+ * @param parserInputSource the input source representing the input skylark file
+ * @return a list of {@link RuleInfo} objects describing the rule definitions
+ * @throws InterruptedException if evaluation is interrupted
+ */
+ // TODO(cparsons): Evaluate load statements recursively.
+ public List<RuleInfo> eval(ParserInputSource parserInputSource)
+ throws InterruptedException {
+ List<RuleInfo> ruleInfoList = new ArrayList<>();
+
+ BuildFileAST buildFileAST = BuildFileAST.parseSkylarkFile(
+ parserInputSource, eventHandler);
+
+ Environment env = createEnvironment(
+ eventHandler,
+ globalFrame(ruleInfoList),
+ /* imports= */ ImmutableMap.of());
+
+ if (!buildFileAST.exec(env, eventHandler)) {
+ throw new RuntimeException("Error loading file");
+ }
+
+ env.mutability().freeze();
+
+ return ruleInfoList;
+ }
+
+ /**
+ * Initialize and return a global frame containing the fake build API.
+ *
+ * @param ruleInfoList the list of {@link RuleInfo} objects, to which rule() invocation
+ * information will be added
+ */
+ private static GlobalFrame globalFrame(List<RuleInfo> ruleInfoList) {
+ // TODO(cparsons): Complete the Fake Build API stubs. For example, implement provider(),
+ // and include the other bootstraps.
+ TopLevelBootstrap topLevelBootstrap =
+ new TopLevelBootstrap(new FakeBuildApiGlobals(),
+ new FakeSkylarkAttrApi(),
+ new FakeSkylarkCommandLineApi(),
+ new FakeSkylarkNativeModuleApi(),
+ new FakeSkylarkRuleFunctionsApi(ruleInfoList),
+ new FakeStructProviderApi(),
+ new FakeOutputGroupInfoProvider(),
+ new FakeActionsInfoProvider(),
+ new FakeDefaultInfoProvider());
+
+ ImmutableMap.Builder<String, Object> envBuilder = ImmutableMap.builder();
+
+ Runtime.addConstantsToBuilder(envBuilder);
+ MethodLibrary.addBindingsToBuilder(envBuilder);
+ topLevelBootstrap.addBindingsToBuilder(envBuilder);
+
+ return GlobalFrame.createForBuiltins(envBuilder.build());
+ }
+
+ private static Environment createEnvironment(EventHandler eventHandler, GlobalFrame globals,
+ Map<String, Extension> imports) {
+ return Environment.builder(Mutability.create("Skydoc"))
+ .useDefaultSemantics()
+ .setGlobals(globals)
+ .setImportedExtensions(imports)
+ .setEventHandler(eventHandler)
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/SystemOutEventHandler.java b/src/main/java/com/google/devtools/build/skydoc/SystemOutEventHandler.java
new file mode 100644
index 0000000000..8d45627276
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/SystemOutEventHandler.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.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+
+/**
+ * A simple {@link EventHandler} which outputs log information to system.out and system.err.
+ */
+class SystemOutEventHandler implements EventHandler {
+
+ @Override
+ public void handle(Event event) {
+ switch (event.getKind()) {
+ case ERROR:
+ case WARNING:
+ case STDERR:
+ System.err.println(messageWithLocation(event));
+ break;
+ case DEBUG:
+ case INFO:
+ case PROGRESS:
+ case STDOUT:
+ System.out.println(messageWithLocation(event));
+ break;
+ default:
+ System.err.println("Unknown message type: " + event);
+ }
+ }
+
+ private String messageWithLocation(Event event) {
+ String location = event.getLocation() == null
+ ? "<no location>"
+ : event.getLocation().print();
+ return location + ": " + event.getMessage();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/BUILD b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/BUILD
new file mode 100644
index 0000000000..766f404582
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/BUILD
@@ -0,0 +1,25 @@
+package(
+ default_visibility = ["//src:__subpackages__"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+java_library(
+ name = "fakebuildapi",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+ "//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",
+ "//src/main/java/com/google/devtools/build/skydoc/rendering",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeActionsInfoProvider.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeActionsInfoProvider.java
new file mode 100644
index 0000000000..b8643e30e8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeActionsInfoProvider.java
@@ -0,0 +1,27 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.skylarkbuildapi.ActionsInfoProviderApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+
+/**
+ * Fake implementation of {@link ActionsInfoProviderApi}.
+ */
+public class FakeActionsInfoProvider implements ActionsInfoProviderApi {
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeBuildApiGlobals.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeBuildApiGlobals.java
new file mode 100644
index 0000000000..d523070517
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeBuildApiGlobals.java
@@ -0,0 +1,33 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.LateBoundDefaultApi;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkBuildApiGlobals;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.EvalException;
+
+/**
+ * Fake implementation of {@link FakeBuildApiGlobals}.
+ */
+public class FakeBuildApiGlobals implements SkylarkBuildApiGlobals {
+
+ @Override
+ public LateBoundDefaultApi configurationField(String fragment, String name, Location loc,
+ Environment env) throws EvalException {
+ return null;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDefaultInfoProvider.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDefaultInfoProvider.java
new file mode 100644
index 0000000000..1f5eacfaa3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDefaultInfoProvider.java
@@ -0,0 +1,38 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.DefaultInfoApi;
+import com.google.devtools.build.lib.skylarkbuildapi.DefaultInfoApi.DefaultInfoApiProvider;
+import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
+import com.google.devtools.build.lib.skylarkbuildapi.RunfilesApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.EvalException;
+
+/**
+ * Fake implementation of {@link DefaultInfoApiProvider}.
+ */
+public class FakeDefaultInfoProvider implements DefaultInfoApiProvider<RunfilesApi, FileApi> {
+
+ @Override
+ public DefaultInfoApi constructor(Object files, Object runfiles, Object dataRunfiles,
+ Object defaultRunfiles, Object executable, Location loc) throws EvalException {
+ return null;
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDescriptor.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDescriptor.java
new file mode 100644
index 0000000000..77c912d6b8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeDescriptor.java
@@ -0,0 +1,30 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkAttrApi.Descriptor;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+
+/**
+ * Fake implementation of {@link Descriptor}.
+ */
+public class FakeDescriptor implements Descriptor {
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+
+ // TODO(cparsons): This class should store information about the attribute definition, for
+ // example, the attribute type.
+} \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeOutputGroupInfo.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeOutputGroupInfo.java
new file mode 100644
index 0000000000..79b7014f9a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeOutputGroupInfo.java
@@ -0,0 +1,57 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.OutputGroupInfoApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+
+/**
+ * Fake implementation of {@link OutputGroupInfoApi}.
+ */
+public class FakeOutputGroupInfo implements OutputGroupInfoApi {
+
+ @Override
+ public String toProto(Location loc) throws EvalException {
+ return "";
+ }
+
+ @Override
+ public String toJson(Location loc) throws EvalException {
+ return "";
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {
+
+ }
+
+ /**
+ * Fake implementation of {@link OutputGroupInfoApiProvider}.
+ */
+ public static class FakeOutputGroupInfoProvider implements OutputGroupInfoApiProvider {
+
+ @Override
+ public OutputGroupInfoApi constructor(SkylarkDict<?, ?> kwargs, Location loc)
+ throws EvalException {
+ return new FakeOutputGroupInfo();
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkAttrApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkAttrApi.java
new file mode 100644
index 0000000000..f9e5f8c5c5
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkAttrApi.java
@@ -0,0 +1,121 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkAttrApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+
+/**
+ * Fake implementation of {@link SkylarkAttrApi}.
+ */
+public class FakeSkylarkAttrApi implements SkylarkAttrApi {
+
+ @Override
+ public Descriptor intAttribute(Integer defaultInt, String doc, Boolean mandatory,
+ SkylarkList<?> values, FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor stringAttribute(String defaultString, String doc, Boolean mandatory,
+ SkylarkList<?> values, FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor labelAttribute(Object defaultO, String doc, Boolean executable,
+ Object allowFiles, Object allowSingleFile, Boolean mandatory, SkylarkList<?> providers,
+ Object allowRules, Boolean singleFile, Object cfg, SkylarkList<?> aspects,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor stringListAttribute(Boolean mandatory, Boolean nonEmpty, Boolean allowEmpty,
+ SkylarkList<?> defaultList, String doc, FuncallExpression ast, Environment env)
+ throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor intListAttribute(Boolean mandatory, Boolean nonEmpty, Boolean allowEmpty,
+ SkylarkList<?> defaultList, String doc, FuncallExpression ast, Environment env)
+ throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor labelListAttribute(Boolean allowEmpty, Object defaultList, String doc,
+ Object allowFiles, Object allowRules, SkylarkList<?> providers, SkylarkList<?> flags,
+ Boolean mandatory, Boolean nonEmpty, Object cfg, SkylarkList<?> aspects,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor labelKeyedStringDictAttribute(Boolean allowEmpty, Object defaultList,
+ String doc, Object allowFiles, Object allowRules, SkylarkList<?> providers,
+ SkylarkList<?> flags, Boolean mandatory, Boolean nonEmpty, Object cfg, SkylarkList<?> aspects,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor boolAttribute(Boolean defaultO, String doc, Boolean mandatory,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor outputAttribute(Object defaultO, String doc, Boolean mandatory,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor outputListAttribute(Boolean allowEmpty, SkylarkList<?> defaultList, String doc,
+ Boolean mandatory, Boolean nonEmpty, FuncallExpression ast, Environment env)
+ throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor stringDictAttribute(Boolean allowEmpty, SkylarkDict<?, ?> defaultO, String doc,
+ Boolean mandatory, Boolean nonEmpty, FuncallExpression ast, Environment env)
+ throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor stringListDictAttribute(Boolean allowEmpty, SkylarkDict<?, ?> defaultO,
+ String doc, Boolean mandatory, Boolean nonEmpty, FuncallExpression ast, Environment env)
+ throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public Descriptor licenseAttribute(Object defaultO, String doc, Boolean mandatory,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return new FakeDescriptor();
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkCommandLineApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkCommandLineApi.java
new file mode 100644
index 0000000000..8c114610c1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkCommandLineApi.java
@@ -0,0 +1,29 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkCommandLineApi;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/**
+ * Fake implementation of {@link SkylarkCommandLineApi}.
+ */
+public class FakeSkylarkCommandLineApi implements SkylarkCommandLineApi {
+
+ @Override
+ public String joinPaths(String separator, SkylarkNestedSet files) {
+ return "";
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkNativeModuleApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkNativeModuleApi.java
new file mode 100644
index 0000000000..22fa94e3e4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkNativeModuleApi.java
@@ -0,0 +1,72 @@
+// 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.fakebuildapi;
+
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkNativeModuleApi;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.Runtime.NoneType;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkList.MutableList;
+
+/**
+ * Fake implementation of {@link SkylarkNativeModuleApi}.
+ */
+public class FakeSkylarkNativeModuleApi implements SkylarkNativeModuleApi {
+
+ @Override
+ public SkylarkList<?> glob(SkylarkList<?> include, SkylarkList<?> exclude,
+ Integer excludeDirectories, FuncallExpression ast, Environment env)
+ throws EvalException, InterruptedException {
+ return MutableList.of(env);
+ }
+
+ @Override
+ public Object existingRule(String name, FuncallExpression ast, Environment env)
+ throws EvalException, InterruptedException {
+ return null;
+ }
+
+ @Override
+ public SkylarkDict<String, SkylarkDict<String, Object>> existingRules(FuncallExpression ast,
+ Environment env) throws EvalException, InterruptedException {
+ return SkylarkDict.of(env);
+ }
+
+ @Override
+ public NoneType packageGroup(String name, SkylarkList<?> packages, SkylarkList<?> includes,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return null;
+ }
+
+ @Override
+ public NoneType exportsFiles(SkylarkList<?> srcs, Object visibility, Object licenses,
+ FuncallExpression ast, Environment env) throws EvalException {
+ return null;
+ }
+
+ @Override
+ public String packageName(FuncallExpression ast, Environment env) throws EvalException {
+ return "";
+ }
+
+ @Override
+ public String repositoryName(Location location, Environment env) throws EvalException {
+ return "";
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java
new file mode 100644
index 0000000000..dcae202abc
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java
@@ -0,0 +1,103 @@
+// 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.fakebuildapi;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
+import com.google.devtools.build.lib.skylarkbuildapi.FileTypeApi;
+import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkAspectApi;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkAttrApi.Descriptor;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkRuleFunctionsApi;
+import com.google.devtools.build.lib.syntax.BaseFunction;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.skydoc.rendering.RuleInfo;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Fake implementation of {@link SkylarkRuleFunctionsApi}.
+ *
+ * <p>This fake hooks into the global {@code rule()} function, noting calls of that function
+ * with a {@link RuleInfoCollector} given in the class constructor.</p>
+ */
+public class FakeSkylarkRuleFunctionsApi implements SkylarkRuleFunctionsApi<FileApi> {
+
+ private final List<RuleInfo> ruleInfoList;
+
+ /**
+ * Constructor.
+ *
+ * @param ruleInfoList the list of {@link RuleInfo} objects to which rule() invocation information
+ * will be added
+ */
+ public FakeSkylarkRuleFunctionsApi(List<RuleInfo> ruleInfoList) {
+ this.ruleInfoList = ruleInfoList;
+ }
+
+ @Override
+ public ProviderApi provider(String doc, Object fields, Location location) throws EvalException {
+ return null;
+ }
+
+ @Override
+ public BaseFunction rule(BaseFunction implementation, Boolean test, Object attrs,
+ Object implicitOutputs, Boolean executable, Boolean outputToGenfiles,
+ SkylarkList<?> fragments, SkylarkList<?> hostFragments, Boolean skylarkTestable,
+ SkylarkList<?> toolchains, String doc, SkylarkList<?> providesArg,
+ Boolean executionPlatformConstraintsAllowed, SkylarkList<?> execCompatibleWith,
+ FuncallExpression ast, Environment funcallEnv) throws EvalException {
+ Set<String> attrNames;
+ if (attrs != null) {
+ SkylarkDict<?, ?> attrsDict = (SkylarkDict<?, ?>) attrs;
+ Map<String, Descriptor> attrsMap =
+ attrsDict.getContents(String.class, Descriptor.class, "attrs");
+ attrNames = attrsMap.keySet();
+ } else {
+ attrNames = ImmutableSet.of();
+ }
+
+ // TODO(cparsons): Improve details given to RuleInfo (for example, attribute types).
+ ruleInfoList.add(new RuleInfo(ast.getLocation(), doc, attrNames));
+ return implementation;
+ }
+
+ @Override
+ public Label label(String labelString, Boolean relativeToCallerRepository, Location loc,
+ Environment env) throws EvalException {
+ return null;
+ }
+
+ @Override
+ public FileTypeApi<FileApi> fileType(SkylarkList<?> types, Location loc, Environment env)
+ throws EvalException {
+ return null;
+ }
+
+ @Override
+ public SkylarkAspectApi aspect(BaseFunction implementation, SkylarkList<?> attributeAspects,
+ Object attrs, SkylarkList<?> requiredAspectProvidersArg, SkylarkList<?> providesArg,
+ SkylarkList<?> fragments, SkylarkList<?> hostFragments, SkylarkList<?> toolchains, String doc,
+ FuncallExpression ast, Environment funcallEnv) throws EvalException {
+ return null;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStructApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStructApi.java
new file mode 100644
index 0000000000..abdea383f6
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeStructApi.java
@@ -0,0 +1,88 @@
+// 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.fakebuildapi;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.skylarkbuildapi.StructApi;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.syntax.ClassObject;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+/**
+ * Fake implementation of {@link StructApi}.
+ */
+public class FakeStructApi implements StructApi, ClassObject {
+
+ private final Map<String, Object> objects;
+
+ public FakeStructApi(Map<String, Object> objects) {
+ this.objects = objects;
+ }
+
+ public FakeStructApi() {
+ this(ImmutableMap.of());
+ }
+
+ @Override
+ public String toProto(Location loc) throws EvalException {
+ return "";
+ }
+
+ @Override
+ public String toJson(Location loc) throws EvalException {
+ return "";
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+
+ @Nullable
+ @Override
+ public Object getValue(String name) throws EvalException {
+ return objects.get(name);
+ }
+
+ @Override
+ public ImmutableCollection<String> getFieldNames() throws EvalException {
+ return ImmutableList.of();
+ }
+
+ @Nullable
+ @Override
+ public String getErrorMessageForUnknownField(String field) {
+ return "";
+ }
+
+ /**
+ * Fake implementation of {@link StructProviderApi}.
+ */
+ public static class FakeStructProviderApi implements StructProviderApi {
+
+ @Override
+ public StructApi createStruct(SkylarkDict<?, ?> kwargs, Location loc) throws EvalException {
+ return new FakeStructApi(kwargs.getContents(String.class, Object.class, "kwargs"));
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {}
+ }
+}
+
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD b/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
new file mode 100644
index 0000000000..13f2cc9edd
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
@@ -0,0 +1,21 @@
+package(
+ default_visibility = ["//src:__subpackages__"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+java_library(
+ name = "rendering",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:events",
+ "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java b/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java
new file mode 100644
index 0000000000..0d8a150dfc
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java
@@ -0,0 +1,58 @@
+// 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.rendering;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.devtools.build.lib.events.Location;
+import java.util.Collection;
+
+/**
+ * Stores information about a skylark rule definition.
+ */
+public class RuleInfo {
+
+ private final Location location;
+ private final String docString;
+ private final Collection<String> attrNames;
+
+ public RuleInfo(Location location, String docString, Collection<String> attrNames) {
+ this.location = location;
+ this.docString = docString;
+ this.attrNames = attrNames;
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+ public String getDocString() {
+ return docString;
+ }
+
+ public Collection<String> getAttrNames() {
+ return attrNames;
+ }
+
+ public String getDescription() {
+ StringBuilder stringBuilder = new StringBuilder();
+ if (!Strings.isNullOrEmpty(docString)) {
+ stringBuilder.append(docString);
+ stringBuilder.append("\n");
+ }
+ Joiner.on(",").appendTo(stringBuilder, attrNames);
+ return stringBuilder.toString();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/skydoc/BUILD b/src/test/java/com/google/devtools/build/skydoc/BUILD
new file mode 100644
index 0000000000..2416d5a339
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/BUILD
@@ -0,0 +1,83 @@
+package(
+ default_testonly = 1,
+ default_visibility = ["//src:__subpackages__"],
+)
+
+filegroup(
+ name = "srcs",
+ testonly = 0,
+ srcs = glob(["**"]),
+ visibility = ["//src:__pkg__"],
+)
+
+java_test(
+ name = "SkydocTest",
+ size = "medium",
+ srcs = ["SkydocTest.java"],
+ shard_count = 1,
+ visibility = ["//devtools/blaze/main:__pkg__"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:syntax",
+ "//src/main/java/com/google/devtools/build/lib/vfs",
+ "//src/main/java/com/google/devtools/build/skydoc:skydoc_lib",
+ "//src/main/java/com/google/devtools/build/skydoc/rendering",
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ "//src/test/java/com/google/devtools/build/lib/skylark:testutil",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
+
+# TODO(cparsons): Make test cases and golden-genrules into a macro.
+sh_test(
+ name = "simple_skydoc_e2e_test",
+ srcs = ["skydoc_e2e_test_runner.sh"],
+ args = [
+ "$(location //src/main/java/com/google/devtools/build/skydoc:skydoc)",
+ "$(location simple_test/input.txt)",
+ "$(location simple_test/golden.txt)",
+ ],
+ data = [
+ "simple_test/golden.txt",
+ "simple_test/input.txt",
+ "//src/main/java/com/google/devtools/build/skydoc",
+ ],
+)
+
+genrule(
+ name = "regenerate_simple_golden",
+ srcs = [
+ "simple_test/input.txt",
+ ],
+ outs = ["simple_output.txt"],
+ cmd = "$(location //src/main/java/com/google/devtools/build/skydoc:skydoc) " +
+ "$(location simple_test/input.txt) $(location simple_output.txt)",
+ tools = ["//src/main/java/com/google/devtools/build/skydoc"],
+)
+
+sh_test(
+ name = "unknown_name_skydoc_e2e_test",
+ srcs = ["skydoc_e2e_test_runner.sh"],
+ args = [
+ "$(location //src/main/java/com/google/devtools/build/skydoc:skydoc)",
+ "$(location unknown_name_test/input.txt)",
+ "$(location unknown_name_test/golden.txt)",
+ ],
+ data = [
+ "unknown_name_test/golden.txt",
+ "unknown_name_test/input.txt",
+ "//src/main/java/com/google/devtools/build/skydoc",
+ ],
+)
+
+genrule(
+ name = "regenerate_unknown_name_golden",
+ srcs = [
+ "unknown_name_test/input.txt",
+ ],
+ outs = ["unknown_name_output.txt"],
+ cmd = "$(location //src/main/java/com/google/devtools/build/skydoc:skydoc) " +
+ "$(location unknown_name_test/input.txt) $(location unknown_name_output.txt)",
+ tools = ["//src/main/java/com/google/devtools/build/skydoc"],
+)
diff --git a/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java b/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java
new file mode 100644
index 0000000000..d80fe4ed35
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/SkydocTest.java
@@ -0,0 +1,67 @@
+// 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
+import com.google.devtools.build.lib.syntax.ParserInputSource;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.skydoc.rendering.RuleInfo;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Java tests for Skydoc.
+ */
+@RunWith(JUnit4.class)
+public final class SkydocTest extends SkylarkTestCase {
+
+ @Test
+ public void testRuleInfoAttrs() throws Exception {
+ Path file =
+ scratch.file(
+ "/test/test.bzl",
+ "def rule_impl(ctx):",
+ " return struct()",
+ "",
+ "my_rule = rule(",
+ " doc = 'This is my rule. It does stuff.',",
+ " implementation = rule_impl,",
+ " attrs = {",
+ " 'first': attr.label(mandatory=True, allow_files=True, single_file=True),",
+ " 'second': attr.string_dict(mandatory=True),",
+ " 'third': attr.output(mandatory=True),",
+ " 'fourth': attr.bool(default=False, mandatory=False),",
+ " },",
+ ")");
+ byte[] bytes = FileSystemUtils.readWithKnownFileSize(file, file.getFileSize());
+
+ ParserInputSource parserInputSource =
+ ParserInputSource.create(bytes, file.asFragment());
+
+ List<RuleInfo> ruleInfos = new SkydocMain().eval(parserInputSource);
+ assertThat(ruleInfos).hasSize(1);
+
+ RuleInfo ruleInfo = Iterables.getOnlyElement(ruleInfos);
+ assertThat(ruleInfo.getDocString()).isEqualTo("This is my rule. It does stuff.");
+ assertThat(ruleInfo.getAttrNames()).containsExactly(
+ "first", "second", "third", "fourth");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/skydoc/simple_test/golden.txt b/src/test/java/com/google/devtools/build/skydoc/simple_test/golden.txt
new file mode 100644
index 0000000000..0bf3a8c96a
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/simple_test/golden.txt
@@ -0,0 +1,3 @@
+my_rule
+This is my rule. It does stuff.
+first,second,third,fourth
diff --git a/src/test/java/com/google/devtools/build/skydoc/simple_test/input.txt b/src/test/java/com/google/devtools/build/skydoc/simple_test/input.txt
new file mode 100644
index 0000000000..de1548b420
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/simple_test/input.txt
@@ -0,0 +1,13 @@
+def my_rule_impl(ctx):
+ return struct()
+
+my_rule = rule(
+ implementation = my_rule_impl,
+ doc = "This is my rule. It does stuff.",
+ attrs = {
+ "first": attr.label(mandatory = True, allow_files = True, single_file = True),
+ "second": attr.string_dict(mandatory = True),
+ "third": attr.output(mandatory = True),
+ "fourth": attr.bool(default = False, mandatory = False),
+ },
+)
diff --git a/src/test/java/com/google/devtools/build/skydoc/skydoc_e2e_test_runner.sh b/src/test/java/com/google/devtools/build/skydoc/skydoc_e2e_test_runner.sh
new file mode 100755
index 0000000000..c32973c17c
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/skydoc_e2e_test_runner.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# 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.
+#
+# Test skydoc output matches the expected golden file output.
+
+set -u
+
+skydoc_bin=$1
+input_file=$2
+golden_file=$3
+
+actual_file="${TEST_TMPDIR}/actual"
+
+${skydoc_bin} ${input_file} ${actual_file}
+
+DIFF="$(diff ${actual_file} ${golden_file})"
+
+if [ "$DIFF" != "" ]
+then
+ echo "Actual did not match golden."
+ echo "${DIFF}"
+ exit 1
+else
+ echo "Result matches golden file"
+fi
diff --git a/src/test/java/com/google/devtools/build/skydoc/unknown_name_test/golden.txt b/src/test/java/com/google/devtools/build/skydoc/unknown_name_test/golden.txt
new file mode 100644
index 0000000000..9b49c77015
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/unknown_name_test/golden.txt
@@ -0,0 +1,2 @@
+<unknown name>
+first,second,third,fourth
diff --git a/src/test/java/com/google/devtools/build/skydoc/unknown_name_test/input.txt b/src/test/java/com/google/devtools/build/skydoc/unknown_name_test/input.txt
new file mode 100644
index 0000000000..24c69d2905
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/skydoc/unknown_name_test/input.txt
@@ -0,0 +1,12 @@
+def my_rule_impl(ctx):
+ return struct()
+
+rule(
+ implementation = my_rule_impl,
+ attrs = {
+ "first": attr.label(mandatory = True, allow_files = True, single_file = True),
+ "second": attr.string_dict(mandatory = True),
+ "third": attr.output(mandatory = True),
+ "fourth": attr.bool(default = False, mandatory = False),
+ },
+)