blob: a01d018cbd6b56096db78fd886d3a61b93a169b2 [file] [log] [blame]
cparsons5d85e752018-06-26 13:47:28 -07001// Copyright 2018 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.skydoc.fakebuildapi;
16
cparsons11c9f202018-07-11 10:30:02 -070017import com.google.common.collect.ImmutableMap;
cparsons5d85e752018-06-26 13:47:28 -070018import com.google.devtools.build.lib.cmdline.Label;
cparsons17710542018-07-13 15:23:46 -070019import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
cparsons5d85e752018-06-26 13:47:28 -070020import com.google.devtools.build.lib.events.Location;
21import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
22import com.google.devtools.build.lib.skylarkbuildapi.FileTypeApi;
23import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
24import com.google.devtools.build.lib.skylarkbuildapi.SkylarkAspectApi;
cparsons5d85e752018-06-26 13:47:28 -070025import com.google.devtools.build.lib.skylarkbuildapi.SkylarkRuleFunctionsApi;
26import com.google.devtools.build.lib.syntax.BaseFunction;
27import com.google.devtools.build.lib.syntax.Environment;
28import com.google.devtools.build.lib.syntax.EvalException;
29import com.google.devtools.build.lib.syntax.FuncallExpression;
cparsonsd790ce42018-06-27 15:29:02 -070030import com.google.devtools.build.lib.syntax.Runtime;
cparsons5d85e752018-06-26 13:47:28 -070031import com.google.devtools.build.lib.syntax.SkylarkDict;
32import com.google.devtools.build.lib.syntax.SkylarkList;
cparsons11c9f202018-07-11 10:30:02 -070033import com.google.devtools.build.skydoc.fakebuildapi.FakeDescriptor.Type;
cparsonsfc0e52f2018-07-09 11:06:57 -070034import com.google.devtools.build.skydoc.rendering.AttributeInfo;
cparsons5d85e752018-06-26 13:47:28 -070035import com.google.devtools.build.skydoc.rendering.RuleInfo;
cparsons11c9f202018-07-11 10:30:02 -070036import java.util.Comparator;
cparsons5d85e752018-06-26 13:47:28 -070037import java.util.List;
cparsonsfc0e52f2018-07-09 11:06:57 -070038import java.util.stream.Collectors;
cparsonsd790ce42018-06-27 15:29:02 -070039import javax.annotation.Nullable;
cparsons5d85e752018-06-26 13:47:28 -070040
41/**
42 * Fake implementation of {@link SkylarkRuleFunctionsApi}.
43 *
cparsonsd790ce42018-06-27 15:29:02 -070044 * <p>This fake hooks into the global {@code rule()} function, adding descriptors of calls of that
45 * function to a {@link List} given in the class constructor.</p>
cparsons5d85e752018-06-26 13:47:28 -070046 */
47public class FakeSkylarkRuleFunctionsApi implements SkylarkRuleFunctionsApi<FileApi> {
48
cparsons11c9f202018-07-11 10:30:02 -070049 private static final FakeDescriptor IMPLICIT_NAME_ATTRIBUTE_DESCRIPTOR =
50 new FakeDescriptor(Type.STRING, "A unique name for this rule.", true);
cparsons5d85e752018-06-26 13:47:28 -070051 private final List<RuleInfo> ruleInfoList;
52
53 /**
54 * Constructor.
55 *
56 * @param ruleInfoList the list of {@link RuleInfo} objects to which rule() invocation information
57 * will be added
58 */
59 public FakeSkylarkRuleFunctionsApi(List<RuleInfo> ruleInfoList) {
60 this.ruleInfoList = ruleInfoList;
61 }
62
63 @Override
64 public ProviderApi provider(String doc, Object fields, Location location) throws EvalException {
cparsons17710542018-07-13 15:23:46 -070065 return new FakeProviderApi();
cparsons5d85e752018-06-26 13:47:28 -070066 }
67
68 @Override
69 public BaseFunction rule(BaseFunction implementation, Boolean test, Object attrs,
70 Object implicitOutputs, Boolean executable, Boolean outputToGenfiles,
71 SkylarkList<?> fragments, SkylarkList<?> hostFragments, Boolean skylarkTestable,
72 SkylarkList<?> toolchains, String doc, SkylarkList<?> providesArg,
73 Boolean executionPlatformConstraintsAllowed, SkylarkList<?> execCompatibleWith,
74 FuncallExpression ast, Environment funcallEnv) throws EvalException {
cparsonsfc0e52f2018-07-09 11:06:57 -070075 List<AttributeInfo> attrInfos;
cparsons11c9f202018-07-11 10:30:02 -070076 ImmutableMap.Builder<String, FakeDescriptor> attrsMapBuilder = ImmutableMap.builder();
cparsonsd790ce42018-06-27 15:29:02 -070077 if (attrs != null && attrs != Runtime.NONE) {
cparsons5d85e752018-06-26 13:47:28 -070078 SkylarkDict<?, ?> attrsDict = (SkylarkDict<?, ?>) attrs;
cparsons11c9f202018-07-11 10:30:02 -070079 attrsMapBuilder.putAll(attrsDict.getContents(String.class, FakeDescriptor.class, "attrs"));
cparsons5d85e752018-06-26 13:47:28 -070080 }
81
cparsons11c9f202018-07-11 10:30:02 -070082 attrsMapBuilder.put("name", IMPLICIT_NAME_ATTRIBUTE_DESCRIPTOR);
83 attrInfos = attrsMapBuilder.build().entrySet().stream()
84 .map(entry -> new AttributeInfo(
85 entry.getKey(),
86 entry.getValue().getDocString(),
87 entry.getValue().getType().getDescription(),
88 entry.getValue().isMandatory()))
89 .collect(Collectors.toList());
90 attrInfos.sort(new AttributeNameComparator());
91
cparsonsd790ce42018-06-27 15:29:02 -070092 RuleDefinitionIdentifier functionIdentifier = new RuleDefinitionIdentifier();
cparsonsfc0e52f2018-07-09 11:06:57 -070093
94 ruleInfoList.add(new RuleInfo(functionIdentifier, ast.getLocation(), doc, attrInfos));
cparsonsd790ce42018-06-27 15:29:02 -070095 return functionIdentifier;
cparsons5d85e752018-06-26 13:47:28 -070096 }
97
98 @Override
99 public Label label(String labelString, Boolean relativeToCallerRepository, Location loc,
100 Environment env) throws EvalException {
cparsons17710542018-07-13 15:23:46 -0700101 try {
102 return Label.parseAbsolute(
103 labelString,
104 /* defaultToMain= */ false,
105 /* repositoryMapping= */ ImmutableMap.of());
106 } catch (LabelSyntaxException e) {
107 throw new EvalException(loc, "Illegal absolute label syntax: " + labelString);
108 }
cparsons5d85e752018-06-26 13:47:28 -0700109 }
110
111 @Override
112 public FileTypeApi<FileApi> fileType(SkylarkList<?> types, Location loc, Environment env)
113 throws EvalException {
114 return null;
115 }
116
117 @Override
118 public SkylarkAspectApi aspect(BaseFunction implementation, SkylarkList<?> attributeAspects,
119 Object attrs, SkylarkList<?> requiredAspectProvidersArg, SkylarkList<?> providesArg,
120 SkylarkList<?> fragments, SkylarkList<?> hostFragments, SkylarkList<?> toolchains, String doc,
121 FuncallExpression ast, Environment funcallEnv) throws EvalException {
cparsons6922b5f2018-08-28 08:32:09 -0700122 return new FakeSkylarkAspect();
cparsons5d85e752018-06-26 13:47:28 -0700123 }
cparsonsd790ce42018-06-27 15:29:02 -0700124
125 /**
126 * A fake {@link BaseFunction} implementation which serves as an identifier for a rule definition.
127 * A skylark invocation of 'rule()' should spawn a unique instance of this class and return it.
128 * Thus, skylark code such as 'foo = rule()' will result in 'foo' being assigned to a unique
129 * identifier, which can later be matched to a registered rule() invocation saved by the fake
130 * build API implementation.
131 */
132 private static class RuleDefinitionIdentifier extends BaseFunction {
133
cparsons93adb102018-07-11 11:44:17 -0700134 private static int idCounter = 0;
135
cparsonsd790ce42018-06-27 15:29:02 -0700136 public RuleDefinitionIdentifier() {
cparsons93adb102018-07-11 11:44:17 -0700137 super("RuleDefinitionIdentifier" + idCounter++);
cparsonsd790ce42018-06-27 15:29:02 -0700138 }
139
140 @Override
141 public boolean equals(@Nullable Object other) {
142 // Use exact object matching.
143 return this == other;
144 }
145 }
cparsons11c9f202018-07-11 10:30:02 -0700146
147 /**
148 * A comparator for {@link AttributeInfo} objects which sorts by attribute name alphabetically,
149 * except that any attribute named "name" is placed first.
150 */
151 private static class AttributeNameComparator implements Comparator<AttributeInfo> {
152
153 @Override
154 public int compare(AttributeInfo o1, AttributeInfo o2) {
155 if (o1.getName().equals("name")) {
156 return o2.getName().equals("name") ? 0 : -1;
157 } else if (o2.getName().equals("name")) {
158 return 1;
159 } else {
160 return o1.getName().compareTo(o2.getName());
161 }
162 }
163 }
cparsons5d85e752018-06-26 13:47:28 -0700164}