use of com.google.devtools.build.lib.analysis.TransitiveInfoCollection in project bazel by bazelbuild.
the class ConstraintSemantics method checkConstraints.
/**
* Performs constraint checking on the given rule's dependencies and reports any errors. This
* includes:
*
* <ul>
* <li>Static environment checking: if this rule supports environment E, all deps outside
* selects must also support E
* <li>Refined environment computation: this rule's refined environments are its static
* environments intersected with the refined environments of all dependencies (including
* chosen deps in selects)
* <li>Refined environment checking: no environment groups can be "emptied" due to refinement
* </ul>
*
* @param ruleContext the rule to analyze
* @param staticEnvironments the rule's supported environments, as defined by the return
* value of {@link #getSupportedEnvironments}. In particular, for any environment group that's
* not in this collection, the rule is assumed to support the defaults for that group.
* @param refinedEnvironments a builder for populating this rule's refined environments
* @param removedEnvironmentCulprits a builder for populating the core dependencies that trigger
* pruning away environments through refinement. If multiple dependencies qualify (e.g.
* two direct deps under the current rule), one is arbitrarily chosen.
*/
public static void checkConstraints(RuleContext ruleContext, EnvironmentCollection staticEnvironments, EnvironmentCollection.Builder refinedEnvironments, Map<Label, Target> removedEnvironmentCulprits) {
Set<EnvironmentWithGroup> refinedEnvironmentsSoFar = new LinkedHashSet<>();
// Start with the full set of static environments:
refinedEnvironmentsSoFar.addAll(staticEnvironments.getGroupedEnvironments());
Set<EnvironmentGroup> groupsWithEnvironmentsRemoved = new LinkedHashSet<>();
// Maps the label results of getUnsupportedEnvironments() to EnvironmentWithGroups. We can't
// have that method just return EnvironmentWithGroups because it also collects group defaults,
// which we only have labels for.
Map<Label, EnvironmentWithGroup> labelsToEnvironments = new HashMap<>();
for (EnvironmentWithGroup envWithGroup : staticEnvironments.getGroupedEnvironments()) {
labelsToEnvironments.put(envWithGroup.environment(), envWithGroup);
}
DepsToCheck depsToCheck = getConstraintCheckedDependencies(ruleContext);
for (TransitiveInfoCollection dep : depsToCheck.allDeps()) {
SupportedEnvironmentsProvider depEnvironments = dep.getProvider(SupportedEnvironmentsProvider.class);
if (!depsToCheck.isSelectOnly(dep)) {
// TODO(bazel-team): support static constraint checking for selects. A selectable constraint
// is valid if the union of all deps in the select includes all of this rule's static
// environments. Determining that requires following the select paths that don't get chosen,
// which means we won't have ConfiguredTargets for those deps and need to find another
// way to get their environments.
Collection<Label> unsupportedEnvironments = getUnsupportedEnvironments(depEnvironments.getStaticEnvironments(), staticEnvironments);
if (!unsupportedEnvironments.isEmpty()) {
ruleContext.ruleError("dependency " + dep.getLabel() + " doesn't support expected environment" + (unsupportedEnvironments.size() == 1 ? "" : "s") + ": " + Joiner.on(", ").join(unsupportedEnvironments));
}
}
// Refine this rule's environments by intersecting with the dep's refined environments:
for (Label refinedEnvironmentToPrune : getUnsupportedEnvironments(depEnvironments.getRefinedEnvironments(), staticEnvironments)) {
EnvironmentWithGroup envToPrune = labelsToEnvironments.get(refinedEnvironmentToPrune);
if (envToPrune == null) {
// set before trying to remove specific items.
for (EnvironmentWithGroup defaultEnv : getDefaults(refinedEnvironmentToPrune, depEnvironments.getRefinedEnvironments())) {
refinedEnvironmentsSoFar.add(defaultEnv);
labelsToEnvironments.put(defaultEnv.environment(), defaultEnv);
}
envToPrune = Verify.verifyNotNull(labelsToEnvironments.get(refinedEnvironmentToPrune));
}
refinedEnvironmentsSoFar.remove(envToPrune);
groupsWithEnvironmentsRemoved.add(envToPrune.group());
removedEnvironmentCulprits.put(envToPrune.environment(), findOriginalRefiner(ruleContext, depEnvironments, envToPrune));
}
}
checkRefinedEnvironmentConstraints(ruleContext, groupsWithEnvironmentsRemoved, refinedEnvironmentsSoFar, refinedEnvironments, removedEnvironmentCulprits);
}
use of com.google.devtools.build.lib.analysis.TransitiveInfoCollection in project bazel by bazelbuild.
the class BazelJavaSemantics method addRunfilesForBinary.
@Override
public void addRunfilesForBinary(RuleContext ruleContext, Artifact launcher, Runfiles.Builder runfilesBuilder) {
TransitiveInfoCollection testSupport = getTestSupport(ruleContext);
if (testSupport != null) {
runfilesBuilder.addTarget(testSupport, JavaRunfilesProvider.TO_RUNFILES);
runfilesBuilder.addTarget(testSupport, RunfilesProvider.DEFAULT_RUNFILES);
}
}
use of com.google.devtools.build.lib.analysis.TransitiveInfoCollection in project bazel by bazelbuild.
the class ConstraintSemantics method getConstraintCheckedDependencies.
/**
* Returns all dependencies that should be constraint-checked against the current rule,
* including both "uncoditional" deps (outside selects) and deps that only appear in selects.
*/
private static DepsToCheck getConstraintCheckedDependencies(RuleContext ruleContext) {
Set<TransitiveInfoCollection> depsToCheck = new LinkedHashSet<>();
Set<TransitiveInfoCollection> selectOnlyDeps = new LinkedHashSet<>();
Set<TransitiveInfoCollection> depsOutsideSelects = new LinkedHashSet<>();
AttributeMap attributes = ruleContext.attributes();
for (String attr : attributes.getAttributeNames()) {
Attribute attrDef = attributes.getAttributeDefinition(attr);
if (attrDef.getType().getLabelClass() != LabelClass.DEPENDENCY || attrDef.skipConstraintsOverride()) {
continue;
}
if (!attrDef.checkConstraintsOverride()) {
// determine exactly which rules need to be constraint-annotated for depot migrations.
if (!DependencyFilter.NO_IMPLICIT_DEPS.apply(ruleContext.getRule(), attrDef) || // because --nodistinct_host_configuration subverts that call.
attrDef.getConfigurationTransition() == Attribute.ConfigurationTransition.HOST) {
continue;
}
}
Set<Label> selectOnlyDepsForThisAttribute = getDepsOnlyInSelects(ruleContext, attr, attributes.getAttributeType(attr));
for (TransitiveInfoCollection dep : ruleContext.getPrerequisites(attr, RuleConfiguredTarget.Mode.DONT_CHECK)) {
// Output files inherit the environment spec of their generating rule.
if (dep instanceof OutputFileConfiguredTarget) {
// Note this reassignment means constraint violation errors reference the generating
// rule, not the file. This makes the source of the environmental mismatch more clear.
dep = ((OutputFileConfiguredTarget) dep).getGeneratingRule();
}
// checking, but for now just pass them by.
if (dep.getProvider(SupportedEnvironmentsProvider.class) != null) {
depsToCheck.add(dep);
if (!selectOnlyDepsForThisAttribute.contains(dep.getLabel())) {
depsOutsideSelects.add(dep);
}
}
}
}
for (TransitiveInfoCollection dep : depsToCheck) {
if (!depsOutsideSelects.contains(dep)) {
selectOnlyDeps.add(dep);
}
}
return new DepsToCheck(depsToCheck, selectOnlyDeps);
}
use of com.google.devtools.build.lib.analysis.TransitiveInfoCollection in project bazel by bazelbuild.
the class AndroidStudioInfoAspect method processDependencies.
private DependenciesResult processDependencies(ConfiguredTarget base, RuleContext ruleContext, AndroidStudioInfoFilesProvider.Builder providerBuilder) {
// Calculate direct dependencies
ImmutableList.Builder<TransitiveInfoCollection> directDepsBuilder = ImmutableList.builder();
for (PrerequisiteAttr prerequisiteAttr : prerequisiteAttrs) {
if (ruleContext.attributes().has(prerequisiteAttr.name, prerequisiteAttr.type)) {
Mode mode = ruleContext.getAttributeMode(prerequisiteAttr.name);
if (mode == Mode.TARGET || mode == Mode.SPLIT) {
directDepsBuilder.addAll(ruleContext.getPrerequisites(prerequisiteAttr.name, Mode.TARGET));
}
}
}
List<TransitiveInfoCollection> directDeps = directDepsBuilder.build();
// Add exports from direct dependencies
NestedSetBuilder<Label> dependenciesBuilder = NestedSetBuilder.stableOrder();
for (AndroidStudioInfoFilesProvider depProvider : AnalysisUtils.getProviders(directDeps, AndroidStudioInfoFilesProvider.class)) {
dependenciesBuilder.addTransitive(depProvider.getExportedDeps());
}
for (TransitiveInfoCollection dep : directDeps) {
dependenciesBuilder.add(dep.getLabel());
}
NestedSet<Label> dependencies = dependenciesBuilder.build();
// Propagate my own exports
JavaExportsProvider javaExportsProvider = base.getProvider(JavaExportsProvider.class);
if (javaExportsProvider != null) {
providerBuilder.exportedDepsBuilder().addTransitive(javaExportsProvider.getTransitiveExports());
}
// android_library without sources exports all its deps
if (ruleContext.getRule().getRuleClass().equals("android_library")) {
JavaSourceInfoProvider sourceInfoProvider = base.getProvider(JavaSourceInfoProvider.class);
boolean hasSources = sourceInfoProvider != null && !sourceInfoProvider.getSourceFiles().isEmpty();
if (!hasSources) {
for (TransitiveInfoCollection dep : directDeps) {
providerBuilder.exportedDepsBuilder().add(dep.getLabel());
}
}
}
// runtime_deps
List<? extends TransitiveInfoCollection> runtimeDeps = ImmutableList.of();
NestedSetBuilder<Label> runtimeDepsBuilder = NestedSetBuilder.stableOrder();
if (ruleContext.attributes().has("runtime_deps", BuildType.LABEL_LIST)) {
runtimeDeps = ruleContext.getPrerequisites("runtime_deps", Mode.TARGET);
for (TransitiveInfoCollection dep : runtimeDeps) {
runtimeDepsBuilder.add(dep.getLabel());
}
}
// resources
@Nullable TransitiveInfoCollection resources = ruleContext.attributes().has("resources", BuildType.LABEL) ? ruleContext.getPrerequisite("resources", Mode.TARGET) : null;
// Propagate providers from all prerequisites (deps + runtime_deps)
ImmutableList.Builder<TransitiveInfoCollection> prerequisitesBuilder = ImmutableList.builder();
prerequisitesBuilder.addAll(directDeps);
prerequisitesBuilder.addAll(runtimeDeps);
if (resources != null) {
prerequisitesBuilder.add(resources);
}
List<TransitiveInfoCollection> prerequisites = prerequisitesBuilder.build();
for (AndroidStudioInfoFilesProvider depProvider : AnalysisUtils.getProviders(prerequisites, AndroidStudioInfoFilesProvider.class)) {
providerBuilder.ideInfoFilesBuilder().addTransitive(depProvider.getIdeInfoFiles());
providerBuilder.ideInfoTextFilesBuilder().addTransitive(depProvider.getIdeInfoTextFiles());
providerBuilder.ideResolveFilesBuilder().addTransitive(depProvider.getIdeResolveFiles());
}
return new DependenciesResult(dependencies, runtimeDepsBuilder.build(), resources != null ? resources.getLabel() : null);
}
use of com.google.devtools.build.lib.analysis.TransitiveInfoCollection in project bazel by bazelbuild.
the class SkylarkRuleContext method buildAttributesCollection.
private static SkylarkRuleAttributesCollection buildAttributesCollection(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);
// 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(prereq.getLabel()));
}
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(ruleContext.getRule().getRuleClass(), attrBuilder.build(), executableBuilder.build(), fileBuilder.build(), filesBuilder.build(), executableRunfilesbuilder.build());
}
Aggregations