Skip to content

Commit

Permalink
Add platform rule to define a platform as a collection of constraint
Browse files Browse the repository at this point in the history
values.

Part of ongoing work on bazelbuild#2219.

Change-Id: Ie4e842a5d8218e47f41a954c2b955ab24237aa65
  • Loading branch information
katre committed Feb 24, 2017
1 parent 4e1415c commit 0de692d
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
import com.google.devtools.build.lib.rules.objc.XcTestAppProvider;
import com.google.devtools.build.lib.rules.platform.ConstraintSettingRule;
import com.google.devtools.build.lib.rules.platform.ConstraintValueRule;
import com.google.devtools.build.lib.rules.platform.PlatformRule;
import com.google.devtools.build.lib.rules.proto.BazelProtoLibraryRule;
import com.google.devtools.build.lib.rules.proto.ProtoConfiguration;
import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainRule;
Expand Down Expand Up @@ -343,6 +344,7 @@ public ImmutableList<RuleSet> requires() {
public void init(Builder builder) {
builder.addRuleDefinition(new ConstraintSettingRule());
builder.addRuleDefinition(new ConstraintValueRule());
builder.addRuleDefinition(new PlatformRule());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.google.devtools.build.lib.rules.platform;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;

/** Defines a platform for execution contexts. */
public class Platform implements RuleConfiguredTargetFactory {
@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws InterruptedException, RuleErrorException {

// TODO(katre): Create platform provider with correct data.
Iterable<ConstraintValueProvider> constraintValues =
ruleContext.getPrerequisites(
PlatformRule.CONSTRAINTS_ATTR, Mode.DONT_CHECK, ConstraintValueProvider.class);

// TODO(katre): Verify the constraints - no two settings.
ImmutableMap<ConstraintSettingProvider, ConstraintValueProvider> constraints = validateConstraints(ruleContext, constraintValues);
if (constraints == null) {
// An error occurred, return null.
return null;
}

PlatformProvider provider = PlatformProvider.create(constraints);

return new RuleConfiguredTargetBuilder(ruleContext)
.addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
.addProvider(FileProvider.class, FileProvider.EMPTY)
.addProvider(FilesToRunProvider.class, FilesToRunProvider.EMPTY)
.addProvider(PlatformProvider.class, provider)
.build();
}

private ImmutableMap<ConstraintSettingProvider, ConstraintValueProvider> validateConstraints(RuleContext ruleContext,
Iterable<ConstraintValueProvider> constraintValues) {
Multimap<ConstraintSettingProvider, ConstraintValueProvider> constraints = ArrayListMultimap.create();

for (ConstraintValueProvider constraintValue : constraintValues) {
constraints.put(constraintValue.constraint(), constraintValue);
}

// Are there any settings with more than one value?
for (ConstraintSettingProvider constraintSetting : constraints.keySet()) {
if (constraints.get(constraintSetting).size() > 1) {
// error
}
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2017 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.lib.rules.platform;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;

/** Provider for a platform, which is a group of constraints and values. */
@AutoValue
@Immutable
public abstract class PlatformProvider implements TransitiveInfoProvider {
public abstract ImmutableMap<ConstraintSettingProvider, ConstraintValueProvider> constraints();

public static PlatformProvider create(
ImmutableMap<ConstraintSettingProvider, ConstraintValueProvider> constraints) {
return new AutoValue_PlatformProvider(constraints);
}

public static PlatformProvider create(Iterable<ConstraintValueProvider> constraintValues) {
ImmutableMap.Builder<ConstraintSettingProvider, ConstraintValueProvider> builder =
new ImmutableMap.Builder<>();

for (ConstraintValueProvider constraintValue : constraintValues) {
builder.put(constraintValue.constraint(), constraintValue);
}

return create(builder.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.google.devtools.build.lib.rules.platform;

import static com.google.devtools.build.lib.packages.Attribute.attr;

import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileTypeSet;

/** Rule definition for {@link Platform}. */
public class PlatformRule implements RuleDefinition {
public static final String RULE_NAME = "platform";
public static final String CONSTRAINTS_ATTR = "constraints";

@Override
public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
/* <!-- #BLAZE_RULE(platform).NAME -->
<!-- #END_BLAZE_RULE.NAME --> */
return builder
.override(
attr("tags", Type.STRING_LIST)
// No need to show up in ":all", etc. target patterns.
.value(ImmutableList.of("manual"))
.nonconfigurable("low-level attribute, used in platform configuration"))

// TODO(katre): add constraints attr.
.add(
attr(CONSTRAINTS_ATTR, BuildType.LABEL_LIST)
.allowedFileTypes(FileTypeSet.NO_FILE)
.mandatoryNativeProviders(
ImmutableList.<Class<? extends TransitiveInfoProvider>>of(
ConstraintValueProvider.class)))
.exemptFromConstraintChecking("this rule *defines* a constraint")
.build();
}

@Override
public Metadata getMetadata() {
return Metadata.builder()
.name(RULE_NAME)
.ancestors(BaseRuleClasses.RuleBase.class)
.factoryClass(Platform.class)
.build();
}
}
/*<!-- #BLAZE_RULE (NAME = platform, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
<!-- #END_BLAZE_RULE -->*/
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,49 @@ public void testConstraint() throws Exception {
assertThat(barValue.getProvider(ConstraintValueProvider.class).value())
.isEqualTo(Label.parseAbsolute("//constraint:bar"));
}

@Test
public void testPlatform() throws Exception {
scratch.file(
"constraint/BUILD",
"constraint_setting(name = 'basic')",
"constraint_value(name = 'foo',",
" constraint=':basic',",
" )",
"platform(name = 'plat1',",
" constraints = [",
" ':foo',",
" ])"
);

ConfiguredTarget platform = getConfiguredTarget("//constraint:plat1");
assertThat(platform).isNotNull();

PlatformProvider provider = platform.getProvider(PlatformProvider.class);
assertThat(provider).isNotNull();
assertThat(provider.constraints()).hasSize(1);
assertThat(provider.constraints()).containsKey(ConstraintSettingProvider.create(Label.parseAbsolute("//constraint:basic")));
assertThat(provider.constraints().get(ConstraintSettingProvider.create(Label.parseAbsolute("//constraint:basic"))).value())
.isEqualTo(Label.parseAbsolute("//constraint:foo"));
}

@Test
public void testPlatform_overlappingConstraintValueError() throws Exception {
checkError("constraint",
"plat1",
"Conflicting constraint values for //constraint:basic",
"constraint_setting(name = 'basic')",
"constraint_value(name = 'foo',",
" constraint=':basic',",
" )",
"constraint_value(name = 'bar',",
" constraint=':basic',",
" )",
"platform(name = 'plat1',",
" constraints = [",
" ':foo',",
" ':bar',",
" ])"
);
}
}

0 comments on commit 0de692d

Please sign in to comment.