diff options
8 files changed, 241 insertions, 30 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index 0fe30e15ed..3da2115a7f 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD @@ -761,8 +761,10 @@ java_library( "rules/java/JavaLibrary.java", "rules/java/JavaPlugin.java", "rules/java/JavaPrimaryClassProvider.java", + "rules/java/JavaProvider.java", "rules/java/JavaRuntimeClasspathProvider.java", "rules/java/JavaRuntimeJarProvider.java", + "rules/java/JavaSkylarkCommon.java", "rules/java/JavaSourceInfoProvider.java", "rules/java/JavaToolchain.java", "rules/java/JavaToolchainRule.java", 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 ef69aefd5a..5881098ba5 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 @@ -109,6 +109,7 @@ import com.google.devtools.build.lib.rules.genquery.GenQueryRule; import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader; import com.google.devtools.build.lib.rules.java.JavaImportBaseRule; import com.google.devtools.build.lib.rules.java.JavaOptions; +import com.google.devtools.build.lib.rules.java.JavaSkylarkCommon; import com.google.devtools.build.lib.rules.java.JavaToolchainRule; import com.google.devtools.build.lib.rules.java.JvmConfigurationLoader; import com.google.devtools.build.lib.rules.java.ProguardLibraryRule; @@ -522,6 +523,7 @@ public class BazelRuleClassProvider { builder.addSkylarkAccessibleTopLevels("android_common", new AndroidSkylarkCommon()); builder.addSkylarkAccessibleTopLevels("java_proto_common", JavaProtoSkylarkCommon.class); + builder.addSkylarkAccessibleTopLevels("java_common", JavaSkylarkCommon.INSTANCE); try { builder.addWorkspaceFilePrefix( diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java index 857e83a362..213cf7606a 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java @@ -44,6 +44,7 @@ import com.google.devtools.build.lib.packages.RuleClass.PackageNameConstraint; import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier; import com.google.devtools.build.lib.packages.TriState; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider; +import com.google.devtools.build.lib.rules.java.JavaProvider; import com.google.devtools.build.lib.rules.java.JavaSemantics; import com.google.devtools.build.lib.rules.java.JavaToolchainProvider; import com.google.devtools.build.lib.syntax.Type; @@ -149,12 +150,20 @@ public class BazelJavaRuleClasses { <a href="common-definitions.html#common-attributes">Attributes common to all build rules </a>. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ - .override(builder.copy("deps") - .allowedFileTypes(JavaSemantics.JAR) - .allowedRuleClasses(ALLOWED_RULES_IN_DEPS) - .mandatoryProviders(ImmutableList.of( - SkylarkProviderIdentifier.forKey(CcLinkParamsProvider.CC_LINK_PARAMS.getKey()))) - .skipAnalysisTimeFileTypeCheck()) + .override( + builder + .copy("deps") + .allowedFileTypes(JavaSemantics.JAR) + .allowedRuleClasses(ALLOWED_RULES_IN_DEPS) + .mandatoryProvidersList( + ImmutableList.of( + ImmutableList.of( + SkylarkProviderIdentifier.forKey( + CcLinkParamsProvider.CC_LINK_PARAMS.getKey())), + ImmutableList.of( + SkylarkProviderIdentifier.forKey( + JavaProvider.JAVA_PROVIDER.getKey())))) + .skipAnalysisTimeFileTypeCheck()) /* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(runtime_deps) --> Libraries to make available to the final binary or test at runtime only. Like ordinary <code>deps</code>, these will appear on the runtime classpath, but unlike @@ -162,10 +171,11 @@ public class BazelJavaRuleClasses { listed here. Dependency-analysis tools should ignore targets that appear in both <code>runtime_deps</code> and <code>deps</code>. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ - .add(attr("runtime_deps", LABEL_LIST) - .allowedFileTypes(JavaSemantics.JAR) - .allowedRuleClasses(ALLOWED_RULES_IN_DEPS) - .skipAnalysisTimeFileTypeCheck()) + .add( + attr("runtime_deps", LABEL_LIST) + .allowedFileTypes(JavaSemantics.JAR) + .allowedRuleClasses(ALLOWED_RULES_IN_DEPS) + .skipAnalysisTimeFileTypeCheck()) /* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(srcs) --> The list of source files that are processed to create the target. @@ -195,11 +205,14 @@ public class BazelJavaRuleClasses { class on the runtime classpath or you specify the <code>runtime_deps</code> argument. </p> <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ - .add(attr("srcs", LABEL_LIST) - .orderIndependent() - .direct_compile_time_input() - .allowedFileTypes(JavaSemantics.JAVA_SOURCE, - JavaSemantics.SOURCE_JAR, JavaSemantics.PROPERTIES)) + .add( + attr("srcs", LABEL_LIST) + .orderIndependent() + .direct_compile_time_input() + .allowedFileTypes( + JavaSemantics.JAVA_SOURCE, + JavaSemantics.SOURCE_JAR, + JavaSemantics.PROPERTIES)) /* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(resources) --> A list of data files to include in a Java jar. <p> @@ -217,8 +230,10 @@ public class BazelJavaRuleClasses { Resources may be source files or generated files. </p> <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ - .add(attr("resources", LABEL_LIST).orderIndependent() - .allowedFileTypes(FileTypeSet.ANY_FILE)) + .add( + attr("resources", LABEL_LIST) + .orderIndependent() + .allowedFileTypes(FileTypeSet.ANY_FILE)) /* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(resource_strip_prefix) --> The path prefix to strip from Java resources. <p> @@ -237,13 +252,17 @@ public class BazelJavaRuleClasses { <code><a href="#java_library.exported_plugins">exported_plugins</a></code>. Resources generated by the plugin will be included in the resulting jar of this rule. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ - .add(attr("plugins", LABEL_LIST).cfg(HOST).allowedRuleClasses("java_plugin") - .legacyAllowAnyFileType()) - .add(attr(":java_plugins", LABEL_LIST) - .cfg(HOST) - .allowedRuleClasses("java_plugin") - .silentRuleClassFilter() - .value(JavaSemantics.JAVA_PLUGINS)) + .add( + attr("plugins", LABEL_LIST) + .cfg(HOST) + .allowedRuleClasses("java_plugin") + .legacyAllowAnyFileType()) + .add( + attr(":java_plugins", LABEL_LIST) + .cfg(HOST) + .allowedRuleClasses("java_plugin") + .silentRuleClassFilter() + .value(JavaSemantics.JAVA_PLUGINS)) /* <!-- #BLAZE_RULE($java_rule).ATTRIBUTE(javacopts) --> Extra compiler options for this library. Subject to <a href="make-variables.html">"Make variable"</a> substitution and diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java index 6104833c31..a8de642c9f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java @@ -24,7 +24,6 @@ import com.google.devtools.build.lib.analysis.RunfilesProvider; 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.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.rules.cpp.CcLinkParams; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider; @@ -169,6 +168,11 @@ public class JavaLibrary implements RuleConfiguredTargetFactory { NestedSet<Artifact> proguardSpecs = new ProguardLibrary(ruleContext).collectProguardSpecs(); CcLinkParamsProvider ccLinkParamsProvider = new CcLinkParamsProvider(ccLinkParamsStore); + JavaCompilationArgsProvider compilationArgsProvider = + JavaCompilationArgsProvider.create( + javaCompilationArgs, recursiveJavaCompilationArgs, + compileTimeJavaDepArtifacts, runTimeJavaDepArtifacts); + JavaProvider javaProvider = new JavaProvider(compilationArgsProvider); builder .add( JavaRuleOutputJarsProvider.class, @@ -186,13 +190,11 @@ public class JavaLibrary implements RuleConfiguredTargetFactory { .setFilesToBuild(filesToBuild) .add(JavaNeverlinkInfoProvider.class, new JavaNeverlinkInfoProvider(neverLink)) .add(CppCompilationContext.class, transitiveCppDeps) - .add( - JavaCompilationArgsProvider.class, - JavaCompilationArgsProvider.create( - javaCompilationArgs, recursiveJavaCompilationArgs, - compileTimeJavaDepArtifacts, runTimeJavaDepArtifacts)) + .add(JavaCompilationArgsProvider.class, compilationArgsProvider) + .add(JavaProvider.class, javaProvider) .add(CcLinkParamsProvider.class, ccLinkParamsProvider) .addNativeDeclaredProvider(ccLinkParamsProvider) + .addNativeDeclaredProvider(javaProvider) .add( JavaNativeLibraryProvider.class, new JavaNativeLibraryProvider(transitiveJavaNativeLibraries)) diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java new file mode 100644 index 0000000000..b6ee004893 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java @@ -0,0 +1,39 @@ +// Copyright 2016 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.collect.ImmutableMap; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.SkylarkClassObject; +import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; + +/** A Skylark declared provider that encapsulates all providers that are needed by Java rules. */ +@Immutable +public final class JavaProvider extends SkylarkClassObject implements TransitiveInfoProvider { + + public static final SkylarkClassObjectConstructor JAVA_PROVIDER = + SkylarkClassObjectConstructor.createNative("java_common.provider"); + + private final JavaCompilationArgsProvider javaCompilationArgsProvider; + + public JavaProvider(JavaCompilationArgsProvider javaCompilationArgsProvider) { + super(JAVA_PROVIDER, ImmutableMap.<String, Object>of()); + this.javaCompilationArgsProvider = javaCompilationArgsProvider; + } + + public JavaCompilationArgsProvider getJavaCompilationArgsProvider() { + return javaCompilationArgsProvider; + } +} 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 new file mode 100644 index 0000000000..7797ef5658 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java @@ -0,0 +1,33 @@ +// Copyright 2016 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.devtools.build.lib.packages.SkylarkClassObjectConstructor; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; + +/** A module that contains Skylark utilities for Java support. */ +@SkylarkModule(name = "java_common", doc = "Utilities for Java compilation support in Skylark.") +public class JavaSkylarkCommon { + public static final JavaSkylarkCommon INSTANCE = new JavaSkylarkCommon(); + + @SkylarkCallable( + name = "provider", + structField = true, + doc = "Returns the Java declared provider." + ) + public SkylarkClassObjectConstructor getJavaProvider() { + return JavaProvider.JAVA_PROVIDER; + } +} diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD index 47e35eaf96..9fadf7f6f5 100644 --- a/src/test/java/com/google/devtools/build/lib/BUILD +++ b/src/test/java/com/google/devtools/build/lib/BUILD @@ -895,6 +895,7 @@ java_test( "//src/main/java/com/google/devtools/build/lib:bazel-main", "//src/main/java/com/google/devtools/build/lib:bazel-rules", "//src/main/java/com/google/devtools/build/lib:build-base", + "//src/main/java/com/google/devtools/build/lib:collect", "//src/main/java/com/google/devtools/build/lib:java-compilation", "//src/main/java/com/google/devtools/build/lib:java-rules", "//src/main/java/com/google/devtools/build/lib:packages-internal", 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 8a18f541d9..616fdb71b5 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 @@ -22,8 +22,10 @@ import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.SkylarkProviders; import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.packages.SkylarkClassObject; import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor.SkylarkKey; +import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; import org.junit.Test; @@ -80,4 +82,115 @@ public class JavaSkylarkApiTest extends BuildViewTestCase { assertThat((List<?>) skylarkClassObject.getValue("processor_classnames")) .containsExactly("com.google.process.stuff"); } + + @Test + public void cannotConstructJavaProvider() throws Exception { + scratch.file( + "foo/extension.bzl", + "my_provider = provider()", + "def _impl(ctx):", + " java_p = java_common.provider", + " dep_params = java_p()", + " return [my_provider(p = dep_params)]", + "my_rule = rule(_impl, attrs = { 'dep' : attr.label() })"); + scratch.file("foo/BUILD", "load(':extension.bzl', 'my_rule')", "my_rule(name = 'r')"); + reporter.removeHandler(failFastHandler); + assertThat(getConfiguredTarget("//foo:r")).isNull(); + assertContainsEvent("'java_common.provider' cannot be constructed from Skylark"); + } + + @Test + public void javaProviderExposedOnJavaLibrary() throws Exception { + scratch.file( + "foo/extension.bzl", + "my_provider = provider()", + "def _impl(ctx):", + " dep_params = ctx.attr.dep[java_common.provider]", + " return [my_provider(p = dep_params)]", + "my_rule = rule(_impl, attrs = { 'dep' : attr.label() })"); + scratch.file( + "foo/BUILD", + "load(':extension.bzl', 'my_rule')", + "java_library(name = 'jl', srcs = ['java/A.java'])", + "my_rule(name = 'r', dep = ':jl')"); + + ConfiguredTarget myRuleTarget = getConfiguredTarget("//foo:r"); + ConfiguredTarget javaLibraryTarget = getConfiguredTarget("//foo:jl"); + SkylarkKey myProviderKey = + new SkylarkKey(Label.parseAbsolute("//foo:extension.bzl"), "my_provider"); + SkylarkClassObject declaredProvider = + myRuleTarget.getProvider(SkylarkProviders.class).getDeclaredProvider(myProviderKey); + Object javaProvider = declaredProvider.getValue("p"); + assertThat(javaProvider).isInstanceOf(JavaProvider.class); + assertThat(javaLibraryTarget.getProvider(JavaProvider.class)).isEqualTo(javaProvider); + } + + @Test + public void javaProviderPropagation() throws Exception { + scratch.file( + "foo/extension.bzl", + "def _impl(ctx):", + " dep_params = ctx.attr.dep[java_common.provider]", + " return [dep_params]", + "my_rule = rule(_impl, attrs = { 'dep' : attr.label() })"); + scratch.file( + "foo/BUILD", + "load(':extension.bzl', 'my_rule')", + "java_library(name = 'jl', srcs = ['java/A.java'])", + "my_rule(name = 'r', dep = ':jl')", + "java_library(name = 'jl_top', srcs = ['java/C.java'], deps = [':r'])"); + + ConfiguredTarget myRuleTarget = getConfiguredTarget("//foo:r"); + ConfiguredTarget javaLibraryTarget = getConfiguredTarget("//foo:jl"); + ConfiguredTarget topJavaLibraryTarget = getConfiguredTarget("//foo:jl_top"); + + Object javaProvider = myRuleTarget.get(JavaProvider.JAVA_PROVIDER.getKey()); + assertThat(javaProvider).isInstanceOf(JavaProvider.class); + + JavaProvider jlJavaProvider = javaLibraryTarget.getProvider(JavaProvider.class); + + assertThat(jlJavaProvider == javaProvider).isTrue(); + + JavaProvider jlTopJavaProvider = topJavaLibraryTarget.getProvider(JavaProvider.class); + + javaCompilationArgsHaveTheSameParent( + jlJavaProvider.getJavaCompilationArgsProvider().getJavaCompilationArgs(), + jlTopJavaProvider.getJavaCompilationArgsProvider().getJavaCompilationArgs()); + } + + private static boolean javaCompilationArgsHaveTheSameParent( + JavaCompilationArgs args, JavaCompilationArgs otherArgs) { + if (!nestedSetsOfArtifactHaveTheSameParent( + args.getCompileTimeJars(), otherArgs.getCompileTimeJars())) { + return false; + } + if (!nestedSetsOfArtifactHaveTheSameParent( + args.getInstrumentationMetadata(), otherArgs.getInstrumentationMetadata())) { + return false; + } + if (!nestedSetsOfArtifactHaveTheSameParent(args.getRuntimeJars(), otherArgs.getRuntimeJars())) { + return false; + } + return true; + } + + private static boolean nestedSetsOfArtifactHaveTheSameParent( + NestedSet<Artifact> artifacts, NestedSet<Artifact> otherArtifacts) { + Iterator<Artifact> iterator = artifacts.iterator(); + Iterator<Artifact> otherIterator = otherArtifacts.iterator(); + while (iterator.hasNext() && otherIterator.hasNext()) { + Artifact artifact = (Artifact) iterator.next(); + Artifact otherArtifact = (Artifact) otherIterator.next(); + if (!artifact + .getPath() + .getParentDirectory() + .equals(otherArtifact.getPath().getParentDirectory())) { + return false; + } + } + if (iterator.hasNext() || otherIterator.hasNext()) { + return false; + } + return true; + } }
\ No newline at end of file |