Skip to content

Commit 1ec795e

Browse files
committed
Toolchainize all testing toolchains
Moves the Scalatest, JUnit, and Specs2 toolchains into `@io_bazel_rules_scala_toolchains//testing`. Part of bazelbuild#1482. Updates all `WORKSPACE` files to set the appropriate `scala_toolchains` parameters and to remove the unnecessary repository import and toolchain registration macros. Adds a `fetch_sources_by_id` parameter to `repositories` from `third_party/repositories/repositories.bzl`. This enables `scala_toolchains` to build the `artifact_ids_to_fetch_sources` mapping from artifact ID lists returned by new macros extracted from `WORKSPACE` macros. The values assigned to each id match the original `fetch_sources` settings in the corresponding original `WORKSPACE` macros. Updates `scala/scala_maven_import_external.bzl` to generate a `load` line for `//scala:scala_import.bzl` based on the repo's canonical name, not `@io_bazel_rules_scala`. As usual, includes several other opportunistic removals of the `@io_bazel_rules_scala` repo name prefix to avoid an internal dependency on that name. This means Bzlmod users won't necessarily have to set the `repo_name` parameter of `bazel_dep` when using `rules_scala`. --- Introduces more macros to return a framework's Maven artifact dependencies, rather than inlining them in a `repositories` call. These inlined lists are replaced by macro invocations, and now the `scala_toolchains` macro can invoke these macros to collect artifact IDs to pass to `repositories`. This also allows for future changes to introduce a `scala_version` parameter if necessary, similar to how `scalafmt_artifact_ids` already works. This is important to avoid collisions when creating repositories for artifacts upon which more than one framework depends under Bzlmod. `WORKSPACE` doesn't seem affected by these collisions, but Bzlmod will produce errors like the following, where both `scala_proto` and `twitter_scrooge` depend upon `io_bazel_rules_scala_guava`: ```txt $ bazel build //src/... ERROR: .../scala/scala_maven_import_external.bzl:299:24: Traceback (most recent call last): File ".../scala/extensions/deps.bzl", line 140, column 21, in _scala_deps_impl scala_toolchains( File ".../scala/private/macros/toolchains.bzl", line 140, column 17, in scala_toolchains _scrooge( File ".../twitter_scrooge/twitter_scrooge.bzl", line 96, column 17, in twitter_scrooge repositories( File ".../third_party/repositories/repositories.bzl", line 113, column 37, in repositories _scala_maven_import_external( File ".../scala/scala_maven_import_external.bzl", line 263, column 30, in scala_maven_import_external jvm_maven_import_external( File ".../scala/scala_maven_import_external.bzl", line 299, column 24, in jvm_maven_import_external jvm_import_external(jar_urls = jar_urls, srcjar_urls = srcjar_urls, coordinates = artifact, **kwargs) Error in repository_rule: A repo named io_bazel_rules_scala_guava_2_13_15 is already generated by this module extension at .../scala/scala_maven_import_external.bzl:299:24 ERROR: Analysis of target '//src/java/io/bazel/rulesscala/worker:worker_test' failed; build aborted: error evaluating module extension scala_deps in //scala/extensions:deps.bzl ``` Recent updates to `scripts/create_repository.py` (bazelbuild#1639, bazelbuild#1642) make it easy to emit full direct dependency lists for artifacts included in `third_party/repositories/scala_*.bzl`. This increases the likelihood of collisions, since this expanded metadata forces the macros that instantiate artifact repos to instantiate even more repos. By fetching list of artifact IDs from these macros, `scala_toolchains` can now consolidate them into dictionary keys. Then it passes these unique keys to `repositories` directly, avoiding the problem of instantiating the same repo multiple times in the same module extension. This, in turn, also avoids the need to add parameters to the original `WORKSPACE` macros that instantiate dependencies to avoid collisions under Bzlmod. The `scala_toolchains` macro never needs to call these original macros, under either `WORKSPACE` or Bzlmod. Finally, it also reduces duplication between these artifact ID lists and the `_*_DEPS` symbols originally from `testing/BUILD` (and now in `testing/deps.bzl`). The dependency labels are now generated programatically. (Aside: As I mentioned, we may eventually need to pass a Scala version argument to these macros. It will be possible to cross that bridge without too much trouble if and when that day comes. Or I can try to future proof it in a follow up pull request.)
1 parent d35448f commit 1ec795e

File tree

26 files changed

+293
-241
lines changed

26 files changed

+293
-241
lines changed

WORKSPACE

+4-10
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ scala_config(enable_compiler_dependency_tracking = True)
4141

4242
load("//scala:scala.bzl", "scala_toolchains")
4343

44-
scala_toolchains(fetch_sources = True)
44+
scala_toolchains(
45+
fetch_sources = True,
46+
testing = True,
47+
)
4548

4649
register_toolchains(
47-
"//testing:testing_toolchain",
4850
"//scala:unused_dependency_checker_error_toolchain",
4951
"//test/proto:scalapb_toolchain",
5052
"@io_bazel_rules_scala_toolchains//...:all",
@@ -79,14 +81,6 @@ load("//scala_proto:scala_proto.bzl", "scala_proto_repositories")
7981

8082
scala_proto_repositories()
8183

82-
load("//scalatest:scalatest.bzl", "scalatest_repositories")
83-
84-
scalatest_repositories()
85-
86-
load("//specs2:specs2_junit.bzl", "specs2_junit_repositories")
87-
88-
specs2_junit_repositories()
89-
9084
load("//scala/scalafmt:scalafmt_repositories.bzl", "scalafmt_default_config", "scalafmt_repositories")
9185

9286
scalafmt_default_config()

examples/crossbuild/WORKSPACE

+1-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ scala_config(
4040

4141
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_toolchains")
4242

43-
scala_toolchains()
43+
scala_toolchains(scalatest = True)
4444

4545
register_toolchains("@io_bazel_rules_scala_toolchains//...:all")
4646

@@ -59,9 +59,3 @@ rules_proto_toolchains()
5959
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
6060

6161
protobuf_deps()
62-
63-
load("@io_bazel_rules_scala//testing:scalatest.bzl", "scalatest_repositories", "scalatest_toolchain")
64-
65-
scalatest_repositories()
66-
67-
scalatest_toolchain()

examples/testing/multi_frameworks_toolchain/BUILD

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
load("@io_bazel_rules_scala//scala:scala.bzl", "setup_scala_testing_toolchain")
2-
load("@io_bazel_rules_scala//scala:scala_cross_version.bzl", "version_suffix")
3-
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSION")
42

53
setup_scala_testing_toolchain(
64
name = "testing_toolchain",
75
junit_classpath = [
86
"@io_bazel_rules_scala_junit_junit",
97
"@io_bazel_rules_scala_org_hamcrest_hamcrest_core",
108
],
11-
scalatest_classpath = [dep + version_suffix(SCALA_VERSION) for dep in [
9+
scalatest_classpath = [
1210
"@io_bazel_rules_scala_scalactic",
1311
"@io_bazel_rules_scala_scalatest",
1412
"@io_bazel_rules_scala_scalatest_compatible",
@@ -21,7 +19,7 @@ setup_scala_testing_toolchain(
2119
"@io_bazel_rules_scala_scalatest_matchers_core",
2220
"@io_bazel_rules_scala_scalatest_mustmatchers",
2321
"@io_bazel_rules_scala_scalatest_shouldmatchers",
24-
]],
22+
],
2523
specs2_classpath = [
2624
"@io_bazel_rules_scala_org_specs2_specs2_common",
2725
"@io_bazel_rules_scala_org_specs2_specs2_core",

examples/testing/multi_frameworks_toolchain/WORKSPACE

+4-11
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ scala_config()
3333

3434
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_toolchains")
3535

36-
scala_toolchains(fetch_sources = True)
36+
scala_toolchains(
37+
fetch_sources = True,
38+
testing = True,
39+
)
3740

3841
register_toolchains(
3942
":testing_toolchain",
@@ -55,13 +58,3 @@ rules_proto_toolchains()
5558
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
5659

5760
protobuf_deps()
58-
59-
load("@io_bazel_rules_scala//testing:scalatest.bzl", "scalatest_repositories")
60-
load("@io_bazel_rules_scala//testing:junit.bzl", "junit_repositories")
61-
load("@io_bazel_rules_scala//testing:specs2_junit.bzl", "specs2_junit_repositories")
62-
63-
scalatest_repositories()
64-
65-
junit_repositories()
66-
67-
specs2_junit_repositories()

examples/testing/scalatest_repositories/WORKSPACE

+4-7
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ scala_config()
3333

3434
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_toolchains")
3535

36-
scala_toolchains(fetch_sources = True)
36+
scala_toolchains(
37+
fetch_sources = True,
38+
scalatest = True,
39+
)
3740

3841
register_toolchains("@io_bazel_rules_scala_toolchains//...:all")
3942

@@ -52,9 +55,3 @@ rules_proto_toolchains()
5255
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
5356

5457
protobuf_deps()
55-
56-
load("@io_bazel_rules_scala//testing:scalatest.bzl", "scalatest_repositories", "scalatest_toolchain")
57-
58-
scalatest_repositories()
59-
60-
scalatest_toolchain()

examples/testing/specs2_junit_repositories/WORKSPACE

+4-7
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ scala_config()
3333

3434
load("@io_bazel_rules_scala//scala:scala.bzl", "scala_toolchains")
3535

36-
scala_toolchains(fetch_sources = True)
36+
scala_toolchains(
37+
fetch_sources = True,
38+
specs2 = True,
39+
)
3740

3841
register_toolchains("@io_bazel_rules_scala_toolchains//...:all")
3942

@@ -52,9 +55,3 @@ rules_proto_toolchains()
5255
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
5356

5457
protobuf_deps()
55-
56-
load("@io_bazel_rules_scala//testing:specs2_junit.bzl", "specs2_junit_repositories", "specs2_junit_toolchain")
57-
58-
specs2_junit_repositories()
59-
60-
specs2_junit_toolchain()

junit/junit.bzl

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ load(
44
)
55
load("//third_party/repositories:repositories.bzl", "repositories")
66

7+
def junit_artifact_ids():
8+
return [
9+
"io_bazel_rules_scala_junit_junit",
10+
"io_bazel_rules_scala_org_hamcrest_hamcrest_core",
11+
]
12+
713
def junit_repositories(
814
maven_servers = _default_maven_server_urls(),
915
fetch_sources = True):
1016
repositories(
11-
for_artifact_ids = [
12-
"io_bazel_rules_scala_junit_junit",
13-
"io_bazel_rules_scala_org_hamcrest_hamcrest_core",
14-
],
17+
for_artifact_ids = junit_artifact_ids(),
1518
fetch_sources = fetch_sources,
1619
maven_servers = maven_servers,
1720
)

scala/private/macros/toolchains.bzl

+64-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
"""Macro to instantiate @io_bazel_rules_scala_toolchains"""
22

33
load(":macros/toolchains_repo.bzl", "scala_toolchains_repo")
4+
load("//junit:junit.bzl", "junit_artifact_ids")
45
load("//scala/private:macros/scala_repositories.bzl", "scala_repositories")
56
load("//scala:scala_cross_version.bzl", "default_maven_server_urls")
7+
load("//scalatest:scalatest.bzl", "scalatest_artifact_ids")
8+
load("//specs2:specs2.bzl", "specs2_artifact_ids")
9+
load("//specs2:specs2_junit.bzl", "specs2_junit_artifact_ids")
10+
load("//third_party/repositories:repositories.bzl", "repositories")
11+
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
612

713
def scala_toolchains(
814
maven_servers = default_maven_server_urls(),
@@ -11,7 +17,11 @@ def scala_toolchains(
1117
load_scala_toolchain_dependencies = True,
1218
fetch_sources = False,
1319
validate_scala_version = True,
14-
scala_compiler_srcjars = {}):
20+
scala_compiler_srcjars = {},
21+
scalatest = False,
22+
junit = False,
23+
specs2 = False,
24+
testing = False):
1525
"""Instantiates @io_bazel_rules_scala_toolchains and all its dependencies.
1626
1727
Provides a unified interface to configuring rules_scala both directly in a
@@ -51,6 +61,11 @@ def scala_toolchains(
5161
compiler srcjar metadata dictionaries containing:
5262
- exactly one "label", "url", or "urls" key
5363
- optional "integrity" or "sha256" keys
64+
scalatest: whether to instantiate the Scalatest toolchain
65+
junit: whether to instantiate the JUnit toolchain
66+
specs2: whether to instantiate the Specs2 JUnit toolchain
67+
testing: whether to instantiate the Scalatest, JUnit, and Specs2 JUnit
68+
toolchains combined
5469
"""
5570
scala_repositories(
5671
maven_servers = maven_servers,
@@ -63,4 +78,51 @@ def scala_toolchains(
6378
scala_compiler_srcjars = scala_compiler_srcjars,
6479
)
6580

66-
scala_toolchains_repo()
81+
if testing:
82+
scalatest = True
83+
junit = True
84+
specs2 = True
85+
if specs2:
86+
junit = True
87+
88+
artifact_ids_to_fetch_sources = {}
89+
90+
if scalatest:
91+
artifact_ids_to_fetch_sources.update({
92+
id: True
93+
for id in scalatest_artifact_ids()
94+
})
95+
if junit:
96+
artifact_ids_to_fetch_sources.update({
97+
id: True
98+
for id in junit_artifact_ids()
99+
})
100+
if specs2:
101+
artifact_ids_to_fetch_sources.update({
102+
id: True
103+
for id in specs2_artifact_ids() + specs2_junit_artifact_ids()
104+
})
105+
106+
for scala_version in SCALA_VERSIONS:
107+
version_specific_artifact_ids = {}
108+
109+
all_artifacts = (
110+
artifact_ids_to_fetch_sources | version_specific_artifact_ids
111+
)
112+
113+
repositories(
114+
scala_version = scala_version,
115+
for_artifact_ids = all_artifacts.keys(),
116+
maven_servers = maven_servers,
117+
fetch_sources = fetch_sources,
118+
fetch_sources_by_id = all_artifacts,
119+
overriden_artifacts = overridden_artifacts,
120+
validate_scala_version = validate_scala_version,
121+
)
122+
123+
scala_toolchains_repo(
124+
scalatest = scalatest,
125+
junit = junit,
126+
specs2 = specs2,
127+
testing = testing,
128+
)

scala/private/macros/toolchains_repo.bzl

+67
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
11
"""Repository rule to instantiate @io_bazel_rules_scala_toolchains"""
22

3+
def _generate_testing_toolchain_build_file_args(repo_attr):
4+
framework_deps = {}
5+
6+
if repo_attr.testing:
7+
framework_deps = {
8+
"scalatest": "SCALATEST_DEPS",
9+
"junit": "JUNIT_DEPS",
10+
"specs2": "SPECS2_DEPS",
11+
"specs2_junit": "SPECS2_JUNIT_DEPS",
12+
}
13+
if repo_attr.scalatest:
14+
framework_deps["scalatest"] = "SCALATEST_DEPS"
15+
if repo_attr.specs2:
16+
framework_deps["specs2"] = "SPECS2_DEPS"
17+
framework_deps["specs2_junit"] = "SPECS2_JUNIT_DEPS"
18+
framework_deps["junit"] = "JUNIT_DEPS"
19+
if repo_attr.junit:
20+
framework_deps["junit"] = "JUNIT_DEPS"
21+
22+
if len(framework_deps) == 0:
23+
return None
24+
25+
# The _TESTING_TOOLCHAIN_BUILD template expects that all framework keys are
26+
# present in the dictionary, so it can set unset framework classpath
27+
# parameters to `None`.
28+
return {
29+
"deps_symbols": "\",\n \"".join(
30+
[s for s in framework_deps.values()],
31+
),
32+
"scalatest": framework_deps.get("scalatest"),
33+
"junit": framework_deps.get("junit"),
34+
"specs2": framework_deps.get("specs2"),
35+
"specs2_junit": framework_deps.get("specs2_junit"),
36+
}
37+
338
def _scala_toolchains_repo_impl(repository_ctx):
439
repo_attr = repository_ctx.attr
540
format_args = {
@@ -10,6 +45,11 @@ def _scala_toolchains_repo_impl(repository_ctx):
1045
if repo_attr.scala:
1146
toolchains["scala"] = _SCALA_TOOLCHAIN_BUILD
1247

48+
testing_build_args = _generate_testing_toolchain_build_file_args(repo_attr)
49+
if testing_build_args != None:
50+
format_args.update(testing_build_args)
51+
toolchains["testing"] = _TESTING_TOOLCHAIN_BUILD
52+
1353
if len(toolchains) == 0:
1454
fail("no toolchains specified")
1555

@@ -22,8 +62,13 @@ def _scala_toolchains_repo_impl(repository_ctx):
2262

2363
_scala_toolchains_repo = repository_rule(
2464
implementation = _scala_toolchains_repo_impl,
65+
doc = "Creates a repo containing Scala toolchain packages",
2566
attrs = {
2667
"scala": attr.bool(default = True),
68+
"scalatest": attr.bool(),
69+
"junit": attr.bool(),
70+
"specs2": attr.bool(),
71+
"testing": attr.bool(),
2772
},
2873
)
2974

@@ -73,3 +118,25 @@ load(
73118
]
74119
]
75120
"""
121+
122+
_TESTING_TOOLCHAIN_BUILD = """
123+
load("@@{rules_scala_repo}//scala:scala.bzl", "setup_scala_testing_toolchain")
124+
load("@@{rules_scala_repo}//scala:scala_cross_version.bzl", "version_suffix")
125+
load(
126+
"@@{rules_scala_repo}//testing:deps.bzl",
127+
"{deps_symbols}",
128+
)
129+
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
130+
131+
[
132+
setup_scala_testing_toolchain(
133+
name = "testing_toolchain" + version_suffix(scala_version),
134+
scala_version = scala_version,
135+
scalatest_classpath = {scalatest},
136+
junit_classpath = {junit},
137+
specs2_classpath = {specs2},
138+
specs2_junit_classpath = {specs2_junit},
139+
)
140+
for scala_version in SCALA_VERSIONS
141+
]
142+
"""

0 commit comments

Comments
 (0)