Skip to content

Commit 7bab259

Browse files
author
Jaden Peterson
committed
Use an outgoing transition to ensure Scala targets' dependencies are built once
1 parent 561a75d commit 7bab259

File tree

13 files changed

+153
-29
lines changed

13 files changed

+153
-29
lines changed

rules/common/private/utils.bzl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ def write_launcher(
6565
# runfiles_enabled = ctx.configuration.runfiles_enabled()
6666
runfiles_enabled = False
6767

68-
java_runtime_info = ctx.attr._target_jdk[java_common.JavaRuntimeInfo]
68+
# See https://bazel.build/extending/config#accessing-attributes-with-transitions:
69+
# "When attaching a transition to an outgoing edge (regardless of whether the transition is a
70+
# 1:1 or 1:2+ transition), `ctx.attr` is forced to be a list if it isn't already. The order of
71+
# elements in this list is unspecified."
72+
java_runtime_info = ctx.attr._target_jdk[0][java_common.JavaRuntimeInfo]
6973
java_executable = java_runtime_info.java_executable_runfiles_path
7074
if not paths.is_absolute(java_executable):
7175
java_executable = workspace_name + "/" + java_executable

rules/private/phases/phase_binary_launcher.bzl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ def phase_binary_launcher(ctx, g):
3535
files = inputs + files,
3636
transitive_files = depset(
3737
order = "default",
38-
transitive = [ctx.attr._target_jdk[java_common.JavaRuntimeInfo].files, g.javainfo.java_info.transitive_runtime_jars],
38+
39+
# See https://bazel.build/extending/config#accessing-attributes-with-transitions:
40+
# "When attaching a transition to an outgoing edge (regardless of whether the
41+
# transition is a 1:1 or 1:2+ transition), `ctx.attr` is forced to be a list if it
42+
# isn't already. The order of elements in this list is unspecified."
43+
transitive = [ctx.attr._target_jdk[0][java_common.JavaRuntimeInfo].files, g.javainfo.java_info.transitive_runtime_jars],
3944
),
4045
collect_default = True,
4146
),

rules/private/phases/phase_javainfo.bzl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@rules_java//java/common:java_common.bzl", "java_common")
12
load("@rules_java//toolchains:toolchain_utils.bzl", "find_java_toolchain")
23
load(
34
"@rules_scala_annex//rules:providers.bzl",
@@ -29,7 +30,12 @@ def phase_javainfo(ctx, g):
2930
ctx.actions,
3031
jar = ctx.outputs.jar,
3132
target_label = ctx.label,
32-
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain),
33+
34+
# See https://bazel.build/extending/config#accessing-attributes-with-transitions:
35+
# "When attaching a transition to an outgoing edge (regardless of whether the
36+
# transition is a 1:1 or 1:2+ transition), `ctx.attr` is forced to be a list if it
37+
# isn't already. The order of elements in this list is unspecified."
38+
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain[0]),
3339
)
3440

3541
source_jar_name = ctx.outputs.jar.basename.replace(".jar", "-src.jar")
@@ -42,7 +48,7 @@ def phase_javainfo(ctx, g):
4248
ctx.actions,
4349
output_source_jar = output_source_jar,
4450
sources = ctx.files.srcs,
45-
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain),
51+
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain[0]),
4652
)
4753

4854
java_info = JavaInfo(

rules/private/phases/phase_test_launcher.bzl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ load("//rules/common:private/utils.bzl", _collect = "collect", _write_launcher =
1111
#
1212

1313
def phase_test_launcher(ctx, g):
14-
files = ctx.attr._target_jdk[java_common.JavaRuntimeInfo].files.to_list() + [g.compile.zinc_info.analysis_store]
14+
# See https://bazel.build/extending/config#accessing-attributes-with-transitions:
15+
# "When attaching a transition to an outgoing edge (regardless of whether the transition is a
16+
# 1:1 or 1:2+ transition), `ctx.attr` is forced to be a list if it isn't already. The order of
17+
# elements in this list is unspecified."
18+
files = ctx.attr._target_jdk[0][java_common.JavaRuntimeInfo].files.to_list() + [g.compile.zinc_info.analysis_store]
1519

1620
coverage_replacements = {}
1721
coverage_runner_jars = depset(direct = [])
@@ -26,7 +30,7 @@ def phase_test_launcher(ctx, g):
2630
coverage_replacements[jar] if jar in coverage_replacements else jar
2731
for jar in g.javainfo.java_info.transitive_runtime_jars.to_list()
2832
])
29-
runner_jars = depset(transitive = [ctx.attr.runner[JavaInfo].transitive_runtime_jars, coverage_runner_jars])
33+
runner_jars = depset(transitive = [ctx.attr.runner[0][JavaInfo].transitive_runtime_jars, coverage_runner_jars])
3034
all_jars = [test_jars, runner_jars]
3135

3236
args = ctx.actions.args()
@@ -38,7 +42,7 @@ def phase_test_launcher(ctx, g):
3842
args.add_all("--shared_classpath", shared_deps.transitive_runtime_jars, map_each = _test_launcher_short_path)
3943
elif ctx.attr.isolation == "process":
4044
subprocess_executable = ctx.actions.declare_file("{}/subprocess".format(ctx.label.name))
41-
subprocess_runner_jars = ctx.attr.subprocess_runner[JavaInfo].transitive_runtime_jars
45+
subprocess_runner_jars = ctx.attr.subprocess_runner[0][JavaInfo].transitive_runtime_jars
4246
all_jars.append(subprocess_runner_jars)
4347
files += _write_launcher(
4448
ctx,

rules/private/phases/phase_zinc_compile.bzl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ def phase_zinc_compile(ctx, g):
2727
javacopts = [
2828
ctx.expand_location(option, ctx.attr.data)
2929
for option in ctx.attr.javacopts + java_common.default_javac_opts(
30-
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain),
30+
# See https://bazel.build/extending/config#accessing-attributes-with-transitions:
31+
# "When attaching a transition to an outgoing edge (regardless of whether the transition
32+
# is a 1:1 or 1:2+ transition), `ctx.attr` is forced to be a list if it isn't already.
33+
# The order of elements in this list is unspecified."
34+
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain[0]),
3135
)
3236
]
3337

rules/register_toolchain.bzl

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@rules_scala_annex_scala_toolchain//:default.bzl", "default_scala_toolchain_name")
12
load(
23
"//rules:providers.bzl",
34
"CodeCoverageConfiguration",
@@ -206,21 +207,32 @@ def _make_register_toolchain(configuration_rule):
206207
register_bootstrap_toolchain = _make_register_toolchain(_bootstrap_configuration)
207208
register_zinc_toolchain = _make_register_toolchain(_zinc_configuration)
208209

209-
def _scala_toolchain_transition_impl(_, attr):
210+
def _scala_toolchain_incoming_transition_impl(settings, attr):
210211
if attr.scala_toolchain_name == "":
211212
return {}
212213

213214
return {
214215
"@rules_scala_annex_scala_toolchain//:scala-toolchain": attr.scala_toolchain_name,
215216
}
216217

217-
scala_toolchain_transition = transition(
218-
implementation = _scala_toolchain_transition_impl,
218+
scala_toolchain_incoming_transition = transition(
219+
implementation = _scala_toolchain_incoming_transition_impl,
220+
inputs = ["@rules_scala_annex_scala_toolchain//:scala-toolchain"],
221+
outputs = ["@rules_scala_annex_scala_toolchain//:scala-toolchain"],
222+
)
223+
224+
def _scala_toolchain_outgoing_transition_impl(_1, _2):
225+
return {
226+
"@rules_scala_annex_scala_toolchain//:scala-toolchain": default_scala_toolchain_name,
227+
}
228+
229+
scala_toolchain_outgoing_transition = transition(
230+
implementation = _scala_toolchain_outgoing_transition_impl,
219231
inputs = [],
220232
outputs = ["@rules_scala_annex_scala_toolchain//:scala-toolchain"],
221233
)
222234

223-
scala_toolchain_transition_attributes = {
235+
scala_toolchain_attributes = {
224236
"scala_toolchain_name": attr.string(
225237
doc = "The name of the Scala toolchain to use for this target (as provided to `register_*_toolchain`)",
226238
),

rules/scala.bzl

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,14 @@ load(":jvm.bzl", _labeled_jars = "labeled_jars")
4343
load(":providers.bzl", _ScalaRulePhase = "ScalaRulePhase")
4444
load(
4545
":register_toolchain.bzl",
46-
_scala_toolchain_transition = "scala_toolchain_transition",
47-
_scala_toolchain_transition_attributes = "scala_toolchain_transition_attributes",
46+
_scala_toolchain_attributes = "scala_toolchain_attributes",
47+
_scala_toolchain_incoming_transition = "scala_toolchain_incoming_transition",
48+
_scala_toolchain_outgoing_transition = "scala_toolchain_outgoing_transition",
4849
)
4950

5051
_compile_private_attributes = {
5152
"_java_toolchain": attr.label(
53+
cfg = _scala_toolchain_outgoing_transition,
5254
default = Label("@bazel_tools//tools/jdk:current_java_toolchain"),
5355
),
5456
"_host_javabase": attr.label(
@@ -77,6 +79,7 @@ _compile_private_attributes = {
7779

7880
_compile_attributes = {
7981
"srcs": attr.label_list(
82+
cfg = _scala_toolchain_outgoing_transition,
8083
doc = "The source Scala and Java files (and `-sources.jar` `.srcjar` `-src.jar` files of those).",
8184
allow_files = [
8285
".scala",
@@ -88,10 +91,12 @@ _compile_attributes = {
8891
flags = ["DIRECT_COMPILE_TIME_INPUT"],
8992
),
9093
"data": attr.label_list(
94+
cfg = _scala_toolchain_outgoing_transition,
9195
doc = "The additional runtime files needed by this library.",
9296
allow_files = True,
9397
),
9498
"deps": attr.label_list(
99+
cfg = _scala_toolchain_outgoing_transition,
95100
aspects = [
96101
_labeled_jars,
97102
_coverage_replacements_provider.aspect,
@@ -100,21 +105,25 @@ _compile_attributes = {
100105
providers = [JavaInfo],
101106
),
102107
"deps_used_whitelist": attr.label_list(
108+
cfg = _scala_toolchain_outgoing_transition,
103109
doc = "The JVM library dependencies to always consider used for `scala_deps_used` checks.",
104110
providers = [JavaInfo],
105111
),
106112
"deps_unused_whitelist": attr.label_list(
113+
cfg = _scala_toolchain_outgoing_transition,
107114
doc = "The JVM library dependencies to always consider unused for `scala_deps_direct` checks.",
108115
providers = [JavaInfo],
109116
),
110117
"runtime_deps": attr.label_list(
118+
cfg = _scala_toolchain_outgoing_transition,
111119
doc = "The JVM runtime-only library dependencies.",
112120
providers = [JavaInfo],
113121
),
114122
"javacopts": attr.string_list(
115123
doc = "The Javac options.",
116124
),
117125
"plugins": attr.label_list(
126+
cfg = _scala_toolchain_outgoing_transition,
118127
doc = "The Scalac plugins.",
119128
providers = [JavaInfo],
120129
),
@@ -123,10 +132,12 @@ _compile_attributes = {
123132
),
124133
"resources": attr.label_list(
125134
allow_files = True,
135+
cfg = _scala_toolchain_outgoing_transition,
126136
doc = "The files to include as classpath resources.",
127137
),
128138
"resource_jars": attr.label_list(
129139
allow_files = [".jar"],
140+
cfg = _scala_toolchain_outgoing_transition,
130141
doc = "The JARs to merge into the output JAR.",
131142
),
132143
"scalacopts": attr.string_list(
@@ -139,6 +150,7 @@ _library_attributes = {
139150
aspects = [
140151
_coverage_replacements_provider.aspect,
141152
],
153+
cfg = _scala_toolchain_outgoing_transition,
142154
doc = "The JVM libraries to add as dependencies to any libraries dependent on this one.",
143155
providers = [JavaInfo],
144156
),
@@ -157,17 +169,20 @@ _runtime_attributes = {
157169
doc = "The JVM runtime flags.",
158170
),
159171
"runtime_deps": attr.label_list(
172+
cfg = _scala_toolchain_outgoing_transition,
160173
doc = "The JVM runtime-only library dependencies.",
161174
providers = [JavaInfo],
162175
),
163176
}
164177

165178
_runtime_private_attributes = {
166179
"_target_jdk": attr.label(
180+
cfg = _scala_toolchain_outgoing_transition,
167181
default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
168182
providers = [java_common.JavaRuntimeInfo],
169183
),
170184
"_java_stub_template": attr.label(
185+
cfg = _scala_toolchain_outgoing_transition,
171186
default = Label("@anx_java_stub_template//file"),
172187
allow_single_file = True,
173188
),
@@ -243,11 +258,11 @@ def make_scala_library(*extras):
243258
_compile_attributes,
244259
_compile_private_attributes,
245260
_library_attributes,
246-
_scala_toolchain_transition_attributes,
261+
_scala_toolchain_attributes,
247262
_extras_attributes(extras),
248263
*[extra["attrs"] for extra in extras]
249264
),
250-
cfg = _scala_toolchain_transition,
265+
cfg = _scala_toolchain_incoming_transition,
251266
doc = "Compiles a Scala JVM library.",
252267
implementation = _scala_library_implementation,
253268
outputs = _dicts.add(
@@ -271,7 +286,7 @@ def make_scala_binary(*extras):
271286
_compile_private_attributes,
272287
_runtime_attributes,
273288
_runtime_private_attributes,
274-
_scala_toolchain_transition_attributes,
289+
_scala_toolchain_attributes,
275290
{
276291
"main_class": attr.string(
277292
doc = "The main class. If not provided, it will be inferred by its type signature.",
@@ -280,7 +295,7 @@ def make_scala_binary(*extras):
280295
_extras_attributes(extras),
281296
*[extra["attrs"] for extra in extras]
282297
),
283-
cfg = _scala_toolchain_transition,
298+
cfg = _scala_toolchain_incoming_transition,
284299
doc = """
285300
Compiles and links a Scala JVM executable.
286301
@@ -317,7 +332,7 @@ def make_scala_test(*extras):
317332
_compile_private_attributes,
318333
_runtime_attributes,
319334
_runtime_private_attributes,
320-
_scala_toolchain_transition_attributes,
335+
_scala_toolchain_attributes,
321336
_testing_private_attributes,
322337
{
323338
"isolation": attr.string(
@@ -331,6 +346,7 @@ def make_scala_test(*extras):
331346
),
332347
"scalacopts": attr.string_list(doc = "Options to pass to scalac."),
333348
"shared_deps": attr.label_list(
349+
cfg = _scala_toolchain_outgoing_transition,
334350
doc = "If isolation is \"classloader\", the list of deps to keep loaded between tests",
335351
providers = [JavaInfo],
336352
),
@@ -345,13 +361,19 @@ def make_scala_test(*extras):
345361
],
346362
doc = "The list of test frameworks to check for. These should conform to the sbt test interface (https://github.com/sbt/test-interface).",
347363
),
348-
"runner": attr.label(default = "@rules_scala_annex//src/main/scala/higherkindness/rules_scala/workers/zinc/test"),
349-
"subprocess_runner": attr.label(default = "@rules_scala_annex//src/main/scala/higherkindness/rules_scala/common/sbt-testing:subprocess"),
364+
"runner": attr.label(
365+
cfg = _scala_toolchain_outgoing_transition,
366+
default = "@rules_scala_annex//src/main/scala/higherkindness/rules_scala/workers/zinc/test",
367+
),
368+
"subprocess_runner": attr.label(
369+
cfg = _scala_toolchain_outgoing_transition,
370+
default = "@rules_scala_annex//src/main/scala/higherkindness/rules_scala/common/sbt-testing:subprocess",
371+
),
350372
},
351373
_extras_attributes(extras),
352374
*[extra["attrs"] for extra in extras]
353375
),
354-
cfg = _scala_toolchain_transition,
376+
cfg = _scala_toolchain_incoming_transition,
355377
doc = """
356378
Compiles and links a collection of Scala tests.
357379
@@ -396,13 +418,15 @@ _scala_repl_private_attributes = _dicts.add(
396418
scala_repl = rule(
397419
attrs = _dicts.add(
398420
_scala_repl_private_attributes,
399-
_scala_toolchain_transition_attributes,
421+
_scala_toolchain_attributes,
400422
{
401423
"data": attr.label_list(
424+
cfg = _scala_toolchain_outgoing_transition,
402425
doc = "The additional runtime files needed by this REPL.",
403426
allow_files = True,
404427
),
405428
"deps": attr.label_list(
429+
cfg = _scala_toolchain_outgoing_transition,
406430
doc = "Dependencies that should be made available to the REPL.",
407431
providers = [JavaInfo],
408432
),
@@ -412,7 +436,7 @@ scala_repl = rule(
412436
"scalacopts": attr.string_list(doc = "Options to pass to scalac."),
413437
},
414438
),
415-
cfg = _scala_toolchain_transition,
439+
cfg = _scala_toolchain_incoming_transition,
416440
doc = """
417441
Launches a REPL with all given dependencies available.
418442
@@ -469,14 +493,16 @@ Use this only for libraries with macros. Otherwise, use `java_import`.""",
469493

470494
scaladoc = rule(
471495
attrs = _dicts.add(
472-
_scala_toolchain_transition_attributes,
496+
_scala_toolchain_attributes,
473497
_scaladoc_private_attributes,
474498
{
475499
"compiler_deps": attr.label_list(
500+
cfg = _scala_toolchain_outgoing_transition,
476501
doc = "JVM targets that should be included on the compile classpath.",
477502
providers = [JavaInfo],
478503
),
479504
"deps": attr.label_list(
505+
cfg = _scala_toolchain_outgoing_transition,
480506
doc = "Dependencies that should be made available to the Scaladoc tool. These may include libraries referenced in Scaladoc or public signatures.",
481507
providers = [JavaInfo],
482508
),
@@ -488,13 +514,14 @@ scaladoc = rule(
488514
"-sources.jar",
489515
"-src.jar",
490516
],
517+
cfg = _scala_toolchain_outgoing_transition,
491518
doc = "Sources from which to generate Scaladoc. These may include `*.java` files, `*.scala` files, and source JARs.",
492519
),
493520
"scalacopts": attr.string_list(doc = "Options to pass to scalac."),
494521
"title": attr.string(doc = "The name of the project. If none is provided, the target label will be used."),
495522
},
496523
),
497-
cfg = _scala_toolchain_transition,
524+
cfg = _scala_toolchain_incoming_transition,
498525
doc = "Generates Scaladoc.",
499526
implementation = _scaladoc_implementation,
500527
toolchains = [

rules/scala/private/repl.bzl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ def scala_repl_implementation(ctx):
4949
runfiles = ctx.runfiles(
5050
collect_default = True,
5151
collect_data = True,
52-
files = ctx.attr._target_jdk[java_common.JavaRuntimeInfo].files.to_list(),
52+
53+
# See https://bazel.build/extending/config#accessing-attributes-with-transitions:
54+
# "When attaching a transition to an outgoing edge (regardless of whether the
55+
# transition is a 1:1 or 1:2+ transition), `ctx.attr` is forced to be a list if it
56+
# isn't already. The order of elements in this list is unspecified."
57+
files = ctx.attr._target_jdk[0][java_common.JavaRuntimeInfo].files.to_list(),
5358
transitive_files = files,
5459
),
5560
),

0 commit comments

Comments
 (0)