diff --git a/rules/jvm/private/label.bzl b/rules/jvm/private/label.bzl index 0771f450..e8adb1d7 100644 --- a/rules/jvm/private/label.bzl +++ b/rules/jvm/private/label.bzl @@ -5,23 +5,27 @@ load( _LabeledJarsData = "LabeledJarsData", ) +def get_labeled_jars(label, java_info, deps): + deps_labeled_jars = [dep[_LabeledJars] for dep in deps if _LabeledJars in dep] + return _LabeledJars( + label = label, + values = depset( + [ + _LabeledJarsData( + label = label, + jars = depset(transitive = [java_info.compile_jars, java_info.full_compile_jars]), + ), + ], + order = "preorder", + transitive = [labeled_jars.values for labeled_jars in deps_labeled_jars], + ), + ) + def labeled_jars_implementation(target, ctx): if JavaInfo not in target: return [] - deps_labeled_jars = [dep[_LabeledJars] for dep in getattr(ctx.rule.attr, "deps", []) if _LabeledJars in dep] - java_info = target[JavaInfo] - return [ - _LabeledJars( - values = depset( - [ - _LabeledJarsData( - label = ctx.label, - jars = depset(transitive = [java_info.compile_jars, java_info.full_compile_jars]), - ), - ], - order = "preorder", - transitive = [labeled_jars.values for labeled_jars in deps_labeled_jars], - ), - ), - ] + if _LabeledJars in target: + return [] + + return [get_labeled_jars(ctx.label, target[JavaInfo], getattr(ctx.rule.attr, "deps", []))] diff --git a/rules/private/phases.bzl b/rules/private/phases.bzl index 40d37820..e22ad408 100644 --- a/rules/private/phases.bzl +++ b/rules/private/phases.bzl @@ -7,6 +7,7 @@ load(":phases/phase_coda.bzl", _phase_coda = "phase_coda") load(":phases/phase_coverage_jacoco.bzl", _phase_coverage_jacoco = "phase_coverage_jacoco") load(":phases/phase_ijinfo.bzl", _phase_ijinfo = "phase_ijinfo") load(":phases/phase_javainfo.bzl", _phase_javainfo = "phase_javainfo") +load(":phases/phase_labeledjars.bzl", _phase_labeledjars = "phase_labeledjars") load(":phases/phase_library_defaultinfo.bzl", _phase_library_defaultinfo = "phase_library_defaultinfo") load(":phases/phase_outputgroupinfo.bzl", _phase_outputgroupinfo = "phase_outputgroupinfo") load(":phases/phase_resources.bzl", _phase_resources = "phase_resources") @@ -37,6 +38,8 @@ phase_ijinfo = _phase_ijinfo phase_javainfo = _phase_javainfo +phase_labeledjars = _phase_labeledjars + phase_library_defaultinfo = _phase_library_defaultinfo phase_outputgroupinfo = _phase_outputgroupinfo diff --git a/rules/private/phases/phase_labeledjars.bzl b/rules/private/phases/phase_labeledjars.bzl new file mode 100644 index 00000000..f0c6c57e --- /dev/null +++ b/rules/private/phases/phase_labeledjars.bzl @@ -0,0 +1,12 @@ +load("//rules:providers.bzl", "LabeledJars") +load("//rules/jvm:private/label.bzl", "get_labeled_jars") + +# +# PHASE: labeledjars +# +# Outputs the `LabeledJars` provider if `deps_checker_label` is set. +# + +def phase_labeledjars(ctx, g): + if ctx.attr.deps_checker_label != "": + g.out.providers.append(get_labeled_jars(ctx.attr.deps_checker_label, g.javainfo.java_info, ctx.attr.deps)) diff --git a/rules/private/phases/phase_zinc_depscheck.bzl b/rules/private/phases/phase_zinc_depscheck.bzl index 5655da1e..494481d1 100644 --- a/rules/private/phases/phase_zinc_depscheck.bzl +++ b/rules/private/phases/phase_zinc_depscheck.bzl @@ -25,7 +25,16 @@ def phase_zinc_depscheck(ctx, g): deps_check = ctx.actions.declare_file("{}/depscheck_{}.success".format(ctx.label.name, name)) deps_args = ctx.actions.args() deps_args.add(name, format = "--check_%s=true") - deps_args.add_all("--direct", [dep.label for dep in ctx.attr.deps], format_each = "_%s") + + direct_dependency_labels = [] + + for dependency in ctx.attr.deps: + if _LabeledJars in dependency: + direct_dependency_labels.append(dependency[_LabeledJars].label) + else: + direct_dependency_labels.append(dependency.label) + + deps_args.add_all("--direct", direct_dependency_labels, format_each = "_%s") # Check the comment on the function we're calling here to understand why # we're not using map_each diff --git a/rules/providers.bzl b/rules/providers.bzl index 80b8e355..e6d00535 100644 --- a/rules/providers.bzl +++ b/rules/providers.bzl @@ -66,6 +66,7 @@ IntellijInfo = provider( LabeledJars = provider( doc = "Exported jars and their labels.", fields = { + "label": "The label of the target providing this provider.", "values": "The preorder depset of label and jars.", }, ) diff --git a/rules/scala.bzl b/rules/scala.bzl index bebb524c..ee082a10 100644 --- a/rules/scala.bzl +++ b/rules/scala.bzl @@ -19,6 +19,7 @@ load( _phase_coverage_jacoco = "phase_coverage_jacoco", _phase_ijinfo = "phase_ijinfo", _phase_javainfo = "phase_javainfo", + _phase_labeledjars = "phase_labeledjars", _phase_library_defaultinfo = "phase_library_defaultinfo", _phase_outputgroupinfo = "phase_outputgroupinfo", _phase_resources = "phase_resources", @@ -75,7 +76,19 @@ _compile_private_attributes = { ), } -_compile_attributes = { +_deps_checker_label_attributes = { + "deps_checker_label": attr.string( + doc = """\ +The label to identify this target in the output of the dependency checker. + +By default, this is just the label of the target. But sometimes—for example, when overriding an artifact with +`rules_jvm_external` to point to your own, or defining an alias to target—you want the dependency checker to suggest +you add or remove a different label as a dependency. In that case, you can set this attribute to that label. +""", + ), +} + +_compile_attributes = _deps_checker_label_attributes | { "srcs": attr.label_list( cfg = _scala_outgoing_transition, doc = "The source Scala and Java files (and `-sources.jar` `.srcjar` `-src.jar` files of those).", @@ -213,6 +226,7 @@ def _scala_library_implementation(ctx): ("resources", _phase_resources), ("classpaths", _phase_classpaths), ("javainfo", _phase_javainfo), + ("labeledjars", _phase_labeledjars), ("semanticdb", _phase_semanticdb), ("singlejar", _phase_singlejar), ("coverage", _phase_coverage_jacoco), @@ -227,6 +241,7 @@ def _scala_binary_implementation(ctx): ("resources", _phase_resources), ("classpaths", _phase_classpaths), ("javainfo", _phase_javainfo), + ("labeledjars", _phase_labeledjars), ("semanticdb", _phase_semanticdb), ("singlejar", _phase_singlejar), ("coverage", _phase_coverage_jacoco), @@ -242,6 +257,7 @@ def _scala_test_implementation(ctx): ("resources", _phase_resources), ("classpaths", _phase_classpaths), ("javainfo", _phase_javainfo), + ("labeledjars", _phase_labeledjars), ("semanticdb", _phase_semanticdb), ("singlejar", _phase_singlejar), ("coverage", _phase_coverage_jacoco), @@ -458,6 +474,7 @@ To run: `bazel run ` scala_import = rule( attrs = _dicts.add( _scala_import_private_attributes, + _deps_checker_label_attributes, { "deps": attr.label_list( doc = "Libraries used by this one.", diff --git a/rules/scala/private/import.bzl b/rules/scala/private/import.bzl index d5d857da..98cda76b 100644 --- a/rules/scala/private/import.bzl +++ b/rules/scala/private/import.bzl @@ -6,6 +6,7 @@ load( "//rules/common:private/utils.bzl", _separate_src_jars_srcs_and_other = "separate_src_jars_srcs_and_other", ) +load("//rules/jvm:private/label.bzl", "get_labeled_jars") scala_import_private_attributes = { "_java_toolchain": attr.label( @@ -14,10 +15,6 @@ scala_import_private_attributes = { } def scala_import_implementation(ctx): - default_info = DefaultInfo( - files = depset(ctx.files.jars + ctx.files.srcjar), - ) - if ctx.files.jars: _src_jar, _, _jar = _separate_src_jars_srcs_and_other(ctx.files.jars) _src_jar += ctx.files.srcjar @@ -66,9 +63,12 @@ def scala_import_implementation(ctx): else: java_info = java_common.merge([dep[JavaInfo] for dep in ctx.attr.deps]) - intellij_info = create_intellij_info(ctx.label, ctx.attr.deps, java_info) + providers = [java_info, create_intellij_info(ctx.label, ctx.attr.deps, java_info)] + + if ctx.attr.deps_checker_label != "": + providers.append(get_labeled_jars(ctx.attr.deps_checker_label, java_info, ctx.attr.deps)) - return [intellij_info, java_info] + return providers def create_intellij_info(label, deps, java_info): # note: tried using transitive_exports from a JavaInfo that was given non-empty exports, but it was always empty diff --git a/tests/dependencies/deps_checker_label/BUILD b/tests/dependencies/deps_checker_label/BUILD new file mode 100644 index 00000000..29a52920 --- /dev/null +++ b/tests/dependencies/deps_checker_label/BUILD @@ -0,0 +1,40 @@ +load("@rules_scala_annex//rules:scala.bzl", "scala_import", "scala_library") + +scala_library( + name = "library", + srcs = [], + deps_checker_label = "//dependencies/deps_checker_label:library-alias", + scala_toolchain_name = "test_zinc_2_13", +) + +alias( + name = "library-alias", + actual = ":library", +) + +scala_library( + name = "depends-on-library-alias", + srcs = [], + scala_toolchain_name = "test_zinc_2_13", + tags = ["manual"], + deps = [":library-alias"], +) + +scala_import( + name = "import", + deps_checker_label = "//dependencies/deps_checker_label:import-alias", + jars = [], +) + +alias( + name = "import-alias", + actual = ":import", +) + +scala_library( + name = "depends-on-import-alias", + srcs = [], + scala_toolchain_name = "test_zinc_2_13", + tags = ["manual"], + deps = [":import-alias"], +) diff --git a/tests/dependencies/deps_checker_label/test b/tests/dependencies/deps_checker_label/test new file mode 100755 index 00000000..556a77ae --- /dev/null +++ b/tests/dependencies/deps_checker_label/test @@ -0,0 +1,8 @@ +#!/bin/bash -e +. "$(dirname "$0")"/../../common.sh + +! bazel build :depends-on-library-alias || false +bazel build :depends-on-library-alias |& grep "buildozer 'remove deps //dependencies/deps_checker_label:library-alias' //dependencies/deps_checker_label:depends-on-library-alias" + +! bazel build :depends-on-import-alias || false +bazel build :depends-on-import-alias |& grep "buildozer 'remove deps //dependencies/deps_checker_label:import-alias' //dependencies/deps_checker_label:depends-on-import-alias"