Skip to content

Commit

Permalink
Support Repository Rules in Stardoc
Browse files Browse the repository at this point in the history
Make the fake implementation of repository_rule register the rule
instead of blindly returning the implementation function. In this
way, the documentation generated for repository rules contains the
correct arguments.

Fixes bazelbuild/skydoc#168

Change-Id: I4b4101a9a604282051eeaadafccdc9a987b14264
PiperOrigin-RevId: 239029265
  • Loading branch information
aehlig authored and copybara-github committed Mar 18, 2019
1 parent 9303df6 commit 547aa48
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ private Map<String, Object> collectBzlGlobals() {
PlatformBootstrap platformBootstrap = new PlatformBootstrap(new FakePlatformCommon());
PyBootstrap pyBootstrap =
new PyBootstrap(new FakePyInfoProvider(), new FakePyRuntimeInfoProvider());
RepositoryBootstrap repositoryBootstrap = new RepositoryBootstrap(new FakeRepositoryModule());
RepositoryBootstrap repositoryBootstrap =
new RepositoryBootstrap(new FakeRepositoryModule(Lists.newArrayList()));
TestingBootstrap testingBootstrap =
new TestingBootstrap(
new FakeTestingModule(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,8 @@ private static GlobalFrame globalFrame(List<RuleInfo> ruleInfoList,
ProtoBootstrap protoBootstrap = new ProtoBootstrap(new FakeProtoInfoApiProvider());
PyBootstrap pyBootstrap =
new PyBootstrap(new FakePyInfoProvider(), new FakePyRuntimeInfoProvider());
RepositoryBootstrap repositoryBootstrap = new RepositoryBootstrap(new FakeRepositoryModule());
RepositoryBootstrap repositoryBootstrap =
new RepositoryBootstrap(new FakeRepositoryModule(ruleInfoList));
TestingBootstrap testingBootstrap =
new TestingBootstrap(
new FakeTestingModule(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public boolean equals(@Nullable Object other) {
* A comparator for {@link AttributeInfo} objects which sorts by attribute name alphabetically,
* except that any attribute named "name" is placed first.
*/
private static class AttributeNameComparator implements Comparator<AttributeInfo> {
public static class AttributeNameComparator implements Comparator<AttributeInfo> {

@Override
public int compare(AttributeInfo o1, AttributeInfo o2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ java_library(
"//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/skylarkbuildapi/repository",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi",
"//src/main/java/com/google/devtools/build/skydoc/rendering",
"//third_party:guava",
"//third_party:jsr305",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,36 @@

package com.google.devtools.build.skydoc.fakebuildapi.repository;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.skylarkbuildapi.repository.RepositoryModuleApi;
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.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.skydoc.fakebuildapi.FakeDescriptor;
import com.google.devtools.build.skydoc.fakebuildapi.FakeSkylarkRuleFunctionsApi.AttributeNameComparator;
import com.google.devtools.build.skydoc.rendering.AttributeInfo;
import com.google.devtools.build.skydoc.rendering.AttributeInfo.Type;
import com.google.devtools.build.skydoc.rendering.RuleInfo;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;

/**
* Fake implementation of {@link RepositoryModuleApi}.
*/
public class FakeRepositoryModule implements RepositoryModuleApi {
private static final FakeDescriptor IMPLICIT_NAME_ATTRIBUTE_DESCRIPTOR =
new FakeDescriptor(Type.NAME, "A unique name for this repository.", true);

private final List<RuleInfo> ruleInfoList;

public FakeRepositoryModule(List<RuleInfo> ruleInfoList) {
this.ruleInfoList = ruleInfoList;
}

@Override
public BaseFunction repositoryRule(
Expand All @@ -33,7 +53,55 @@ public BaseFunction repositoryRule(
SkylarkList<String> environ,
String doc,
FuncallExpression ast,
Environment env) {
return implementation;
Environment env)
throws EvalException {
List<AttributeInfo> attrInfos;
ImmutableMap.Builder<String, FakeDescriptor> attrsMapBuilder = ImmutableMap.builder();
if (attrs != null && attrs != Runtime.NONE) {
SkylarkDict<?, ?> attrsDict = (SkylarkDict<?, ?>) attrs;
attrsMapBuilder.putAll(attrsDict.getContents(String.class, FakeDescriptor.class, "attrs"));
}

attrsMapBuilder.put("name", IMPLICIT_NAME_ATTRIBUTE_DESCRIPTOR);
attrInfos =
attrsMapBuilder.build().entrySet().stream()
.filter(entry -> !entry.getKey().startsWith("_"))
.map(
entry ->
new AttributeInfo(
entry.getKey(),
entry.getValue().getDocString(),
entry.getValue().getType(),
entry.getValue().isMandatory()))
.collect(Collectors.toList());
attrInfos.sort(new AttributeNameComparator());

RepositoryRuleDefinitionIdentifier functionIdentifier =
new RepositoryRuleDefinitionIdentifier();

ruleInfoList.add(new RuleInfo(functionIdentifier, ast.getLocation(), doc, attrInfos));
return functionIdentifier;
}

/**
* A fake {@link BaseFunction} implementation which serves as an identifier for a rule definition.
* A skylark invocation of 'rule()' should spawn a unique instance of this class and return it.
* Thus, skylark code such as 'foo = rule()' will result in 'foo' being assigned to a unique
* identifier, which can later be matched to a registered rule() invocation saved by the fake
* build API implementation.
*/
private static class RepositoryRuleDefinitionIdentifier extends BaseFunction {

private static int idCounter = 0;

public RepositoryRuleDefinitionIdentifier() {
super("RepositoryRuleDefinitionIdentifier" + idCounter++);
}

@Override
public boolean equals(@Nullable Object other) {
// Use exact object matching.
return this == other;
}
}
}
7 changes: 7 additions & 0 deletions src/test/java/com/google/devtools/build/skydoc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ skydoc_test(
whitelisted_symbols = ["my_rule"],
)

skydoc_test(
name = "repo_rule_test",
golden_file = "testdata/repo_rules_test/golden.txt",
input_file = "testdata/repo_rules_test/input.bzl",
skydoc = "//src/main/java/com/google/devtools/build/skydoc",
)

skydoc_test(
name = "unknown_name",
golden_file = "testdata/unknown_name_test/golden.txt",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<a name="#my_repo"></a>
## my_repo

<pre>
my_repo(<a href="#my_repo-name">name</a>, <a href="#my_repo-useless">useless</a>)
</pre>

Minimal example of a repository rule.

### Attributes

<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="my_repo-name">
<td><code>name</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
<p>
A unique name for this repository.
</p>
</td>
</tr>
<tr id="my_repo-useless">
<td><code>useless</code></td>
<td>
String; optional
<p>
This argument will be ingored. You don't have to specify it, but you may.
</p>
</td>
</tr>
</tbody>
</table>


Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def _repo_rule_impl(ctx):
ctx.file("BUILD", "")

my_repo = repository_rule(
implementation = _repo_rule_impl,
doc = "Minimal example of a repository rule.",
attrs = {
"useless" : attr.string(
doc = "This argument will be ingored. You don't have to specify it, but you may.",
default = "ignoreme",
),
},
)

0 comments on commit 547aa48

Please sign in to comment.