From 26ec43dffac4a501bbce49a3d3370b13dcce3672 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 25 Oct 2022 08:17:12 -0700 Subject: [PATCH] Starlarkify java_import Rewrite native java_import into Starlark. PiperOrigin-RevId: 483678662 Change-Id: Ie3f914780fcb508338186455b5a8756f24374239 --- .../lib/rules/java/JavaConfiguration.java | 20 +- .../lib/rules/java/JavaToolchainProvider.java | 15 +- .../java/JavaConfigurationApi.java | 12 + .../JavaToolchainStarlarkApiProviderApi.java | 8 + .../starlark/builtins_bzl/bazel/exports.bzl | 2 + .../common/java/import_deps_check.bzl | 80 ++++++ .../builtins_bzl/common/java/java_import.bzl | 263 ++++++++++++++++++ .../lib/rules/java/JavaStarlarkApiTest.java | 42 +++ .../java/JavaImportConfiguredTargetTest.java | 13 + .../integration/java_integration_test.sh | 29 ++ 10 files changed, 478 insertions(+), 6 deletions(-) create mode 100644 src/main/starlark/builtins_bzl/common/java/import_deps_check.bzl create mode 100644 src/main/starlark/builtins_bzl/common/java/java_import.bzl diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java index 1013dc698cd6f0..87c973f941c280 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java @@ -235,6 +235,16 @@ public boolean getUseIjars() { return useIjars; } + /** + * Returns true iff Java compilation should use ijars. Checks if the functions is been called from + * builtins. + */ + @Override + public boolean getUseIjarsInStarlark(StarlarkThread thread) throws EvalException { + checkPrivateAccess(thread); + return useIjars; + } + /** Returns true iff Java header compilation is enabled. */ public boolean useHeaderCompilation() { return useHeaderCompilation; @@ -278,7 +288,7 @@ public String getFixDepsTool() { return fixDepsTool; } - /** @return proper label only if --java_launcher= is specified, otherwise null. */ + /** Returns proper label only if --java_launcher= is specified, otherwise null. */ @StarlarkConfigurationField( name = "launcher", doc = "Returns the label provided with --java_launcher, if any.", @@ -397,6 +407,14 @@ public boolean getDisallowJavaImportEmptyJarsInStarlark(StarlarkThread thread) return disallowJavaImportEmptyJars; } + /** Returns true if java_import exports are not allowed. */ + @Override + public boolean getDisallowJavaImportExportsInStarlark(StarlarkThread thread) + throws EvalException { + checkPrivateAccess(thread); + return disallowJavaImportExports; + } + @Override public String starlarkOneVersionEnforcementLevel() { return oneVersionEnforcementLevel().name(); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java index ec0e4f3d9054d7..416c97cecb9d80 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java @@ -267,7 +267,7 @@ public Label getToolchainLabel() { return label; } - /** @return the target Java bootclasspath */ + /** Returns the target Java bootclasspath. */ public BootClassPathInfo getBootclasspath() { return bootclasspath; } @@ -325,7 +325,6 @@ public ImmutableSet getReducedClasspathIncompatibleProcessors() { return reducedClasspathIncompatibleProcessors; } - /** * Returns {@code true} if header compilation should be forcibly disabled, overriding * --java_header_compilation. @@ -374,6 +373,12 @@ public Artifact depsChecker() { return depsChecker; } + @Override + public Artifact getDepsCheckerForStarlark(StarlarkThread thread) throws EvalException { + checkPrivateAccess(thread); + return depsChecker(); + } + @Nullable public Artifact getResourceJarBuilder() { return resourceJarBuilder; @@ -397,12 +402,12 @@ ImmutableListMultimap getCompatibleJavacOptions() { return compatibleJavacOptions; } - /** @return the map of target environment-specific javacopts. */ + /** Returns the map of target environment-specific javacopts. */ public ImmutableList getCompatibleJavacOptions(String key) { return getCompatibleJavacOptions().get(key); } - /** @return the list of default options for the java compiler */ + /** Returns the list of default options for the java compiler. */ public ImmutableList getJavacOptions(RuleContext ruleContext) { ImmutableList.Builder result = ImmutableList.builder().addAll(javacOptions); if (ruleContext != null) { @@ -421,7 +426,7 @@ public NestedSet getJvmOptions() { return jvmOptions; } - /** @return whether JavaBuilders supports running as a persistent worker or not */ + /** Returns whether JavaBuilders supports running as a persistent worker or not. */ public boolean getJavacSupportsWorkers() { return javacSupportsWorkers; } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java index 54b7a7c13cfaad..da583f1b5819b9 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java @@ -79,4 +79,16 @@ public interface JavaConfigurationApi extends StarlarkValue { doc = "Returns true if empty java_import jars are not allowed.", useStarlarkThread = true) boolean getDisallowJavaImportEmptyJarsInStarlark(StarlarkThread thread) throws EvalException; + + @StarlarkMethod( + name = "use_ijars", + doc = "Returns true iff Java compilation should use ijars.", + useStarlarkThread = true) + boolean getUseIjarsInStarlark(StarlarkThread thread) throws EvalException; + + @StarlarkMethod( + name = "disallow_java_import_exports", + doc = "Returns true if java_import exports are not allowed.", + useStarlarkThread = true) + boolean getDisallowJavaImportExportsInStarlark(StarlarkThread thread) throws EvalException; } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java index bfe776a7188ca8..45c129bd0a69a8 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java @@ -126,4 +126,12 @@ public interface JavaToolchainStarlarkApiProviderApi extends StructApi { @Nullable ImmutableList getCompatibleJavacOptionsForStarlark(String key, StarlarkThread thread) throws EvalException; + + @Nullable + @StarlarkMethod( + name = "deps_checker", + documented = false, + useStarlarkThread = true, + allowReturnNones = true) + FileApi getDepsCheckerForStarlark(StarlarkThread thread) throws EvalException; } diff --git a/src/main/starlark/builtins_bzl/bazel/exports.bzl b/src/main/starlark/builtins_bzl/bazel/exports.bzl index f4bd5dc1ff9844..0736d74dc91687 100644 --- a/src/main/starlark/builtins_bzl/bazel/exports.bzl +++ b/src/main/starlark/builtins_bzl/bazel/exports.bzl @@ -16,6 +16,7 @@ load("@_builtins//:common/java/java_library.bzl", "java_library") load("@_builtins//:common/java/java_plugin.bzl", "java_plugin") +load("@_builtins//:common/java/java_import.bzl", "java_import") load("@_builtins//:common/java/proto/java_proto_library.bzl", "java_proto_library") load("@_builtins//:common/cc/cc_proto_library.bzl", "cc_proto_library") @@ -23,6 +24,7 @@ exported_toplevels = {} exported_rules = { "java_library": java_library, "java_plugin": java_plugin, + "-java_import": java_import, "java_proto_library": java_proto_library, "+cc_proto_library": cc_proto_library, } diff --git a/src/main/starlark/builtins_bzl/common/java/import_deps_check.bzl b/src/main/starlark/builtins_bzl/common/java/import_deps_check.bzl new file mode 100644 index 00000000000000..614f1365e5a5b9 --- /dev/null +++ b/src/main/starlark/builtins_bzl/common/java/import_deps_check.bzl @@ -0,0 +1,80 @@ +# Copyright 2022 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. + +"""Creates the import deps checker for java rules""" + +load(":common/java/java_semantics.bzl", "semantics") + +java_common = _builtins.toplevel.java_common + +def import_deps_check( + ctx, + jars_to_check, + declared_deps, + transitive_deps, + rule_class): + """ + Creates actions that checks import deps for java rules. + + Args: + ctx: (RuleContext) Used to register the actions. + jars_to_check: (list[File]) A list of jars files to check. + declared_deps: (list[File]) A list of direct dependencies. + transitive_deps: (list[File]) A list of transitive dependencies. + rule_class: (String) Rule class. + + Returns: + (File) Output file of the created action. + """ + java_toolchain = semantics.find_java_toolchain(ctx) + deps_checker = java_toolchain.deps_checker() + if deps_checker == None: + return None + + jdeps_output = ctx.actions.declare_file("_%s/%s/jdeps.proto" % (rule_class, ctx.label.name)) + + args = ctx.actions.args() + args.add("-jar", deps_checker) + args.add_all(jars_to_check, before_each = "--input") + args.add_all(declared_deps, before_each = "--directdep") + args.add_all( + depset(order = "preorder", transitive = [declared_deps, transitive_deps]), + before_each = "--classpath_entry", + ) + args.add_all(java_toolchain.bootclasspath, before_each = "--bootclasspath_entry") + args.add("--checking_mode=error") + args.add("--jdeps_output", jdeps_output) + args.add("--rule_label", ctx.label) + + inputs = depset( + jars_to_check, + transitive = [ + declared_deps, + transitive_deps, + java_toolchain.bootclasspath, + ], + ) + tools = [deps_checker, java_toolchain.java_runtime.files] + + ctx.actions.run( + mnemonic = "ImportDepsChecker", + progress_message = "Checking the completeness of the deps for %s" % jars_to_check, + executable = java_toolchain.java_runtime.java_executable_exec_path, + arguments = [args], + inputs = inputs, + outputs = [jdeps_output], + tools = tools, + ) + + return jdeps_output diff --git a/src/main/starlark/builtins_bzl/common/java/java_import.bzl b/src/main/starlark/builtins_bzl/common/java/java_import.bzl new file mode 100644 index 00000000000000..344fa2cabc5763 --- /dev/null +++ b/src/main/starlark/builtins_bzl/common/java/java_import.bzl @@ -0,0 +1,263 @@ +# Copyright 2021 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. + +""" +Definition of java_import rule. +""" + +load(":common/java/java_common.bzl", "construct_defaultinfo") +load(":common/java/java_semantics.bzl", "semantics") +load(":common/java/proguard_validation.bzl", "VALIDATE_PROGUARD_SPECS_IMPLICIT_ATTRS", "validate_proguard_specs") +load(":common/rule_util.bzl", "merge_attrs") +load(":common/java/java_util.bzl", "create_single_jar") +load(":common/java/import_deps_check.bzl", "import_deps_check") + +JavaInfo = _builtins.toplevel.JavaInfo +CcInfo = _builtins.toplevel.CcInfo +java_common = _builtins.toplevel.java_common + +def _filter_provider(provider, *attrs): + return [dep[provider] for attr in attrs for dep in attr if provider in dep] + +def _collect_jars(ctx, jars): + jars_dict = {} + for info in jars: + if JavaInfo in info: + fail("//" + ctx.label.package + ":" + ctx.attr.name + ": should not refer to Java rules") + for jar in info.files.to_list(): + jar_path = jar.dirname + jar.basename + if jars_dict.get(jar_path) != None: + fail("in jars attribute of java_import rule //" + ctx.label.package + ":" + ctx.attr.name + ": " + jar.basename + " is a duplicate") + jars_dict[jar_path] = jar + return [jar_tuple[1] for jar_tuple in jars_dict.items()] if len(jars_dict.items()) > 0 else [] + +def _process_with_ijars_if_needed(jars, ctx): + file_dict = {} + use_ijars = ctx.fragments.java.use_ijars() + for jar in jars: + interface_jar = jar + if use_ijars: + ijar_basename = jar.short_path.removesuffix("." + jar.extension) + "-ijar.jar" + interface_jar_directory = "_ijar/" + ctx.label.name + "/" + ijar_basename + + interface_jar = ctx.actions.declare_file(interface_jar_directory) + create_single_jar( + ctx, + interface_jar, + depset([jar]), + ) + file_dict[jar] = interface_jar + + return file_dict + +def _check_export_error(ctx, exports): + if len(exports) != 0 and (ctx.fragments.java.disallow_java_import_exports() or + (hasattr(ctx.attr, "_allowlist_java_import_exports") and not getattr(ctx.attr, "_allowlist_java_import_exports").isAvailableFor(ctx.label))): + fail("java_import.exports is no longer supported; use java_import.deps instead") + +def _check_empty_jars_error(ctx, jars): + # TODO(kotlaja): Remove temporary incompatible flag [disallow_java_import_empty_jars] once migration is done. + if len(jars) == 0 and ctx.fragments.java.disallow_java_import_empty_jars() and hasattr(ctx.attr, "_allowlist_java_import_empty_jars") and not getattr(ctx.attr, "_allowlist_java_import_empty_jars").isAvailableFor(ctx.label): + fail("empty java_import.jars is no longer supported " + ctx.label.package) + +def _create_java_info_with_dummy_output_file(ctx, srcjar, deps, exports, runtime_deps_list, neverlink): + dummy_jar = ctx.actions.declare_file(ctx.label.name + "_dummy.jar") + dummy_src_jar = srcjar + if dummy_src_jar == None: + dummy_src_jar = ctx.actions.declare_file(ctx.label.name + "_src_dummy.java") + ctx.actions.write(dummy_src_jar, "") + return java_common.compile( + ctx, + output = dummy_jar, + java_toolchain = semantics.find_java_toolchain(ctx), + source_files = [dummy_src_jar], + deps = [target[JavaInfo] for target in [exports + deps] if JavaInfo in target], + runtime_deps = runtime_deps_list, + neverlink = neverlink, + exports = [export[JavaInfo] for export in exports if JavaInfo in export], # Watchout, maybe you need to add them there manually. + ) + +def bazel_java_import_rule( + ctx, + jars = [], + srcjar = None, + deps = [], + runtime_deps = [], + exports = [], + neverlink = False, + constraints = [], + proguard_specs = []): + """Implements java_import. + + This rule allows the use of precompiled .jar files as libraries in other Java rules. + + Args: + ctx: (RuleContext) Used to register the actions. + jars: (list[Artifact]) List of output jars. + srcjar: (Artifact) The jar containing the sources. + deps: (list[Target]) The list of dependent libraries. + runtime_deps: (list[Target]) Runtime dependencies to attach to the rule. + exports: (list[Target]) The list of exported libraries. + neverlink: (bool) Whether this rule should only be used for compilation and not at runtime. + constraints: (list[String]) Rule constraints. + proguard_specs: (list[File]) Files to be used as Proguard specification. + + Returns: + (list[provider]) A list containing DefaultInfo, JavaInfo, + OutputGroupsInfo, ProguardSpecProvider providers. + """ + + _check_empty_jars_error(ctx, jars) + _check_export_error(ctx, exports) + + collected_jars = _collect_jars(ctx, jars) + all_deps = _filter_provider(JavaInfo, deps, exports) + + jdeps_artifact = None + merged_java_info = java_common.merge(all_deps) + if len(collected_jars) > 0 and hasattr(ctx.attr, "_allowlist_java_import_deps_checking") and not ctx.attr._allowlist_java_import_deps_checking.isAvailableFor(ctx.label) and "incomplete-deps" not in ctx.attr.tags: + jdeps_artifact = import_deps_check( + ctx, + collected_jars, + merged_java_info.compile_jars, + merged_java_info.transitive_compile_time_jars, + "java_import", + ) + + compilation_to_runtime_jar_map = _process_with_ijars_if_needed(collected_jars, ctx) + runtime_deps_list = [runtime_dep[JavaInfo] for runtime_dep in runtime_deps if JavaInfo in runtime_dep] + java_info = None + if len(collected_jars) > 0: + java_infos = [] + for jar in collected_jars: + java_infos.append(JavaInfo( + output_jar = jar, + compile_jar = compilation_to_runtime_jar_map[jar], + deps = all_deps, + runtime_deps = runtime_deps_list, + neverlink = neverlink, + source_jar = srcjar, + exports = [export[JavaInfo] for export in exports if JavaInfo in export], # Watchout, maybe you need to add them there manually. + )) + java_info = java_common.merge(java_infos) + else: + # TODO(kotlaja): Remove next line once all java_import targets with empty jars attribute are cleaned from depot (b/246559727). + java_info = _create_java_info_with_dummy_output_file(ctx, srcjar, deps, exports, runtime_deps_list, neverlink) + + if len(constraints): + java_info = semantics.add_constraints(java_info, constraints) + + target = {"JavaInfo": java_info} + + target["ProguardSpecProvider"] = validate_proguard_specs( + ctx, + proguard_specs, + [deps, runtime_deps, exports], + ) + + # TODO(kotlaja): Revise if collected_runtimes can be added into construct_defaultinfo directly. + collected_runtimes = [] + for runtime_dep in ctx.attr.runtime_deps: + collected_runtimes.extend(runtime_dep.files.to_list()) + + target["DefaultInfo"] = construct_defaultinfo( + ctx, + collected_jars, + collected_jars + collected_runtimes, + neverlink, + exports, + ) + + output_group_src_jars = depset() if srcjar == None else depset([srcjar]) + target["OutputGroupInfo"] = OutputGroupInfo( + **{ + "_source_jars": output_group_src_jars, + "_direct_source_jars": output_group_src_jars, + "_validation": depset() if jdeps_artifact == None else depset([jdeps_artifact]), + "_hidden_top_level_INTERNAL_": target["ProguardSpecProvider"].specs, + } + ) + return target + +def _proxy(ctx): + return bazel_java_import_rule( + ctx, + ctx.attr.jars, + ctx.file.srcjar, + ctx.attr.deps, + ctx.attr.runtime_deps, + ctx.attr.exports, + ctx.attr.neverlink, + ctx.attr.constraints, + ctx.files.proguard_specs, + ).values() + +_ALLOWED_RULES_IN_DEPS_FOR_JAVA_IMPORT = [ + "java_library", + "java_import", + "cc_library", + "cc_binary", +] + +JAVA_IMPORT_ATTRS = merge_attrs( + VALIDATE_PROGUARD_SPECS_IMPLICIT_ATTRS, + { + "data": attr.label_list( + allow_files = True, + flags = ["SKIP_CONSTRAINTS_OVERRIDE"], + ), + "deps": attr.label_list( + providers = [JavaInfo], + allow_rules = _ALLOWED_RULES_IN_DEPS_FOR_JAVA_IMPORT, + ), + "exports": attr.label_list( + providers = [JavaInfo], + allow_rules = _ALLOWED_RULES_IN_DEPS_FOR_JAVA_IMPORT, + ), + "runtime_deps": attr.label_list( + allow_files = [".jar"], + allow_rules = _ALLOWED_RULES_IN_DEPS_FOR_JAVA_IMPORT, + providers = [[CcInfo], [JavaInfo]], + flags = ["SKIP_ANALYSIS_TIME_FILETYPE_CHECK"], + ), + # JavaImportBazeRule attr + "jars": attr.label_list( + allow_files = [".jar"], + mandatory = True, + ), + "srcjar": attr.label( + allow_single_file = [".srcjar", ".jar"], + flags = ["DIRECT_COMPILE_TIME_INPUT"], + ), + "neverlink": attr.bool( + default = False, + ), + "constraints": attr.string_list(), + # ProguardLibraryRule attr + "proguard_specs": attr.label_list( + allow_files = True, + ), + # Additional attrs + "licenses": attr.string_list(), + "_java_toolchain_type": attr.label(default = semantics.JAVA_TOOLCHAIN_TYPE), + }, +) + +java_import = rule( + _proxy, + attrs = JAVA_IMPORT_ATTRS, + provides = [JavaInfo], + fragments = ["java", "cpp"], + toolchains = [semantics.JAVA_TOOLCHAIN], +) diff --git a/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java b/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java index bb270a2aa0b196..9c3b76d22c8848 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/java/JavaStarlarkApiTest.java @@ -2563,6 +2563,48 @@ public void strictJavaDepsFlagExposed_error() throws Exception { assertThat(((String) info.getValue("strict_java_deps"))).isEqualTo("error"); } + @Test + public void useIjars_fails() throws Exception { + setBuildLanguageOptions("--experimental_builtins_injection_override=+java_import"); + scratch.file( + "foo/rule.bzl", + "result = provider()", + "def _impl(ctx):", + " ctx.fragments.java.use_ijars()", + " return []", + "myrule = rule(", + " implementation=_impl,", + " fragments = ['java']", + ")"); + scratch.file("foo/BUILD", "load(':rule.bzl', 'myrule')", "myrule(name='myrule')"); + reporter.removeHandler(failFastHandler); + + getConfiguredTarget("//foo:myrule"); + + assertContainsEvent("Rule in 'foo' cannot use private API"); + } + + @Test + public void disallowJavaImportExports_fails() throws Exception { + setBuildLanguageOptions("--experimental_builtins_injection_override=+java_import"); + scratch.file( + "foo/rule.bzl", + "result = provider()", + "def _impl(ctx):", + " ctx.fragments.java.disallow_java_import_exports()", + " return []", + "myrule = rule(", + " implementation=_impl,", + " fragments = ['java']", + ")"); + scratch.file("foo/BUILD", "load(':rule.bzl', 'myrule')", "myrule(name='myrule')"); + reporter.removeHandler(failFastHandler); + + getConfiguredTarget("//foo:myrule"); + + assertContainsEvent("Rule in 'foo' cannot use private API"); + } + @Test public void mergeRuntimeOutputJarsTest() throws Exception { scratch.file( diff --git a/src/test/java/com/google/devtools/build/lib/view/java/JavaImportConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/view/java/JavaImportConfiguredTargetTest.java index 5d38681f4d64d9..63415d3d3800da 100644 --- a/src/test/java/com/google/devtools/build/lib/view/java/JavaImportConfiguredTargetTest.java +++ b/src/test/java/com/google/devtools/build/lib/view/java/JavaImportConfiguredTargetTest.java @@ -50,6 +50,11 @@ @RunWith(JUnit4.class) public class JavaImportConfiguredTargetTest extends BuildViewTestCase { + @Before + public void setCommandLineFlags() throws Exception { + setBuildLanguageOptions("--experimental_google_legacy_api"); + } + @Before public final void writeBuildFile() throws Exception { scratch.file( @@ -66,6 +71,12 @@ public final void writeBuildFile() throws Exception { " name = 'java_import_exports',", " packages = ['//...'],", ")"); + scratch.overwriteFile( + "tools/allowlists/java_import_empty_jars/BUILD", + "package_group(", + " name = 'java_import_empty_jars',", + " packages = [],", + ")"); } @Test @@ -259,7 +270,9 @@ public void testRequiresJars() throws Exception { @Test public void testPermitsEmptyJars() throws Exception { + useConfiguration("--incompatible_disallow_java_import_empty_jars=0"); scratchConfiguredTarget("pkg", "rule", "java_import(name = 'rule', jars = [])"); + assertNoEvents(); } @Test diff --git a/src/test/shell/integration/java_integration_test.sh b/src/test/shell/integration/java_integration_test.sh index 64c79668216a02..6bf01aa113a83d 100755 --- a/src/test/shell/integration/java_integration_test.sh +++ b/src/test/shell/integration/java_integration_test.sh @@ -818,6 +818,35 @@ EOF expect_log "symbol not found missing.NoSuch" } +function test_java_import_with_empty_jars_attribute() { + local -r pkg="${FUNCNAME[0]}" + mkdir -p $pkg/java/hello/ || fail "Expected success" + cat > $pkg/java/hello/Hello.java < $pkg/java/hello/BUILD <& "$TEST_log" \ + || fail "Expected success" + bazel run //$pkg/java/hello:hello -- --singlejar >& "$TEST_log" + expect_log "Hello World!" +} + function test_arg_compile_action() { local package="${FUNCNAME[0]}" mkdir -p "${package}"