Skip to content

Commit 08ab275

Browse files
authored
Toolchainize //scala/scalafmt:scalafmt_toolchain (#1678)
* Toolchainize //scala/scalafmt:scalafmt_toolchain This is a pretty straightforward and easy update on top of the previous `setup_toolchains` and `scala_toolchains_repo` changes. Part of #1482. * Make test_reproducibility.sh build test/coverage_* Replaces the nonexistent `//test/coverage/...` target with packages that actually exist, rendering the test more meaningful. A spurious failure caused me to run the following to inspect what was happening: ```txt RULES_SCALA_TEST_ONLY=test_build_is_identical ./test_reproducibility.sh ``` This caused me to see that the following command was failing because `//test/coverage/...` didn't exist: ```txt bazel build --collect_code_coverage -- //test/coverage/... ``` * Export `SCALAFMT_TOOLCHAIN_TYPE` constant Reduces string duplication in `//scala/scalafmt/toolchain/*.bzl` files. * Remove scalafmt_toolchain dep_providers default It's likely that no one will ever rely on the default when defining their own `scalafmt_toolchain`. While investigating #1675, I realized the `dep_providers` default was set to a nonexistent target. This didn't break our tests because our Scalafmt toolchains are created by `setup_scala_toolchain`, which sets `dep_providers` explicitly. I thought about aliasing the provider generated for the toolchain for `SCALA_VERSION` in `@io_bazel_rules_scala_toolchains//scalafmt`, or generating a new one. I ultimately decided to remove the default, because the `deps_providers` is literally the only attribute. Anyone defining their own `scalafmt_toolchain` will certainly define their own `deps_providers` target(s). * Update tests for Bazel 6 + Bzlmod Copied the regular expression used to optionally match canonical repo name prefixes in `buildozer` commands from #1622. These never failed when building with Bzlmod and Bazel 7.4.1, but did under Bazel 6.5.0. * Fix `//third_party` tests with `$(rootpath)` Fixes `{strict_deps,unused_dependency_checker}_test` from `//third_party/dependency_analyzer/src/test` under Bazel 8 by updating `$(location)` to `$(rootpath)`. Part of #1652. `//third_party/dependency_analyzer/src/test:strict_deps_test` and `//third_party/dependency_analyzer/src/test:unused_dependency_checker_test` both failed with errors of the form: ```txt StrictDepsTest: - error on indirect dependency target *** FAILED *** (379 milliseconds) nice errors on sequence of strings.this.infos.exists(nice errors on sequence of strings.this.checkErrorContainsMessage(target)) was false expected an error on //commons:Target to appear in errors (with buildozer command)! Errors: List(object apache is not a member of package org) (StrictDepsTest.scala:85) ``` This happened both under `WORKSPACE` and Bzlmod. Copying the test script with the following (with `$ID` being one of `7`, `8`, `7-updated`, or `8-updated`) helped reveal the differences: ```txt cp bazel-bin/third_party/dependency_analyzer/src/test/strict_deps_test \ strict_deps_test-$ID.sh ``` Under Bazel 7, we find the following lines whether using `$(location)` or `$(rootpath)` on the `org.apache.commons` artifact (the other artifacts already use `$(rootpath)`: ```txt -Dscala.library.location=external/io_bazel_rules_scala_scala_library_2_12_20/scala-library-2.12.20.jar -Dscala.reflect.location=external/io_bazel_rules_scala_scala_reflect_2_12_20/scala-reflect-2.12.20.jar -Dguava.jar.location=external/com_google_guava_guava_21_0_with_file/guava-21.0.jar -Dapache.commons.jar.location=external/org_apache_commons_commons_lang_3_5_without_file/commons-lang3-3.5.jar ``` Under Bazel 8, notice that the `external/` prefix has become `../` for the other paths already using `$(rootpath)`, but remains `external/` for the `$(location)` artifact. This breaks the Bazel 8 build: ```txt -Dscala.library.location=../io_bazel_rules_scala_scala_library_2_12_20/scala-library-2.12.20.jar -Dscala.reflect.location=../io_bazel_rules_scala_scala_reflect_2_12_20/scala-reflect-2.12.20.jar -Dguava.jar.location=../com_google_guava_guava_21_0_with_file/guava-21.0.jar -Dapache.commons.jar.location=external/org_apache_commons_commons_lang_3_5_without_file/commons-lang3-3.5.jar ``` Under Bazel 8, using `$(rootpath)` for the `org.apache.commons` artifact converts its `external/`, fixing the Bazel 8 build: ```txt -Dscala.library.location=../io_bazel_rules_scala_scala_library_2_12_20/scala-library-2.12.20.jar -Dscala.reflect.location=../io_bazel_rules_scala_scala_reflect_2_12_20/scala-reflect-2.12.20.jar -Dguava.jar.location=../com_google_guava_guava_21_0_with_file/guava-21.0.jar -Dapache.commons.jar.location=../org_apache_commons_commons_lang_3_5_without_file/commons-lang3-3.5.jar ```
1 parent a8ae50e commit 08ab275

14 files changed

+80
-57
lines changed

WORKSPACE

+1-6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ load("//scala:toolchains.bzl", "scala_toolchains")
5050

5151
scala_toolchains(
5252
fetch_sources = True,
53+
scalafmt = True,
5354
testing = True,
5455
)
5556

@@ -71,12 +72,6 @@ load("//scala_proto:scala_proto.bzl", "scala_proto_repositories")
7172

7273
scala_proto_repositories()
7374

74-
load("//scala/scalafmt:scalafmt_repositories.bzl", "scalafmt_default_config", "scalafmt_repositories")
75-
76-
scalafmt_default_config()
77-
78-
scalafmt_repositories()
79-
8075
# needed for the cross repo proto test
8176
local_repository(
8277
name = "proto_cross_repo_boundary",

scala/scalafmt/BUILD

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
load("//scala/scalafmt/toolchain:setup_scalafmt_toolchain.bzl", "setup_scalafmt_toolchains")
21
load("//scala/scalafmt/toolchain:toolchain.bzl", "export_scalafmt_deps")
32
load("//scala/scalafmt:phase_scalafmt_ext.bzl", "scalafmt_singleton")
43
load("//scala:scala.bzl", "scala_binary")
@@ -37,12 +36,13 @@ scalafmt_singleton(
3736
visibility = ["//visibility:public"],
3837
)
3938

40-
setup_scalafmt_toolchains()
41-
4239
# Alias for backward compatibility:
4340
alias(
4441
name = "scalafmt_toolchain",
45-
actual = "scalafmt_toolchain" + version_suffix(SCALA_VERSION),
42+
actual = (
43+
"@io_bazel_rules_scala_toolchains//scalafmt:scalafmt_toolchain" +
44+
version_suffix(SCALA_VERSION)
45+
),
4646
)
4747

4848
export_scalafmt_deps(

scala/scalafmt/phase_scalafmt_ext.bzl

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ext_scalafmt = {
2020
),
2121
"_fmt": attr.label(
2222
cfg = "exec",
23-
default = "//scala/scalafmt",
23+
default = Label("//scala/scalafmt"),
2424
executable = True,
2525
),
2626
"_java_host_runtime": attr.label(
@@ -30,19 +30,19 @@ ext_scalafmt = {
3030
),
3131
"_runner": attr.label(
3232
allow_single_file = True,
33-
default = "//scala/scalafmt:runner",
33+
default = Label("//scala/scalafmt:runner"),
3434
),
3535
"_testrunner": attr.label(
3636
allow_single_file = True,
37-
default = "//scala/scalafmt:testrunner",
37+
default = Label("//scala/scalafmt:testrunner"),
3838
),
3939
},
4040
"outputs": {
4141
"scalafmt_runner": "%{name}.format",
4242
"scalafmt_testrunner": "%{name}.format-test",
4343
},
4444
"phase_providers": [
45-
"//scala/scalafmt:phase_scalafmt",
45+
Label("//scala/scalafmt:phase_scalafmt"),
4646
],
4747
}
4848

scala/scalafmt/scalafmt_repositories.bzl

+6-14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ load(
44
"version_suffix",
55
_default_maven_server_urls = "default_maven_server_urls",
66
)
7+
load(
8+
"//scala_proto/default:repositories.bzl",
9+
"SCALAPB_COMPILE_ARTIFACT_IDS",
10+
)
711
load("//third_party/repositories:repositories.bzl", "repositories")
812
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
913

@@ -32,22 +36,16 @@ def scalafmt_default_config(path = ".scalafmt.conf", **kwargs):
3236
_SCALAFMT_DEPS = [
3337
"com_geirsson_metaconfig_core",
3438
"com_geirsson_metaconfig_typesafe_config",
35-
"com_google_protobuf_protobuf_java",
3639
"com_lihaoyi_fansi",
37-
"com_lihaoyi_fastparse",
38-
"com_lihaoyi_sourcecode",
3940
"com_typesafe_config",
40-
"org_scala_lang_modules_scala_collection_compat",
4141
"org_scala_lang_scalap",
4242
"org_scalameta_common",
4343
"org_scalameta_parsers",
4444
"org_scalameta_scalafmt_core",
4545
"org_scalameta_scalameta",
4646
"org_scalameta_trees",
4747
"org_typelevel_paiges_core",
48-
"scala_proto_rules_scalapb_lenses",
49-
"scala_proto_rules_scalapb_runtime",
50-
]
48+
] + SCALAPB_COMPILE_ARTIFACT_IDS
5149

5250
_SCALAFMT_DEPS_2_11 = [
5351
"com_lihaoyi_pprint",
@@ -79,8 +77,7 @@ def scalafmt_artifact_ids(scala_version):
7977

8078
def scalafmt_repositories(
8179
maven_servers = _default_maven_server_urls(),
82-
overriden_artifacts = {},
83-
bzlmod_enabled = False):
80+
overriden_artifacts = {}):
8481
for scala_version in SCALA_VERSIONS:
8582
repositories(
8683
scala_version = scala_version,
@@ -89,11 +86,6 @@ def scalafmt_repositories(
8986
overriden_artifacts = overriden_artifacts,
9087
)
9188

92-
if not bzlmod_enabled:
93-
_register_scalafmt_toolchains()
94-
95-
def _register_scalafmt_toolchains():
96-
for scala_version in SCALA_VERSIONS:
9789
native.register_toolchains(str(Label(
9890
"//scala/scalafmt:scalafmt_toolchain" +
9991
version_suffix(scala_version),

scala/scalafmt/toolchain/setup_scalafmt_toolchain.bzl

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
load("//scala/scalafmt/toolchain:toolchain.bzl", "scalafmt_toolchain")
1+
load(
2+
"//scala/scalafmt/toolchain:toolchain.bzl",
3+
"SCALAFMT_TOOLCHAIN_TYPE",
4+
"scalafmt_toolchain",
5+
)
26
load("//scala/scalafmt:scalafmt_repositories.bzl", "scalafmt_artifact_ids")
37
load("//scala:providers.bzl", "declare_deps_provider")
48
load("//scala:scala_cross_version.bzl", "version_suffix")
@@ -28,9 +32,7 @@ def setup_scalafmt_toolchain(
2832
version_suffix(scala_version),
2933
],
3034
toolchain = ":%s_impl" % name,
31-
toolchain_type = Label(
32-
"//scala/scalafmt/toolchain:scalafmt_toolchain_type",
33-
),
35+
toolchain_type = SCALAFMT_TOOLCHAIN_TYPE,
3436
visibility = visibility,
3537
)
3638

+7-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
load("@io_bazel_rules_scala//scala:providers.bzl", _DepsInfo = "DepsInfo")
22
load("//scala/private/toolchain_deps:toolchain_deps.bzl", "expose_toolchain_deps")
33

4+
SCALAFMT_TOOLCHAIN_TYPE = Label(
5+
"//scala/scalafmt/toolchain:scalafmt_toolchain_type",
6+
)
7+
48
def _scalafmt_toolchain_impl(ctx):
59
toolchain = platform_common.ToolchainInfo(
610
dep_providers = ctx.attr.dep_providers,
@@ -10,20 +14,12 @@ def _scalafmt_toolchain_impl(ctx):
1014
scalafmt_toolchain = rule(
1115
_scalafmt_toolchain_impl,
1216
attrs = {
13-
"dep_providers": attr.label_list(
14-
default = [
15-
"@io_bazel_rules_scala//scala/scalafmt:scalafmt_classpath_provider",
16-
],
17-
providers = [_DepsInfo],
18-
),
17+
"dep_providers": attr.label_list(providers = [_DepsInfo]),
1918
},
2019
)
2120

2221
def _export_scalafmt_deps_impl(ctx):
23-
return expose_toolchain_deps(
24-
ctx,
25-
"@io_bazel_rules_scala//scala/scalafmt/toolchain:scalafmt_toolchain_type",
26-
)
22+
return expose_toolchain_deps(ctx, SCALAFMT_TOOLCHAIN_TYPE)
2723

2824
export_scalafmt_deps = rule(
2925
_export_scalafmt_deps_impl,
@@ -32,6 +28,6 @@ export_scalafmt_deps = rule(
3228
mandatory = True,
3329
),
3430
},
35-
toolchains = ["@io_bazel_rules_scala//scala/scalafmt/toolchain:scalafmt_toolchain_type"],
31+
toolchains = [SCALAFMT_TOOLCHAIN_TYPE],
3632
incompatible_use_toolchain_transition = True,
3733
)

scala/toolchains.bzl

+22-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22

33
load("//junit:junit.bzl", "junit_artifact_ids")
44
load("//scala/private:macros/scala_repositories.bzl", "scala_repositories")
5-
load("//scala:toolchains_repo.bzl", "scala_toolchains_repo")
5+
load(
6+
"//scala/scalafmt:scalafmt_repositories.bzl",
7+
"scalafmt_artifact_ids",
8+
"scalafmt_default_config",
9+
)
610
load("//scala:scala_cross_version.bzl", "default_maven_server_urls")
11+
load("//scala:toolchains_repo.bzl", "scala_toolchains_repo")
712
load("//scalatest:scalatest.bzl", "scalatest_artifact_ids")
813
load("//specs2:specs2.bzl", "specs2_artifact_ids")
914
load("//specs2:specs2_junit.bzl", "specs2_junit_artifact_ids")
@@ -21,7 +26,9 @@ def scala_toolchains(
2126
scalatest = False,
2227
junit = False,
2328
specs2 = False,
24-
testing = False):
29+
testing = False,
30+
scalafmt = False,
31+
scalafmt_default_config_path = ".scalafmt.conf"):
2532
"""Instantiates @io_bazel_rules_scala_toolchains and all its dependencies.
2633
2734
Provides a unified interface to configuring rules_scala both directly in a
@@ -66,6 +73,9 @@ def scala_toolchains(
6673
specs2: whether to instantiate the Specs2 JUnit toolchain
6774
testing: whether to instantiate the Scalatest, JUnit, and Specs2 JUnit
6875
toolchains combined
76+
scalafmt: whether to instantiate the Scalafmt toolchain
77+
scalafmt_default_config_path: the relative path to the default Scalafmt
78+
config file within the repository
6979
"""
7080
scala_repositories(
7181
maven_servers = maven_servers,
@@ -78,6 +88,9 @@ def scala_toolchains(
7888
scala_compiler_srcjars = scala_compiler_srcjars,
7989
)
8090

91+
if scalafmt:
92+
scalafmt_default_config(scalafmt_default_config_path)
93+
8194
if testing:
8295
scalatest = True
8396
junit = True
@@ -106,6 +119,12 @@ def scala_toolchains(
106119
for scala_version in SCALA_VERSIONS:
107120
version_specific_artifact_ids = {}
108121

122+
if scalafmt:
123+
version_specific_artifact_ids.update({
124+
id: fetch_sources
125+
for id in scalafmt_artifact_ids(scala_version)
126+
})
127+
109128
all_artifacts = (
110129
artifact_ids_to_fetch_sources | version_specific_artifact_ids
111130
)
@@ -125,6 +144,7 @@ def scala_toolchains(
125144
junit = junit,
126145
specs2 = specs2,
127146
testing = testing,
147+
scalafmt = scalafmt,
128148
)
129149

130150
def scala_register_toolchains():

scala/toolchains_repo.bzl

+13
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def _scala_toolchains_repo_impl(repository_ctx):
5050
format_args.update(testing_build_args)
5151
toolchains["testing"] = _TESTING_TOOLCHAIN_BUILD
5252

53+
if repo_attr.scalafmt:
54+
toolchains["scalafmt"] = _SCALAFMT_TOOLCHAIN_BUILD
55+
5356
if len(toolchains) == 0:
5457
fail("no toolchains specified")
5558

@@ -69,6 +72,7 @@ _scala_toolchains_repo = repository_rule(
6972
"junit": attr.bool(),
7073
"specs2": attr.bool(),
7174
"testing": attr.bool(),
75+
"scalafmt": attr.bool(),
7276
},
7377
)
7478

@@ -143,3 +147,12 @@ load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
143147
for scala_version in SCALA_VERSIONS
144148
]
145149
"""
150+
151+
_SCALAFMT_TOOLCHAIN_BUILD = """
152+
load(
153+
"@@{rules_scala_repo}//scala/scalafmt/toolchain:setup_scalafmt_toolchain.bzl",
154+
"setup_scalafmt_toolchains",
155+
)
156+
157+
setup_scalafmt_toolchains()
158+
"""

test/shell/test_scala_library.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ test_scala_library_expect_failure_on_missing_direct_internal_deps() {
5959
}
6060

6161
test_scala_library_expect_failure_on_missing_direct_external_deps_jar() {
62-
dependenecy_target='@com_google_guava_guava_21_0//:com_google_guava_guava_21_0'
62+
dependenecy_target='@[a-z_.~+-]*com_google_guava_guava_21_0//:com_google_guava_guava_21_0'
6363
test_target='test_expect_failure/missing_direct_deps/external_deps:transitive_external_dependency_user'
6464

6565
test_scala_library_expect_failure_on_missing_direct_deps $dependenecy_target $test_target
6666
}
6767

6868
test_scala_library_expect_failure_on_missing_direct_external_deps_file_group() {
69-
dependenecy_target='@com_google_guava_guava_21_0_with_file//:com_google_guava_guava_21_0_with_file'
69+
dependenecy_target='@[a-z_.~+-]*com_google_guava_guava_21_0_with_file//:com_google_guava_guava_21_0_with_file'
7070
test_target='test_expect_failure/missing_direct_deps/external_deps:transitive_external_dependency_user_file_group'
7171

7272
test_scala_library_expect_failure_on_missing_direct_deps $dependenecy_target $test_target

test/shell/test_strict_dependency.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ test_strict_deps_filter_excluded_target() {
6060

6161
test_strict_deps_filter_included_target() {
6262
local test_target="//test_expect_failure/missing_direct_deps/filtering:b"
63-
local expected_message="buildozer 'add deps @com_google_guava_guava_21_0//:com_google_guava_guava_21_0' ${test_target}"
63+
local expected_message="buildozer 'add deps @[a-z_.~+-]*com_google_guava_guava_21_0//:com_google_guava_guava_21_0' ${test_target}"
6464

6565
test_expect_failure_or_warning_on_missing_direct_deps_with_expected_message \
6666
"${expected_message}" ${test_target} \

test/shell/test_unused_dependency.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ test_unused_deps_filter_excluded_target() {
7979

8080
test_unused_deps_filter_included_target() {
8181
local test_target="//test_expect_failure/unused_dependency_checker/filtering:b"
82-
local expected_message="buildozer 'remove deps @com_google_guava_guava_21_0//:com_google_guava_guava_21_0' ${test_target}"
82+
local expected_message="buildozer 'remove deps @[a-z_.~+-]*com_google_guava_guava_21_0//:com_google_guava_guava_21_0' ${test_target}"
8383

8484
test_expect_failure_or_warning_on_missing_direct_deps_with_expected_message \
8585
"${expected_message}" ${test_target} \

test_cross_build/WORKSPACE

+1-4
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,8 @@ scala_config(
6666
load("@io_bazel_rules_scala//scala:toolchains.bzl", "scala_toolchains")
6767

6868
scala_toolchains(
69+
scalafmt = True,
6970
scalatest = True,
7071
)
7172

7273
register_toolchains("@io_bazel_rules_scala_toolchains//...:all")
73-
74-
load("@io_bazel_rules_scala//scala/scalafmt:scalafmt_repositories.bzl", "scalafmt_repositories")
75-
76-
scalafmt_repositories()

test_reproducibility.sh

+10-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@ non_deploy_jar_md5_sum() {
2020
find bazel-bin/test -name "*.jar" ! -name "*_deploy.jar" ! -path 'bazel-bin/test/jmh/*' | xargs -n 1 -P 5 $(md5_util) | sort
2121
}
2222

23+
2324
test_build_is_identical() {
25+
local test_coverage_packages=()
26+
27+
for package_dir in test/coverage_*; do
28+
test_coverage_packages+=("//${package_dir}/...")
29+
done
30+
2431
bazel clean #ensure we are starting from square one
2532
bazel build test/...
2633
# Also build instrumented jars.
27-
bazel build --collect_code_coverage -- //test/coverage/...
34+
bazel build --collect_code_coverage -- "${test_coverage_packages[@]}"
2835
non_deploy_jar_md5_sum > hash1
2936
bazel clean
3037
sleep 10 # to make sure that if timestamps slip in we get different ones
@@ -37,7 +44,8 @@ test_build_is_identical() {
3744
fi
3845

3946
bazel build --disk_cache $random_dir test/...
40-
bazel build --disk_cache $random_dir --collect_code_coverage -- //test/coverage/...
47+
bazel build --disk_cache $random_dir --collect_code_coverage -- \
48+
"${test_coverage_packages[@]}"
4149
non_deploy_jar_md5_sum > hash2
4250
diff hash1 hash2
4351
}

third_party/dependency_analyzer/src/test/analyzer_test.bzl

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def tests():
5757
],
5858
jvm_flags = common_jvm_flags + [
5959
"-Dguava.jar.location=$(rootpath @com_google_guava_guava_21_0_with_file//jar)",
60-
"-Dapache.commons.jar.location=$(location @org_apache_commons_commons_lang_3_5_without_file//:linkable_org_apache_commons_commons_lang_3_5_without_file)",
60+
"-Dapache.commons.jar.location=$(rootpath @org_apache_commons_commons_lang_3_5_without_file//:linkable_org_apache_commons_commons_lang_3_5_without_file)",
6161
],
6262
unused_dependency_checker_mode = "off",
6363
deps = scala_std_dependencies + [
@@ -76,7 +76,7 @@ def tests():
7676
"io/bazel/rulesscala/dependencyanalyzer/UnusedDependencyCheckerTest.scala",
7777
],
7878
jvm_flags = common_jvm_flags + [
79-
"-Dapache.commons.jar.location=$(location @org_apache_commons_commons_lang_3_5_without_file//:linkable_org_apache_commons_commons_lang_3_5_without_file)",
79+
"-Dapache.commons.jar.location=$(rootpath @org_apache_commons_commons_lang_3_5_without_file//:linkable_org_apache_commons_commons_lang_3_5_without_file)",
8080
],
8181
unused_dependency_checker_mode = "off",
8282
deps = scala_std_dependencies + [

0 commit comments

Comments
 (0)