diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java | 281 |
1 files changed, 46 insertions, 235 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java index 8388391361..7910b80410 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java @@ -27,7 +27,6 @@ import com.google.common.collect.Ordering; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.Root; import com.google.devtools.build.lib.analysis.ActionsProvider; -import com.google.devtools.build.lib.analysis.AliasProvider; import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext; import com.google.devtools.build.lib.analysis.DefaultInfo; import com.google.devtools.build.lib.analysis.FilesToRunProvider; @@ -43,6 +42,7 @@ import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector; import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.packages.Aspect; import com.google.devtools.build.lib.packages.AspectDescriptor; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition; @@ -71,14 +71,12 @@ import com.google.devtools.build.lib.syntax.SkylarkDict; import com.google.devtools.build.lib.syntax.SkylarkIndexable; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkSemantics; -import com.google.devtools.build.lib.syntax.SkylarkType; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.syntax.Type.LabelClass; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -205,8 +203,8 @@ public final class SkylarkRuleContext implements SkylarkValue { private final SkylarkSemantics skylarkSemantics; private SkylarkDict<String, String> makeVariables; - private SkylarkRuleAttributesCollection attributesCollection; - private SkylarkRuleAttributesCollection ruleAttributesCollection; + private SkylarkAttributesCollection attributesCollection; + private SkylarkAttributesCollection ruleAttributesCollection; private Info splitAttributes; // TODO(bazel-team): we only need this because of the css_binary rule. @@ -285,28 +283,46 @@ public final class SkylarkRuleContext implements SkylarkValue { this.artifactsLabelMap = artifactLabelMapBuilder.build(); this.outputsObject = outputs; - this.attributesCollection = - buildAttributesCollection( - this, attributes, ruleContext, attributeValueExtractorForRule(ruleContext)); + SkylarkAttributesCollection.Builder builder = SkylarkAttributesCollection.builder(this); + for (Attribute attribute : ruleContext.getRule().getAttributes()) { + Object value = ruleContext.attributes().get(attribute.getName(), attribute.getType()); + builder.addAttribute(attribute, value); + } + + this.attributesCollection = builder.build(); this.splitAttributes = buildSplitAttributeInfo(attributes, ruleContext); this.ruleAttributesCollection = null; } else { // ASPECT this.isForAspect = true; this.artifactsLabelMap = ImmutableMap.of(); this.outputsObject = null; - this.attributesCollection = - buildAttributesCollection( - this, - ruleContext.getAspectAttributes().values(), - ruleContext, - ATTRIBUTE_VALUE_EXTRACTOR_FOR_ASPECT); + + ImmutableCollection<Attribute> attributes = + ruleContext.getMainAspect().getDefinition().getAttributes().values(); + SkylarkAttributesCollection.Builder aspectBuilder = SkylarkAttributesCollection.builder(this); + for (Attribute attribute : attributes) { + aspectBuilder.addAttribute(attribute, attribute.getDefaultValue(null)); + } + this.attributesCollection = aspectBuilder.build(); + this.splitAttributes = null; - this.ruleAttributesCollection = - buildAttributesCollection( - this, - ruleContext.getRule().getAttributes(), - ruleContext, - attributeValueExtractorForRule(ruleContext)); + SkylarkAttributesCollection.Builder ruleBuilder = SkylarkAttributesCollection.builder(this); + + for (Attribute attribute : ruleContext.getRule().getAttributes()) { + Object value = ruleContext.attributes().get(attribute.getName(), attribute.getType()); + ruleBuilder.addAttribute(attribute, value); + } + for (Aspect aspect : ruleContext.getAspects()) { + if (aspect.equals(ruleContext.getMainAspect())) { + // Aspect's own attributes are in <code>attributesCollection</code>. + continue; + } + for (Attribute attribute : aspect.getDefinition().getAttributes().values()) { + ruleBuilder.addAttribute(attribute, attribute.getDefaultValue(null)); + } + } + + this.ruleAttributesCollection = ruleBuilder.build(); } makeVariables = ruleContext.getConfigurationMakeVariableContext().collectMakeVariables(); @@ -366,7 +382,7 @@ public final class SkylarkRuleContext implements SkylarkValue { if (context.isExecutable() && EXECUTABLE_OUTPUT_NAME.equals(name)) { executableCreated = true; // createOutputArtifact() will cache the created artifact. - return context.ruleContext.createOutputArtifact(); + return context.getRuleContext().createOutputArtifact(); } return outputs.get(name); @@ -461,121 +477,8 @@ public final class SkylarkRuleContext implements SkylarkValue { return aspectDescriptor; } - private Function<Attribute, Object> attributeValueExtractorForRule( - final RuleContext ruleContext) { - return new Function<Attribute, Object>() { - @Nullable - @Override - public Object apply(Attribute attribute) { - return ruleContext.attributes().get(attribute.getName(), attribute.getType()); - } - }; - } - - private static SkylarkRuleAttributesCollection buildAttributesCollection( - SkylarkRuleContext skylarkRuleContext, - Collection<Attribute> attributes, - RuleContext ruleContext, - Function<Attribute, Object> attributeValueExtractor) { - Builder<String, Object> attrBuilder = new Builder<>(); - Builder<String, Object> executableBuilder = new Builder<>(); - Builder<Artifact, FilesToRunProvider> executableRunfilesbuilder = new Builder<>(); - Builder<String, Object> fileBuilder = new Builder<>(); - Builder<String, Object> filesBuilder = new Builder<>(); - HashSet<Artifact> seenExecutables = new HashSet<>(); - for (Attribute a : attributes) { - Type<?> type = a.getType(); - Object val = attributeValueExtractor.apply(a); - // TODO(mstaib): Remove the LABEL_DICT_UNARY special case of this conditional - // LABEL_DICT_UNARY was previously not treated as a dependency-bearing type, and was put into - // Skylark as a Map<String, Label>; this special case preserves that behavior temporarily. - if (type.getLabelClass() != LabelClass.DEPENDENCY || type == BuildType.LABEL_DICT_UNARY) { - attrBuilder.put(a.getPublicName(), val == null ? Runtime.NONE - // Attribute values should be type safe - : SkylarkType.convertToSkylark(val, null)); - continue; - } - String skyname = a.getPublicName(); - if (a.isExecutable()) { - // In Skylark only label (not label list) type attributes can have the Executable flag. - FilesToRunProvider provider = - ruleContext.getExecutablePrerequisite(a.getName(), Mode.DONT_CHECK); - if (provider != null && provider.getExecutable() != null) { - Artifact executable = provider.getExecutable(); - executableBuilder.put(skyname, executable); - if (!seenExecutables.contains(executable)) { - // todo(dslomov,laurentlb): In general, this is incorrect. - // We associate the first encountered FilesToRunProvider with - // the executable (this provider is later used to build the spawn). - // However ideally we should associate a provider with the attribute name, - // and pass the correct FilesToRunProvider to the spawn depending on - // what attribute is used to access the executable. - executableRunfilesbuilder.put(executable, provider); - seenExecutables.add(executable); - } - } else { - executableBuilder.put(skyname, Runtime.NONE); - } - } - if (a.isSingleArtifact()) { - // In Skylark only label (not label list) type attributes can have the SingleArtifact flag. - Artifact artifact = ruleContext.getPrerequisiteArtifact(a.getName(), Mode.DONT_CHECK); - if (artifact != null) { - fileBuilder.put(skyname, artifact); - } else { - fileBuilder.put(skyname, Runtime.NONE); - } - } - filesBuilder.put( - skyname, ruleContext.getPrerequisiteArtifacts(a.getName(), Mode.DONT_CHECK).list()); - - if (type == BuildType.LABEL && !a.hasSplitConfigurationTransition()) { - Object prereq = ruleContext.getPrerequisite(a.getName(), Mode.DONT_CHECK); - if (prereq == null) { - prereq = Runtime.NONE; - } - attrBuilder.put(skyname, prereq); - } else if (type == BuildType.LABEL_LIST - || (type == BuildType.LABEL && a.hasSplitConfigurationTransition())) { - List<?> allPrereq = ruleContext.getPrerequisites(a.getName(), Mode.DONT_CHECK); - attrBuilder.put(skyname, SkylarkList.createImmutable(allPrereq)); - } else if (type == BuildType.LABEL_KEYED_STRING_DICT) { - ImmutableMap.Builder<TransitiveInfoCollection, String> builder = - new ImmutableMap.Builder<>(); - Map<Label, String> original = BuildType.LABEL_KEYED_STRING_DICT.cast(val); - List<? extends TransitiveInfoCollection> allPrereq = - ruleContext.getPrerequisites(a.getName(), Mode.DONT_CHECK); - for (TransitiveInfoCollection prereq : allPrereq) { - builder.put(prereq, original.get(AliasProvider.getDependencyLabel(prereq))); - } - attrBuilder.put(skyname, SkylarkType.convertToSkylark(builder.build(), null)); - } else if (type == BuildType.LABEL_DICT_UNARY) { - Map<Label, TransitiveInfoCollection> prereqsByLabel = new LinkedHashMap<>(); - for (TransitiveInfoCollection target - : ruleContext.getPrerequisites(a.getName(), Mode.DONT_CHECK)) { - prereqsByLabel.put(target.getLabel(), target); - } - ImmutableMap.Builder<String, TransitiveInfoCollection> attrValue = - new ImmutableMap.Builder<>(); - for (Map.Entry<String, Label> entry : ((Map<String, Label>) val).entrySet()) { - attrValue.put(entry.getKey(), prereqsByLabel.get(entry.getValue())); - } - attrBuilder.put(skyname, attrValue.build()); - } else { - throw new IllegalArgumentException( - "Can't transform attribute " + a.getName() + " of type " + type - + " to a Skylark object"); - } - } - - return new SkylarkRuleAttributesCollection( - skylarkRuleContext, - ruleContext.getRule().getRuleClass(), - attrBuilder.build(), - executableBuilder.build(), - fileBuilder.build(), - filesBuilder.build(), - executableRunfilesbuilder.build()); + public String getRuleLabelCanonicalName() { + return ruleLabelCanonicalName; } private static Info buildSplitAttributeInfo( @@ -624,101 +527,6 @@ public final class SkylarkRuleContext implements SkylarkValue { + "split configuration."); } - @SkylarkModule( - name = "rule_attributes", - category = SkylarkModuleCategory.NONE, - doc = "Information about attributes of a rule an aspect is applied to." - ) - private static class SkylarkRuleAttributesCollection implements SkylarkValue { - private final SkylarkRuleContext skylarkRuleContext; - private final Info attrObject; - private final Info executableObject; - private final Info fileObject; - private final Info filesObject; - private final ImmutableMap<Artifact, FilesToRunProvider> executableRunfilesMap; - private final String ruleClassName; - - private SkylarkRuleAttributesCollection( - SkylarkRuleContext skylarkRuleContext, - String ruleClassName, ImmutableMap<String, Object> attrs, - ImmutableMap<String, Object> executables, - ImmutableMap<String, Object> singleFiles, - ImmutableMap<String, Object> files, - ImmutableMap<Artifact, FilesToRunProvider> executableRunfilesMap) { - this.skylarkRuleContext = skylarkRuleContext; - this.ruleClassName = ruleClassName; - attrObject = - NativeProvider.STRUCT.create( - attrs, - "No attribute '%s' in attr. Make sure you declared a rule attribute with this name."); - executableObject = - NativeProvider.STRUCT.create( - executables, - "No attribute '%s' in executable. Make sure there is a label type attribute marked " - + "as 'executable' with this name"); - fileObject = - NativeProvider.STRUCT.create( - singleFiles, - "No attribute '%s' in file. Make sure there is a label type attribute marked " - + "as 'single_file' with this name"); - filesObject = - NativeProvider.STRUCT.create( - files, - "No attribute '%s' in files. Make sure there is a label or label_list type attribute " - + "with this name"); - this.executableRunfilesMap = executableRunfilesMap; - } - - private void checkMutable(String attrName) throws EvalException { - skylarkRuleContext.checkMutable("rule." + attrName); - } - - @SkylarkCallable(name = "attr", structField = true, doc = ATTR_DOC) - public Info getAttr() throws EvalException { - checkMutable("attr"); - return attrObject; - } - - @SkylarkCallable(name = "executable", structField = true, doc = EXECUTABLE_DOC) - public Info getExecutable() throws EvalException { - checkMutable("executable"); - return executableObject; - } - - @SkylarkCallable(name = "file", structField = true, doc = FILE_DOC) - public Info getFile() throws EvalException { - checkMutable("file"); - return fileObject; - } - - @SkylarkCallable(name = "files", structField = true, doc = FILES_DOC) - public Info getFiles() throws EvalException { - checkMutable("files"); - return filesObject; - } - - @SkylarkCallable(name = "kind", structField = true, doc = - "The kind of a rule, such as 'cc_library'") - public String getRuleClassName() throws EvalException { - checkMutable("kind"); - return ruleClassName; - } - - public ImmutableMap<Artifact, FilesToRunProvider> getExecutableRunfilesMap() { - return executableRunfilesMap; - } - - @Override - public boolean isImmutable() { - return skylarkRuleContext.isImmutable(); - } - - @Override - public void repr(SkylarkPrinter printer) { - printer.append("<rule collection for " + skylarkRuleContext.ruleLabelCanonicalName + ">"); - } - } - @Override public boolean isImmutable() { return ruleContext == null; @@ -922,10 +730,13 @@ public final class SkylarkRuleContext implements SkylarkValue { return outputsObject; } - @SkylarkCallable(structField = true, - doc = "Returns rule attributes descriptor for the rule that aspect is applied to." - + " Only available in aspect implementation functions.") - public SkylarkRuleAttributesCollection rule() throws EvalException { + @SkylarkCallable( + structField = true, + doc = + "Returns rule attributes descriptor for the rule that aspect is applied to." + + " Only available in aspect implementation functions." + ) + public SkylarkAttributesCollection rule() throws EvalException { checkMutable("rule"); if (!isForAspect) { throw new EvalException( |