diff options
7 files changed, 173 insertions, 15 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index 6a5c3d2b1d..f021bec6c8 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -519,8 +519,8 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new AndroidDeviceRule()); builder.addSkylarkAccessibleTopLevels("android_common", new AndroidSkylarkCommon()); - builder.addSkylarkAccessibleTopLevels( - "java_common", new JavaSkylarkCommon(BazelJavaSemantics.INSTANCE)); + builder.addSkylarkAccessibleTopLevels("java_common", new JavaSkylarkCommon( + BazelJavaSemantics.INSTANCE, builder.getToolsRepository())); builder.addSkylarkAccessibleTopLevels("java_proto_common", JavaProtoSkylarkCommon.class); try { diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java index 73f9f09c51..108edd055c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java @@ -73,6 +73,9 @@ public class JavaRuntime implements RuleConfiguredTargetFactory { .addTransitiveArtifacts(filesToBuild) .build(); + JavaRuntimeProvider javaRuntime = new JavaRuntimeProvider( + filesToBuild, javaHome, javaBinaryExecPath, javaBinaryRunfilesPath); + MakeVariableProvider makeVariableProvider = new MakeVariableProvider(ImmutableMap.of( "JAVA", javaBinaryExecPath.getPathString(), "JAVABASE", javaHome.getPathString())); @@ -80,8 +83,8 @@ public class JavaRuntime implements RuleConfiguredTargetFactory { return new RuleConfiguredTargetBuilder(ruleContext) .addProvider(RunfilesProvider.class, RunfilesProvider.simple(runfiles)) .setFilesToBuild(filesToBuild) - .addProvider(JavaRuntimeProvider.class, JavaRuntimeProvider.create( - filesToBuild, javaHome, javaBinaryExecPath, javaBinaryRunfilesPath)) + .addProvider(JavaRuntimeProvider.class, javaRuntime) + .addNativeDeclaredProvider(javaRuntime) .addProvider(MiddlemanProvider.class, new MiddlemanProvider(middleman)) .addProvider(makeVariableProvider) .addNativeDeclaredProvider(makeVariableProvider) diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java index 7df3efcb7a..33235a3d04 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java @@ -14,34 +14,81 @@ package com.google.devtools.build.lib.rules.java; -import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.ClassObjectConstructor; +import com.google.devtools.build.lib.packages.NativeClassObjectConstructor; +import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.vfs.PathFragment; /** Information about the Java runtime used by the <code>java_*</code> rules. */ -@AutoValue +@SkylarkModule( + name = "JavaRuntimeInfo", + doc = "Information about the Java runtime being used." +) @Immutable -public abstract class JavaRuntimeProvider implements TransitiveInfoProvider { +public class JavaRuntimeProvider extends SkylarkClassObject + implements TransitiveInfoProvider { + public static final String SKYLARK_NAME = "JavaRuntimeInfo"; - public static JavaRuntimeProvider create( + public static final ClassObjectConstructor SKYLARK_CONSTRUCTOR = + new NativeClassObjectConstructor(JavaToolchainProvider.class, SKYLARK_NAME) {}; + + private final NestedSet<Artifact> javaBaseInputs; + private final PathFragment javaHome; + private final PathFragment javaBinaryExecPath; + private final PathFragment javaBinaryRunfilesPath; + + public JavaRuntimeProvider( NestedSet<Artifact> javaBaseInputs, PathFragment javaHome, PathFragment javaBinaryExecPath, PathFragment javaBinaryRunfilesPath) { - return new AutoValue_JavaRuntimeProvider( - javaBaseInputs, javaHome, javaBinaryExecPath, javaBinaryRunfilesPath); + super(SKYLARK_CONSTRUCTOR, ImmutableMap.<String, Object>of()); + this.javaBaseInputs = javaBaseInputs; + this.javaHome = javaHome; + this.javaBinaryExecPath = javaBinaryExecPath; + this.javaBinaryRunfilesPath = javaBinaryRunfilesPath; } /** All input artifacts in the javabase. */ - public abstract NestedSet<Artifact> javaBaseInputs(); + public NestedSet<Artifact> javaBaseInputs() { + return javaBaseInputs; + } /** The root directory of the Java installation. */ - public abstract PathFragment javaHome(); + public PathFragment javaHome() { + return javaHome; + } + @SkylarkCallable( + name = "java_executable_exec_path", + doc = "Returns the execpath of the Java executable.", + structField = true + ) /** The execpath of the Java binary. */ - public abstract PathFragment javaBinaryExecPath(); + public PathFragment javaBinaryExecPath() { + return javaBinaryExecPath; + } /** The runfiles path of the Java binary. */ - public abstract PathFragment javaBinaryRunfilesPath(); + public PathFragment javaBinaryRunfilesPath() { + return javaBinaryRunfilesPath; + } + + // Not all of JavaRuntimeProvider is exposed to Skylark, which makes implementing deep equality + // impossible: if Java-only parts are considered, the behavior is surprising in Skylark, if they + // are not, the behavior is surprising in Java. Thus, object identity it is. + @Override + public boolean equals(Object other) { + return other == this; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java index dfde6fd937..cab0d2c481 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java @@ -35,14 +35,17 @@ public class JavaRuntimeSuite implements RuleConfiguredTargetFactory { if (runtime == null) { runtime = ruleContext.getPrerequisite("default", Mode.TARGET); } + if (runtime == null) { ruleContext.throwWithRuleError( "could not resolve runtime for cpu " + ruleContext.getConfiguration().getCpu()); } MakeVariableProvider makeVariableProvider = runtime.getProvider(MakeVariableProvider.class); + return new RuleConfiguredTargetBuilder(ruleContext) .addProvider(JavaRuntimeProvider.class, runtime.getProvider(JavaRuntimeProvider.class)) + .addNativeDeclaredProvider(runtime.get(JavaRuntimeProvider.SKYLARK_CONSTRUCTOR.getKey())) .addProvider(RunfilesProvider.class, runtime.getProvider(RunfilesProvider.class)) .addProvider(MiddlemanProvider.class, runtime.getProvider(MiddlemanProvider.class)) .addProvider(makeVariableProvider) diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java index 7ac14a5c4e..4d3359161c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.rules.java; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.MiddlemanProvider; import com.google.devtools.build.lib.analysis.RuleContext; @@ -24,7 +25,10 @@ import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDe import com.google.devtools.build.lib.collect.nestedset.NestedSet; 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.Attribute; +import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.ClassObjectConstructor; +import com.google.devtools.build.lib.rules.SkylarkAttr; import com.google.devtools.build.lib.rules.SkylarkRuleContext; import com.google.devtools.build.lib.rules.java.proto.StrictDepsUtils; import com.google.devtools.build.lib.skylarkinterface.Param; @@ -40,9 +44,11 @@ import java.util.List; @SkylarkModule(name = "java_common", doc = "Utilities for Java compilation support in Skylark.") public class JavaSkylarkCommon { private final JavaSemantics javaSemantics; + private final String toolsRepository; - public JavaSkylarkCommon(JavaSemantics javaSemantics) { + public JavaSkylarkCommon(JavaSemantics javaSemantics, String toolsrepository) { this.javaSemantics = javaSemantics; + this.toolsRepository = toolsrepository; } @SkylarkCallable( @@ -452,4 +458,30 @@ public class JavaSkylarkCommon { + " Only OFF and ERROR values are accepted."); } } + + @SkylarkCallable( + name = JavaRuntimeProvider.SKYLARK_NAME, + doc = "The key used to retrieve the provider that contains information about the Java " + + "runtime being used.", + structField = true + ) + public static ClassObjectConstructor getJavaRuntimeProvider() { + return JavaRuntimeProvider.SKYLARK_CONSTRUCTOR; + } + + @SkylarkCallable( + name = "java_runtime_attr", + doc = "A value that, when passed as a value in the attribute dictionary of a rule " + + "definition, will yield a dependency that describes the current Java runtime in use.", + documented = false, + structField = true + ) + public SkylarkAttr.Descriptor getJvmAttribute() { + ConfiguredRuleClassProvider.Builder env = new ConfiguredRuleClassProvider.Builder(); + env.setToolsRepository(toolsRepository); + return new SkylarkAttr.Descriptor( + "java_runtime_attr", + new Attribute.Builder<>("", BuildType.LABEL) + .value(JavaSemantics.jvmAttribute(env))); + } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProviderTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProviderTest.java new file mode 100644 index 0000000000..750390dd5d --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProviderTest.java @@ -0,0 +1,48 @@ +// 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.java; + +import com.google.common.testing.EqualsTester; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.collect.nestedset.Order; +import com.google.devtools.build.lib.vfs.PathFragment; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@code JavaRuntimeProvider} + */ +@RunWith(JUnit4.class) +public class JavaRuntimeProviderTest { + @Test + public void equalityIsObjectIdentity() { + JavaRuntimeProvider a = new JavaRuntimeProvider( + NestedSetBuilder.emptySet(Order.STABLE_ORDER), + PathFragment.create(""), + PathFragment.create(""), + PathFragment.create("")); + JavaRuntimeProvider b = new JavaRuntimeProvider( + NestedSetBuilder.emptySet(Order.STABLE_ORDER), + PathFragment.create(""), + PathFragment.create(""), + PathFragment.create("")); + + new EqualsTester() + .addEqualityGroup(a) + .addEqualityGroup(b) + .testEquals(); + } +} diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java index f594ca2cfd..b16dd4e24e 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaSkylarkApiTest.java @@ -28,6 +28,7 @@ import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor.Skyl import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.OutputJar; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkNestedSet; +import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -43,6 +44,30 @@ import org.junit.runners.JUnit4; public class JavaSkylarkApiTest extends BuildViewTestCase { @Test + public void testJavaRuntimeProvider() throws Exception { + scratch.file("a/BUILD", + "load(':rule.bzl', 'jrule')", + "java_runtime(name='jvm', srcs=[], java_home='/foo/bar/')", + "java_runtime_suite(name='suite', default=':jvm')", + "jrule(name='r')"); + + scratch.file( + "a/rule.bzl", + "def _impl(ctx):", + " provider = ctx.attr._java_runtime[java_common.JavaRuntimeInfo]", + " return struct(", + " java_executable = provider.java_executable_exec_path,", + ")", + "jrule = rule(_impl, attrs = { '_java_runtime': java_common.java_runtime_attr})"); + + useConfiguration("--javabase=//a:suite"); + ConfiguredTarget ct = getConfiguredTarget("//a:r"); + @SuppressWarnings("unchecked") PathFragment javaExecutable = + (PathFragment) ct.get("java_executable"); + assertThat(javaExecutable.getPathString()).startsWith("/foo/bar/bin/java"); + } + + @Test public void testExposesJavaSkylarkApiProvider() throws Exception { scratch.file( "java/test/BUILD", |