diff options
author | 2017-01-16 09:11:33 +0000 | |
---|---|---|
committer | 2017-01-16 13:47:07 +0000 | |
commit | e9674fb187b5b95136eb93058eab9d48dcfdbeca (patch) | |
tree | 450ff9f6a59166a0767a1f39ed60aee3ab3aa52c | |
parent | 266bb166293c44cd6fb25d66fc2b2aff328ed69e (diff) |
Adding Java compilation to java_lite_proto_library Skylark version.
--
PiperOrigin-RevId: 144608820
MOS_MIGRATED_REVID=144608820
5 files changed, 568 insertions, 3 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 d89953d1bf..362fd2709b 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 @@ -52,6 +52,7 @@ import com.google.devtools.build.lib.bazel.rules.java.BazelJavaImportRule; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaLibraryRule; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaPluginRule; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses; +import com.google.devtools.build.lib.bazel.rules.java.BazelJavaSemantics; import com.google.devtools.build.lib.bazel.rules.java.BazelJavaTestRule; import com.google.devtools.build.lib.bazel.rules.java.proto.BazelJavaLiteProtoAspect; import com.google.devtools.build.lib.bazel.rules.java.proto.BazelJavaLiteProtoLibraryRule; @@ -550,8 +551,9 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new BazelAarImportRule()); builder.addSkylarkAccessibleTopLevels("android_common", new AndroidSkylarkCommon()); + builder.addSkylarkAccessibleTopLevels( + "java_common", new JavaSkylarkCommon(BazelJavaSemantics.INSTANCE)); 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/rules/java/JavaSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSkylarkCommon.java index 7797ef5658..632dba6da4 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 @@ -13,14 +13,33 @@ // limitations under the License. package com.google.devtools.build.lib.rules.java; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.MiddlemanProvider; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode; +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.SkylarkClassObjectConstructor; +import com.google.devtools.build.lib.rules.SkylarkRuleContext; +import com.google.devtools.build.lib.skylarkinterface.Param; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; +import com.google.devtools.build.lib.syntax.SkylarkList; +import java.util.LinkedList; +import java.util.List; /** 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(); + private final JavaSemantics javaSemantics; + + public JavaSkylarkCommon(JavaSemantics javaSemantics) { + this.javaSemantics = javaSemantics; + } @SkylarkCallable( name = "provider", @@ -30,4 +49,119 @@ public class JavaSkylarkCommon { public SkylarkClassObjectConstructor getJavaProvider() { return JavaProvider.JAVA_PROVIDER; } + + @SkylarkCallable( + name = "compile", + // There is one mandatory positional: the Skylark rule context. + mandatoryPositionals = 1, + parameters = { + @Param( + name = "source_jars", + positional = false, + named = true, + type = SkylarkList.class, + generic1 = Artifact.class + ), + @Param(name = "output", positional = false, named = true, type = Artifact.class), + @Param( + name = "javac_opts", + positional = false, + named = true, + type = SkylarkList.class, + generic1 = String.class + ), + @Param( + name = "deps", + positional = false, + named = true, + type = SkylarkList.class, + generic1 = JavaProvider.class + ), + @Param( + name = "strict_deps", + defaultValue = "OFF", + positional = false, + named = true, + type = String.class + ), + @Param( + name = "java_toolchain", + positional = false, + named = true, + type = ConfiguredTarget.class + ), + @Param( + name = "host_javabase", + positional = false, + named = true, + type = ConfiguredTarget.class + ), + } + ) + public JavaProvider createJavaCompileAction( + SkylarkRuleContext skylarkRuleContext, + SkylarkList<Artifact> sourceJars, + Artifact outputJar, + SkylarkList<String> javacOpts, + SkylarkList<JavaProvider> deps, + String strictDepsMode, + ConfiguredTarget javaToolchain, + ConfiguredTarget hostJavabase) { + JavaLibraryHelper helper = + new JavaLibraryHelper(skylarkRuleContext.getRuleContext()) + .setOutput(outputJar) + .addSourceJars(sourceJars) + .setJavacOpts(javacOpts); + helper.addAllDeps(getJavaCompilationArgsProviders(deps)); + helper.setCompilationStrictDepsMode(getStrictDepsMode(strictDepsMode)); + MiddlemanProvider hostJavabaseProvider = hostJavabase.getProvider(MiddlemanProvider.class); + + NestedSet<Artifact> hostJavabaseArtifacts = + hostJavabase == null + ? NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER) + : hostJavabaseProvider.getMiddlemanArtifact(); + JavaToolchainProvider javaToolchainProvider = + checkNotNull(javaToolchain.getProvider(JavaToolchainProvider.class)); + JavaCompilationArgs artifacts = + helper.build( + javaSemantics, + javaToolchainProvider, + hostJavabaseArtifacts, + SkylarkList.createImmutable(ImmutableList.<Artifact>of())); + return new JavaProvider(helper.buildCompilationArgsProvider(artifacts, true)); + } + + @SkylarkCallable( + name = "merge", + // We have one positional argument: the list of providers to merge. + mandatoryPositionals = 1 + ) + public static JavaProvider mergeJavaProviders(SkylarkList<JavaProvider> providers) { + return new JavaProvider( + JavaCompilationArgsProvider.merge(getJavaCompilationArgsProviders(providers))); + } + + private static List<JavaCompilationArgsProvider> getJavaCompilationArgsProviders( + SkylarkList<JavaProvider> providers) { + List<JavaCompilationArgsProvider> javaCompilationArgsProviders = new LinkedList<>(); + for (JavaProvider provider : providers) { + javaCompilationArgsProviders.add(provider.getJavaCompilationArgsProvider()); + } + return javaCompilationArgsProviders; + } + + private static StrictDepsMode getStrictDepsMode(String strictDepsMode) { + switch (strictDepsMode) { + case "OFF": + return StrictDepsMode.OFF; + case "ERROR": + return StrictDepsMode.ERROR; + default: + throw new IllegalArgumentException( + "StrictDepsMode " + + strictDepsMode + + " not allowed." + + " Only OFF and ERROR values are accepted."); + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoSkylarkCommon.java index 4135d4029a..5612095478 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoSkylarkCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoSkylarkCommon.java @@ -19,7 +19,12 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.rules.SkylarkRuleContext; +import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; +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.rules.proto.ProtoCompileActionBuilder; import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainProvider; import com.google.devtools.build.lib.rules.proto.ProtoSupportDataProvider; @@ -27,6 +32,7 @@ import com.google.devtools.build.lib.rules.proto.SupportData; import com.google.devtools.build.lib.skylarkinterface.Param; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; +import java.util.List; /** * A class that exposes Java common methods for proto compilation. @@ -77,6 +83,47 @@ public class JavaProtoSkylarkCommon { true /* allowServices */); } + @SkylarkCallable( + name = "toolchain_deps", + // This function is experimental for now. + documented = false, + // There's only one mandatory positional,the Skylark context + mandatoryPositionals = 1, + parameters = { + @Param(name = "proto_toolchain_attr", positional = false, named = true, type = String.class) + } + ) + public static JavaProvider getRuntimeToolchainProvider( + SkylarkRuleContext skylarkRuleContext, String protoToolchainAttr) { + TransitiveInfoCollection runtime = + getProtoToolchainProvider(skylarkRuleContext, protoToolchainAttr).runtime(); + return new JavaProvider(runtime.getProvider(JavaCompilationArgsProvider.class)); + } + + @SkylarkCallable( + name = "javac_opts", + // This function is experimental for now. + documented = false, + // There's only one mandatory positional,the Skylark context + mandatoryPositionals = 1, + parameters = { + @Param(name = "java_toolchain_attr", positional = false, named = true, type = String.class) + } + ) + // TODO(elenairina): Consider a nicer way of returning this, taking in a JavaToolchainProvider. + public static List<String> getJavacOpts( + SkylarkRuleContext skylarkRuleContext, String javaToolchainAttr) { + ConfiguredTarget javaToolchainConfigTarget = + (ConfiguredTarget) checkNotNull(skylarkRuleContext.getAttr().getValue(javaToolchainAttr)); + JavaToolchainProvider toolchain = + checkNotNull(javaToolchainConfigTarget.getProvider(JavaToolchainProvider.class)); + + return ImmutableList.<String>builder() + .addAll(toolchain.getJavacOptions()) + .addAll(toolchain.getCompatibleJavacOptions(JavaSemantics.PROTO_JAVACOPTS_KEY)) + .build(); + } + private static ProtoLangToolchainProvider getProtoToolchainProvider( SkylarkRuleContext skylarkRuleContext, String protoToolchainAttr) { ConfiguredTarget javaliteToolchain = (ConfiguredTarget) checkNotNull( diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java index bb859c90c6..387b565e44 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java @@ -157,12 +157,28 @@ public final class EvalUtils { || c.equals(String.class) // basic values || c.equals(Integer.class) || c.equals(Boolean.class) - || c.isAnnotationPresent(SkylarkModule.class) // registered Skylark class + // there is a registered Skylark ancestor class (useful e.g. when using AutoValue) + || hasSkylarkAcceptableAncestor(c) || ImmutableMap.class.isAssignableFrom(c) // will be converted to SkylarkDict || NestedSet.class.isAssignableFrom(c) // will be converted to SkylarkNestedSet || c.equals(PathFragment.class); // other known class } + private static boolean hasSkylarkAcceptableAncestor(Class<?> c) { + if (c == null) { + return false; + } + if (c.isAnnotationPresent(SkylarkModule.class)) { + return true; + } + for (Class<?> inter : c.getInterfaces()) { + if (hasSkylarkAcceptableAncestor(inter)) { + return true; + } + } + return hasSkylarkAcceptableAncestor(c.getSuperclass()); + } + // TODO(bazel-team): move the following few type-related functions to SkylarkType /** * Return the Skylark-type of {@code c} diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/proto/SkylarkJavaLiteProtoLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/proto/SkylarkJavaLiteProtoLibraryTest.java new file mode 100644 index 0000000000..d4fae4a945 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/rules/java/proto/SkylarkJavaLiteProtoLibraryTest.java @@ -0,0 +1,366 @@ +// 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.proto; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.devtools.build.lib.actions.Artifact.ROOT_RELATIVE_PATH_STRING; +import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames; +import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyJarNames; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Multimaps; +import com.google.common.eventbus.EventBus; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.util.ActionsTestUtil; +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.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.rules.java.JavaCompilationArgs; +import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; +import com.google.devtools.build.lib.rules.java.JavaCompileAction; +import com.google.devtools.build.lib.rules.java.JavaProvider; +import com.google.devtools.build.lib.testutil.MoreAsserts; +import com.google.devtools.build.runtime.Runfiles; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for the Skylark version of java_lite_proto_library rule. + */ +@RunWith(JUnit4.class) +public class SkylarkJavaLiteProtoLibraryTest extends BuildViewTestCase { + private static final String RULE_DIRECTORY = "tools/build_rules/java_lite_proto_library"; + private ActionsTestUtil actionsTestUtil; + + @Before + public final void setUpMocks() throws Exception { + scratch.file( + "java/com/google/io/protocol/BUILD", + "package(default_visibility=['//visibility:public'])", + "java_import(name = 'protocol',", + " jars = [ 'protocol.jar' ])"); + scratch.file( + "java/com/google/io/protocol2/BUILD", + "package(default_visibility=['//visibility:public'])", + "java_import(name = 'protocol2',", + " jars = [ 'protocol2.jar' ])"); + + scratch.file("net/proto/BUILD", "exports_files(['sawzall_message_set.proto'])"); + scratch.file("net/proto2/compiler/public/BUILD", "exports_files(['protocol_compiler'])"); + + mockToolchains(); + + actionsTestUtil = actionsTestUtil(); + } + + @Before + public final void setupSkylarkRule() throws Exception { + File[] files = Runfiles.location(RULE_DIRECTORY).listFiles(); + for (File file : files) { + scratch.file(RULE_DIRECTORY + "/" + file.getName(), Files.readAllBytes(file.toPath())); + } + scratch.file(RULE_DIRECTORY + "/BUILD", "exports_files(['java_lite_proto_library.bzl'])"); + invalidatePackages(); + } + + private void mockToolchains() throws IOException { + mockRuntimes(); + + scratch.file( + "tools/proto/toolchains/BUILD", + "package(default_visibility=['//visibility:public'])", + "proto_lang_toolchain(", + " name = 'javalite',", + " command_line = '--java_out=lite,immutable,no_enforce_api_compatibility:$(OUT)',", + " runtime = '//protobuf:javalite_runtime',", + ")"); + } + + private void mockRuntimes() throws IOException { + mockToolsConfig.overwrite( + "protobuf/BUILD", + "package(default_visibility=['//visibility:public'])", + "java_library(name = 'javalite_runtime', srcs = ['javalite_runtime.java'])"); + } + + /** Tests that java_binaries which depend on proto_libraries depend on the right set of files. */ + @Test + public void testBinaryDeps() throws Exception { + scratch.file( + "x/BUILD", + "load('//" + RULE_DIRECTORY + ":java_lite_proto_library.bzl', ", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'lite_pb2', deps = [':foo'])", + "proto_library(name = 'foo', srcs = ['foo.proto', 'bar.proto'], deps = [':baz'])", + "proto_library(name = 'baz', srcs = ['baz.proto'])"); + + ConfiguredTarget target = getConfiguredTarget("//x:lite_pb2"); + NestedSet<Artifact> filesToBuild = getFilesToBuild(target); + Iterable<String> deps = prettyArtifactNames(actionsTestUtil.artifactClosureOf(filesToBuild)); + + // Should depend on compiler and Java proto1 API. + assertThat(deps).contains("net/proto2/compiler/public/protocol_compiler"); + + // Also should not depend on RPC APIs. + assertThat(deps).doesNotContain("apps/xplat/rpc/codegen/protoc-gen-rpc"); + + // Should depend on Java outputs. + assertThat(deps).contains("x/foo-lite-src.jar"); + assertThat(deps).contains("x/baz-lite-src.jar"); + + // Should depend on Java libraries. + assertThat(deps).contains("x/libfoo-lite.jar"); + assertThat(deps).contains("x/libbaz-lite.jar"); + assertThat(deps).contains("protobuf/libjavalite_runtime-hjar.jar"); + } + + /** Tests that we pass the correct arguments to the protocol compiler. */ + @Test + public void testJavaProto2CompilerArgs() throws Exception { + scratch.file( + "x/BUILD", + "load('//" + RULE_DIRECTORY + ":java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'lite_pb2', deps = [':protolib'])", + "proto_library(name = 'protolib', srcs = ['file.proto'])"); + + String genfilesDir = targetConfig.getGenfilesFragment().getPathString(); + + List<String> args = + getGeneratingSpawnAction(getConfiguredTarget("//x:lite_pb2"), "x/protolib-lite-src.jar") + .getRemainingArguments(); + + assertThat(args) + .contains( + "--java_out=lite,immutable,no_enforce_api_compatibility:" + + genfilesDir + + "/x/protolib-lite-src.jar"); + + MoreAsserts.assertContainsSublist(args, "-Ix/file.proto=x/file.proto", "x/file.proto"); + } + + @Test + public void testProtoLibraryBuildsCompiledJar() throws Exception { + ConfiguredTarget target = + scratchConfiguredTarget( + "java", + "lite_pb2", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'lite_pb2', deps = [':compiled'])", + "proto_library(name = 'compiled',", + " srcs = [ 'ok.proto' ])"); + + Artifact compiledJar = + ActionsTestUtil.getFirstArtifactEndingWith( + getFilesToBuild(target), "/libcompiled-lite.jar"); + assertThat(compiledJar).isNotNull(); + } + + @Test + public void testEmptySrcsForJavaApi() throws Exception { + ConfiguredTarget target = + scratchConfiguredTarget( + "notbad", + "lite_pb2", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'lite_pb2', deps = [':null_lib'])", + "proto_library(name = 'null_lib')"); + JavaCompilationArgsProvider provider = getJavaCompilationArgsProvider(target); + assertThat(provider).isNotNull(); + assertThat(provider.getJavaCompilationArgs()).isNotNull(); + } + + @Test + public void testSameVersionCompilerArguments() throws Exception { + scratch.file( + "cross/BUILD", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'lite_pb2', deps = ['bravo'], strict_deps = 0)", + "proto_library(name = 'bravo', srcs = ['bravo.proto'], deps = [':alpha'])", + "proto_library(name = 'alpha')"); + + String genfilesDir = targetConfig.getGenfilesFragment().getPathString(); + + ConfiguredTarget litepb2 = getConfiguredTarget("//cross:lite_pb2"); + + List<String> args = + getGeneratingSpawnAction(litepb2, "cross/bravo-lite-src.jar").getRemainingArguments(); + assertThat(args) + .contains( + "--java_out=lite,immutable,no_enforce_api_compatibility:" + + genfilesDir + + "/cross/bravo-lite-src.jar"); + MoreAsserts.assertContainsSublist( + args, "-Icross/bravo.proto=cross/bravo.proto", "cross/bravo.proto"); + + List<String> directJars = + prettyJarNames( + getJavaCompilationArgsProvider(litepb2).getJavaCompilationArgs().getRuntimeJars()); + assertThat(directJars).containsExactly("cross/libbravo-lite.jar"); + } + + /** Protobufs should always be compiled with the default and proto javacopts. */ + @Test + public void testJavacOpts() throws Exception { + ConfiguredTarget rule = + scratchConfiguredTarget( + "x", + "lite_pb2", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'lite_pb2', deps = [':proto_lib'])", + "proto_library(name = 'proto_lib',", + " srcs = ['input1.proto', 'input2.proto'])"); + JavaCompilationArgs compilationArgs = + getJavaCompilationArgsProvider(rule).getJavaCompilationArgs(); + assertThat(compilationArgs.getInstrumentationMetadata()).isEmpty(); + + ImmutableListMultimap<String, Artifact> runtimeJars = + Multimaps.index(compilationArgs.getRuntimeJars(), ROOT_RELATIVE_PATH_STRING); + + Artifact jar = Iterables.getOnlyElement(runtimeJars.get("x/libproto_lib-lite.jar")); + JavaCompileAction action = (JavaCompileAction) getGeneratingAction(jar); + + List<String> commandLine = ImmutableList.copyOf(action.buildCommandLine()); + assertThat(commandLine).contains("-protoMarkerForTest"); + } + + /** + * Verify that a java_lite_proto_library exposes Skylark providers for the Java code it generates. + */ + @Test + public void testJavaProtosExposeSkylarkProviders() throws Exception { + scratch.file( + "proto/extensions.bzl", + "def _impl(ctx):", + " print (ctx.attr.dep[java_common.provider])", + "custom_rule = rule(", + " implementation=_impl,", + " attrs={", + " 'dep': attr.label()", + " },", + ")"); + scratch.file( + "proto/BUILD", + "load('/proto/extensions', 'custom_rule')", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "proto_library(", + " name = 'proto',", + " srcs = [ 'file.proto' ],", + ")", + "java_lite_proto_library(name = 'lite_pb2', deps = [':proto'])", + "custom_rule(name = 'custom', dep = ':lite_pb2')"); + update( + ImmutableList.of("//proto:custom"), + false /* keepGoing */, + 1 /* loadingPhaseThreads */, + true /* doAnalysis */, + new EventBus()); + // Implicitly check that `update()` above didn't throw an exception. This implicitly checks that + // ctx.attr.dep.java.{transitive_deps, outputs}, above, is defined. + } + + @Test + public void testProtoLibraryInterop() throws Exception { + scratch.file( + "proto/BUILD", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "proto_library(", + " name = 'proto',", + " srcs = [ 'file.proto' ],", + " java_api_version = 2,", + ")", + "java_lite_proto_library(name = 'lite_pb2', deps = [':proto'])"); + update( + ImmutableList.of("//proto:lite_pb2"), + false /* keepGoing */, + 1 /* loadingPhaseThreads */, + true /* doAnalysis */, + new EventBus()); + } + + /** + * Tests that a java_lite_proto_library only provides direct jars corresponding on the + * proto_library rules it directly depends on, excluding anything that the proto_library rules + * depends on themselves. This does not concern strict-deps in the compilation of the generated + * Java code itself, only compilation of regular code in java_library/java_binary and similar + * rules. + */ + @Test + public void jplCorrectlyDefinesDirectJars_strictDepsEnabled() throws Exception { + scratch.file( + "x/BUILD", + "load('//tools/build_rules/java_lite_proto_library:java_lite_proto_library.bzl',", + "'java_lite_proto_library')", + "java_lite_proto_library(name = 'foo_lite_pb2', deps = [':foo'], strict_deps = 1)", + "proto_library(", + " name = 'foo',", + " srcs = [ 'foo.proto' ],", + " deps = [ ':bar' ],", + ")", + "java_lite_proto_library(name = 'bar_lite_pb2', deps = [':bar'])", + "proto_library(", + " name = 'bar',", + " srcs = [ 'bar.proto' ],", + " deps = [ ':baz' ],", + ")", + "proto_library(", + " name = 'baz',", + " srcs = [ 'baz.proto' ],", + ")"); + + { + JavaCompilationArgsProvider compilationArgsProvider = + getJavaCompilationArgsProvider(getConfiguredTarget("//x:foo_lite_pb2")); + + Iterable<String> directJars = + prettyJarNames(compilationArgsProvider.getJavaCompilationArgs().getCompileTimeJars()); + + assertThat(directJars).containsExactly("x/libfoo-lite-hjar.jar"); + } + + { + JavaCompilationArgsProvider compilationArgsProvider = + getJavaCompilationArgsProvider(getConfiguredTarget("//x:bar_lite_pb2")); + + Iterable<String> directJars = + prettyJarNames(compilationArgsProvider.getJavaCompilationArgs().getCompileTimeJars()); + + assertThat(directJars).containsExactly("x/libbar-lite-hjar.jar"); + } + } + + private static JavaCompilationArgsProvider getJavaCompilationArgsProvider( + ConfiguredTarget target) { + SkylarkProviders skylarkProviders = target.getProvider(SkylarkProviders.class); + JavaProvider javaProvider = + (JavaProvider) skylarkProviders.getDeclaredProvider(JavaProvider.JAVA_PROVIDER.getKey()); + return javaProvider.getJavaCompilationArgsProvider(); + } +} |