diff options
9 files changed, 207 insertions, 9 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java index 9708f3eb8b..7797838c06 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java @@ -86,6 +86,7 @@ import com.google.devtools.build.lib.skyframe.CoverageReportValue; import com.google.devtools.build.lib.skyframe.SkyframeAnalysisResult; import com.google.devtools.build.lib.skyframe.SkyframeBuildView; import com.google.devtools.build.lib.skyframe.SkyframeExecutor; +import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.SkylarkImport; import com.google.devtools.build.lib.syntax.SkylarkImports; @@ -1225,10 +1226,11 @@ public class BuildView { */ @VisibleForTesting public RuleContext getRuleContextForTesting( - ConfiguredTarget target, StoredEventHandler eventHandler, + ConfiguredTarget target, + StoredEventHandler eventHandler, BuildConfigurationCollection configurations) throws EvalException, InvalidConfigurationException, InterruptedException, - InconsistentAspectOrderException { + InconsistentAspectOrderException, ToolchainContextException { BuildConfiguration targetConfig = target.getConfiguration(); CachingAnalysisEnvironment env = new CachingAnalysisEnvironment(getArtifactFactory(), @@ -1243,12 +1245,20 @@ public class BuildView { * given configured target. */ @VisibleForTesting - public RuleContext getRuleContextForTesting(ExtendedEventHandler eventHandler, + public RuleContext getRuleContextForTesting( + ExtendedEventHandler eventHandler, ConfiguredTarget target, - AnalysisEnvironment env, BuildConfigurationCollection configurations) + AnalysisEnvironment env, + BuildConfigurationCollection configurations) throws EvalException, InvalidConfigurationException, InterruptedException, - InconsistentAspectOrderException { + InconsistentAspectOrderException, ToolchainContextException { BuildConfiguration targetConfig = target.getConfiguration(); + List<Label> requiredToolchains = + target.getTarget().getAssociatedRule().getRuleClassObject().getRequiredToolchains(); + ToolchainContext toolchainContext = + skyframeExecutor.getToolchainContextForTesting( + requiredToolchains, targetConfig, eventHandler); + return new RuleContext.Builder( env, (Rule) target.getTarget(), @@ -1263,6 +1273,7 @@ public class BuildView { .setPrerequisites(getPrerequisiteMapForTesting(eventHandler, target, configurations)) .setConfigConditions(ImmutableMap.<Label, ConfigMatchingProvider>of()) .setUniversalFragment(ruleClassProvider.getUniversalFragment()) + .setToolchainContext(toolchainContext) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java index d93c5a6dea..bc47c69d57 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java @@ -40,8 +40,9 @@ public class PlatformSemantics { @Override public List<Label> resolve( Rule rule, AttributeMap attributes, BuildConfiguration configuration) { - if (rule.getRuleClassObject().getRequiredToolchains().isEmpty()) { - return null; + // rule may be null for tests + if (rule == null || rule.getRuleClassObject().getRequiredToolchains().isEmpty()) { + return ImmutableList.of(); } return configuration.getFragment(PlatformConfiguration.class).getTargetPlatforms(); } @@ -52,7 +53,8 @@ public class PlatformSemantics { new Attribute.LateBoundLabel<BuildConfiguration>(PlatformConfiguration.class) { @Override public Label resolve(Rule rule, AttributeMap attributes, BuildConfiguration configuration) { - if (rule.getRuleClassObject().getRequiredToolchains().isEmpty()) { + // rule may be null for tests + if (rule == null || rule.getRuleClassObject().getRequiredToolchains().isEmpty()) { return null; } return configuration.getFragment(PlatformConfiguration.class).getExecutionPlatform(); diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java index 9cbdd475ac..8754c3e892 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java @@ -142,6 +142,7 @@ public class ToolchainContext { prerequisiteMap .keys() .stream() + .filter(attribute -> attribute != null) .filter(attribute -> attribute.getName().equals(PlatformSemantics.TOOLCHAINS_ATTR)) .findFirst(); Preconditions.checkState( diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java new file mode 100644 index 0000000000..7df8afddd5 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctionEnvironmentForTesting.java @@ -0,0 +1,65 @@ +// 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.skyframe; + +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.events.ExtendedEventHandler; +import com.google.devtools.build.lib.util.ResourceUsage; +import com.google.devtools.build.skyframe.AbstractSkyFunctionEnvironment; +import com.google.devtools.build.skyframe.BuildDriver; +import com.google.devtools.build.skyframe.EvaluationResult; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import com.google.devtools.build.skyframe.ValueOrExceptionUtils; +import com.google.devtools.build.skyframe.ValueOrUntypedException; +import java.util.Map; + +/** A skyframe environment that can be used to evaluate arbitrary skykeys for testing. */ +public class SkyFunctionEnvironmentForTesting extends AbstractSkyFunctionEnvironment + implements SkyFunction.Environment { + + private final BuildDriver buildDriver; + private final ExtendedEventHandler eventHandler; + + /** Creates a SkyFunctionEnvironmentForTesting that uses a BuildDriver to evaluate skykeys. */ + public SkyFunctionEnvironmentForTesting( + BuildDriver buildDriver, ExtendedEventHandler eventHandler) { + this.buildDriver = buildDriver; + this.eventHandler = eventHandler; + } + + @Override + protected Map<SkyKey, ValueOrUntypedException> getValueOrUntypedExceptions( + Iterable<? extends SkyKey> depKeys) throws InterruptedException { + ImmutableMap.Builder<SkyKey, ValueOrUntypedException> resultMap = ImmutableMap.builder(); + EvaluationResult<SkyValue> evaluationResult = + buildDriver.evaluate(depKeys, true, ResourceUsage.getAvailableProcessors(), eventHandler); + for (SkyKey depKey : depKeys) { + resultMap.put(depKey, ValueOrExceptionUtils.ofValue(evaluationResult.get(depKey))); + } + return resultMap.build(); + } + + @Override + public ExtendedEventHandler getListener() { + return eventHandler; + } + + @Override + public boolean inErrorBubblingForTesting() { + return false; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java index d46779124c..d6aec311a1 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java @@ -59,6 +59,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.Dependency; import com.google.devtools.build.lib.analysis.MergedConfiguredTarget; import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException; +import com.google.devtools.build.lib.analysis.ToolchainContext; import com.google.devtools.build.lib.analysis.TopLevelArtifactContext; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction; import com.google.devtools.build.lib.analysis.WorkspaceStatusAction.Factory; @@ -117,6 +118,7 @@ import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName; import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ActionCompletedReceiver; import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor.ProgressSupplier; import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; +import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException; import com.google.devtools.build.lib.syntax.SkylarkSemanticsOptions; import com.google.devtools.build.lib.util.AbruptExitException; import com.google.devtools.build.lib.util.ExitCode; @@ -830,6 +832,15 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory { return (WorkspaceStatusAction) value.get(); } + @VisibleForTesting + public ToolchainContext getToolchainContextForTesting( + List<Label> requiredToolchains, BuildConfiguration config, ExtendedEventHandler eventHandler) + throws ToolchainContextException, InterruptedException { + SkyFunctionEnvironmentForTesting env = + new SkyFunctionEnvironmentForTesting(buildDriver, eventHandler); + return ToolchainUtil.createToolchainContext(env, "", requiredToolchains, config); + } + /** * Informs user about number of modified files (source and output files). */ diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/MockPlatformSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/MockPlatformSupport.java new file mode 100644 index 0000000000..dd0b5463dd --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/packages/util/MockPlatformSupport.java @@ -0,0 +1,36 @@ +// 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.packages.util; + +import java.io.IOException; + +/** Mocking support for platforms and toolchains. */ +public class MockPlatformSupport { + + /** Adds mocks for basic host and target platform. */ + public static void setup(MockToolsConfig mockToolsConfig) throws IOException { + mockToolsConfig.create( + "buildenv/platforms/BUILD", + "package(default_visibility=['//visibility:public'])", + "platform(", + " name = 'target_platform',", + " target_platform = True,", + ")", + "platform(", + " name = 'host_platform',", + " host_platform = True,", + ")"); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/rules/platform/ToolchainTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/platform/ToolchainTestCase.java index bea2f5f227..23e92db4c1 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/platform/ToolchainTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/rules/platform/ToolchainTestCase.java @@ -41,7 +41,11 @@ public abstract class ToolchainTestCase extends SkylarkTestCase { "constraint_value(name = 'linux',", " constraint_setting = ':os')", "constraint_value(name = 'mac',", - " constraint_setting = ':os')"); + " constraint_setting = ':os')", + "platform(name = 'linux_plat',", + " constraint_values = [':linux'])", + "platform(name = 'mac_plat',", + " constraint_values = [':mac'])"); setting = ConstraintSettingInfo.create(makeLabel("//constraint:os")); linuxConstraint = ConstraintValueInfo.create(setting, makeLabel("//constraint:linux")); diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java new file mode 100644 index 0000000000..5ba165b4ed --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skyframe/RuleContextTest.java @@ -0,0 +1,42 @@ +// 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.skyframe; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.packages.util.MockPlatformSupport; +import com.google.devtools.build.lib.rules.platform.ToolchainTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for toolchains computed in BuildViewTestCase. */ +@RunWith(JUnit4.class) +public class RuleContextTest extends ToolchainTestCase { + + @Test + public void testMockRuleContextHasToolchains() throws Exception { + MockPlatformSupport.setup(mockToolsConfig); + mockToolsConfig.create("x/BUILD", "mock_toolchain_rule(name='x')"); + useConfiguration( + "--experimental_host_platform=//constraint:linux_plat", + "--experimental_platforms=//constraint:mac_plat"); + RuleContext ruleContext = getRuleContext(getConfiguredTarget("//x")); + assertThat(ruleContext.getToolchainContext().getResolvedToolchainLabels()) + .contains(Label.parseAbsolute("//toolchain:test_toolchain_1")); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java b/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java index 21661e446a..e69cb7ec0a 100644 --- a/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java +++ b/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java @@ -20,17 +20,21 @@ import static com.google.devtools.build.lib.packages.BuildType.OUTPUT_LIST; import static com.google.devtools.build.lib.syntax.Type.INTEGER; import static com.google.devtools.build.lib.syntax.Type.STRING_LIST; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.MakeVariableInfo; +import com.google.devtools.build.lib.analysis.PlatformConfiguration; +import com.google.devtools.build.lib.analysis.PlatformSemantics; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.RuleClass; @@ -72,6 +76,7 @@ public class TestRuleClassProvider { new ConfiguredRuleClassProvider.Builder(); addStandardRules(builder); builder.addRuleDefinition(new TestingDummyRule()); + builder.addRuleDefinition(new MockToolchainRule()); ruleProvider = builder.build(); } return ruleProvider; @@ -141,4 +146,25 @@ public class TestRuleClassProvider { .build(); } } + + /** A mock rule that requires a toolchain. */ + public static class MockToolchainRule implements RuleDefinition { + @Override + public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { + return PlatformSemantics.platformAttributes(builder) + .requiresConfigurationFragments(PlatformConfiguration.class) + .addRequiredToolchains( + ImmutableList.of(Label.parseAbsoluteUnchecked("//toolchain:test_toolchain"))) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("mock_toolchain_rule") + .factoryClass(UnknownRuleConfiguredTarget.class) + .ancestors(BaseRuleClasses.RuleBase.class) + .build(); + } + } } |