diff --git a/README.md b/README.md index 074c5ed89..7fe3f238d 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,13 @@ http_archive( load("@io_bazel_rules_scala//scala:scala.bzl", "scala_repositories") scala_repositories() ``` -To use a particular tag, use the tagged number in `tag = ` and omit the `commit` attribute. -Note that these plugins are still evolving quickly, as is bazel, so you may need to select -the version most appropriate for you. +In addition, you **must** register `scala_toolchain` - To register default empty toolcahin simply add those lines to `WORKSPACE` file: +```python + +load("@io_bazel_rules_scala/scala:toolchains.bzl", "scala_register_toolchains") +scala_register_toolchains() +``` +[read more here](#scala_toolchain) Then in your BUILD file just add the following so the rules will be available: ```python @@ -543,9 +547,50 @@ generated by the [ScalaPB compiler](https://github.com/scalapb/ScalaPB). +## scala_toolchain +Scala toolchain allows you to define global configuration to all scala targets. +Currently the only option that can be set is `scalacopts` but the plan is to expand it to other options as well. + +**some scala_toolchain must be registered!** +### Several options to configure scala_toolchain: +#### A) Use default scala_toolchain: +In your workspace file add the following lines: + ```python + # WORKSPACE + # register default scala toolchain + load("@io_bazel_rules_scala/scala:toolchains.bzl", "scala_register_toolchains") + scala_register_toolchains() + ``` +#### B) Defining your own scala_toolchain requires 2 steps: +1. Add your own definition to scala_toolchain to a `BUILD` file: + ```python + # //toolchains/BUILD + load("//scala:scala_toolchain.bzl", "scala_toolchain") + + scala_toolchain( + name = "my_toolchain_impl", + scalacopts = ["-Ywarn-unused"], + visibility = ["//visibility:public"] + ) + + toolchain( + name = "my_scala_toolchain", + toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type", + toolchain = "my_toolchain_impl", + visibility = ["//visibility:public"] + ) + ``` +2. register your custom toolchain from `WORKSPACE`: + ```python + # WORKSPACE + # ... + register_toolchains("//toolchains:my_scala_toolchain") + ``` + + ## [Experimental] Using strict-deps -Bazel pushes towards explicit and minimial dependencies to keep BUILD file higene and allow for targets to refactor their dependencies without fear of downstream breaking. -Currently rules_scala does this at the cost of having cryptic `scalac` errors when one mistakenly depends on a transitive dependency or, as more often the case for some, a transitive dependency is needed to [please scalac](https://github.com/scalacenter/advisoryboard/blob/master/proposals/009-improve-direct-dependency-experience.md) itself. +Bazel pushes towards explicit and minimial dependencies to keep BUILD file higene and allow for targets to refactor their dependencies without fear of downstream breaking. +Currently rules_scala does this at the cost of having cryptic `scalac` errors when one mistakenly depends on a transitive dependency or, as more often the case for some, a transitive dependency is needed to [please scalac](https://github.com/scalacenter/advisoryboard/blob/master/proposals/009-improve-direct-dependency-experience.md) itself. To learn more about the motivation of strict-deps itself you can visit this Bazel blog [post](https://blog.bazel.build/2017/06/28/sjd-unused_deps.html) on the subject. To use it just add `--strict_java_deps=WARN|ERROR` to your `bazel` invocation. @@ -556,7 +601,7 @@ Target '//some_package:transitive_dependency' is used but isn't explicitly decla You can use the following buildozer command: buildozer 'add deps //some_package:transitive_dependency' //some_other_package:transitive_dependency_user ``` -Note that if you have `buildozer` installed you can just run the last line and have it automatically apply the fix for you. +Note that if you have `buildozer` installed you can just run the last line and have it automatically apply the fix for you. **Caveats:** - + Note: Currently strict-deps is protected by a feature toggle but we're strongly considering making it the default behavior as `java_*` rules do. ## Building from source diff --git a/WORKSPACE b/WORKSPACE index 0b06eb76b..e66f37740 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -80,3 +80,6 @@ filegroup( ) """ ) + +load("@io_bazel_rules_scala//scala:toolchains.bzl","scala_register_toolchains") +scala_register_toolchains() diff --git a/scala/BUILD b/scala/BUILD index e69de29bb..f10a1f8a4 100644 --- a/scala/BUILD +++ b/scala/BUILD @@ -0,0 +1,21 @@ +load("//scala:scala_toolchain.bzl", "scala_toolchain") + +toolchain_type( + name = "toolchain_type", + visibility = ["//visibility:public"] +) + + +scala_toolchain( + name = 'default_toolchain_impl', + scalacopts = [], + visibility = ["//visibility:public"] +) + + +toolchain( + name = 'default_toolchain', + toolchain_type = '@io_bazel_rules_scala//scala:toolchain_type', + toolchain = ':default_toolchain_impl', + visibility = ["//visibility:public"] +) diff --git a/scala/scala.bzl b/scala/scala.bzl index ed8c63c62..1dfa485ce 100644 --- a/scala/scala.bzl +++ b/scala/scala.bzl @@ -16,6 +16,8 @@ load("//specs2:specs2_junit.bzl", "specs2_junit_dependencies") load(":scala_cross_version.bzl", "scala_version", "scala_mvn_artifact") +load("@io_bazel_rules_scala//scala:scala_toolchain.bzl", "scala_toolchain") + _jar_filetype = FileType([".jar"]) _java_filetype = FileType([".java"]) _scala_filetype = FileType([".scala"]) @@ -183,6 +185,9 @@ CurrentTarget: {current_target} compiler_classpath = ":".join([j.path for j in compiler_classpath_jars]) + toolchain = ctx.toolchains['@io_bazel_rules_scala//scala:toolchain_type'] + scalacopts = toolchain.scalacopts + ctx.attr.scalacopts + scalac_args = """ Classpath: {cp} EnableIjar: {enableijar} @@ -205,7 +210,7 @@ DependencyAnalyzerMode: {dependency_analyzer_mode} """.format( out=ctx.outputs.jar.path, manifest=ctx.outputs.manifest.path, - scala_opts=",".join(ctx.attr.scalacopts), + scala_opts=",".join(scalacopts), print_compile_time=ctx.attr.print_compile_time, plugin_arg=plugin_arg, cp=compiler_classpath, @@ -963,7 +968,8 @@ scala_library = rule( implementation=_scala_library_impl, attrs=_scala_library_attrs, outputs=library_outputs, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'], ) # the scala compiler plugin used for dependency analysis is compiled using `scala_library`. @@ -978,7 +984,8 @@ scala_library_for_plugin_bootstrapping = rule( implementation=_scala_library_impl, attrs= _scala_library_for_plugin_bootstrapping_attrs, outputs=library_outputs, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'], ) _scala_macro_library_attrs = { @@ -993,7 +1000,8 @@ scala_macro_library = rule( implementation=_scala_macro_library_impl, attrs= _scala_macro_library_attrs, outputs= common_outputs, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'], ) _scala_binary_attrs = { @@ -1008,7 +1016,8 @@ scala_binary = rule( attrs= _scala_binary_attrs, outputs= common_outputs, executable=True, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'], ) _scala_test_attrs = { @@ -1030,7 +1039,8 @@ scala_test = rule( outputs= common_outputs, executable=True, test=True, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'], ) _scala_repl_attrs = {} @@ -1043,7 +1053,8 @@ scala_repl = rule( attrs= _scala_repl_attrs, outputs= common_outputs, executable=True, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'], ) SCALA_BUILD_FILE = """ @@ -1210,7 +1221,8 @@ scala_junit_test = rule( attrs= _scala_junit_test_attrs, outputs= common_outputs, test=True, - fragments = ["java"] + fragments = ["java"], + toolchains = ['@io_bazel_rules_scala//scala:toolchain_type'] ) def scala_specs2_junit_test(name, **kwargs): @@ -1220,3 +1232,4 @@ def scala_specs2_junit_test(name, **kwargs): suite_label = Label("//src/java/io/bazel/rulesscala/specs2:specs2_test_discovery"), suite_class = "io.bazel.rulesscala.specs2.Specs2DiscoveredTestSuite", **kwargs) + diff --git a/scala/scala_toolchain.bzl b/scala/scala_toolchain.bzl new file mode 100644 index 000000000..fa3ff689c --- /dev/null +++ b/scala/scala_toolchain.bzl @@ -0,0 +1,12 @@ +def _scala_toolchain_impl(ctx): + toolchain = platform_common.ToolchainInfo( + scalacopts = ctx.attr.scalacopts, + ) + return [toolchain] + +scala_toolchain = rule( + _scala_toolchain_impl, + attrs = { + 'scalacopts': attr.string_list(), + } +) \ No newline at end of file diff --git a/scala/toolchains.bzl b/scala/toolchains.bzl new file mode 100644 index 000000000..5e5f78b81 --- /dev/null +++ b/scala/toolchains.bzl @@ -0,0 +1,3 @@ + +def scala_register_toolchains(): + native.register_toolchains("@io_bazel_rules_scala//scala:default_toolchain") \ No newline at end of file diff --git a/test_expect_failure/scalacopts_from_toolchain/BUILD b/test_expect_failure/scalacopts_from_toolchain/BUILD new file mode 100644 index 000000000..4bdc92487 --- /dev/null +++ b/test_expect_failure/scalacopts_from_toolchain/BUILD @@ -0,0 +1,21 @@ +load("//scala:scala_toolchain.bzl", "scala_toolchain") +load("//scala:scala.bzl", "scala_library") + +scala_toolchain( + name = "failing_toolchain_impl", + scalacopts = ["-Ywarn-unused"], + visibility = ["//visibility:public"] +) + +toolchain( + name = "failing_scala_toolchain", + toolchain_type = "@io_bazel_rules_scala//scala:toolchain_type", + toolchain = "failing_toolchain_impl", + visibility = ["//visibility:public"] +) + +scala_library( + name = "failing_build", + srcs = ["ClassWithUnused.scala"], + scalacopts = ["-Xfatal-warnings"] +) \ No newline at end of file diff --git a/test_expect_failure/scalacopts_from_toolchain/ClassWithUnused.scala b/test_expect_failure/scalacopts_from_toolchain/ClassWithUnused.scala new file mode 100644 index 000000000..52a0d01ac --- /dev/null +++ b/test_expect_failure/scalacopts_from_toolchain/ClassWithUnused.scala @@ -0,0 +1,8 @@ +package test_expect_failure.scalacopts_from_toolchain + +class ClassWithUnused(name:String){ + def talk():String = { + val unusedValue = "I am not used :-(" + s"hello $name" + } +} \ No newline at end of file diff --git a/test_intellij_aspect.sh b/test_intellij_aspect.sh index fde665593..bb93c8d87 100755 --- a/test_intellij_aspect.sh +++ b/test_intellij_aspect.sh @@ -20,7 +20,7 @@ test_intellij_aspect() { cd intellij && git fetch && git pull fi git checkout "${intellij_git_tag}" - bazel test --test_output=errors --override_repository io_bazel_rules_scala="${rules_scala_dir}" //aspect/testing/tests/src/com/google/idea/blaze/aspect/scala/... + bazel test --test_output=errors --override_repository io_bazel_rules_scala="${rules_scala_dir}" --extra_toolchains=@io_bazel_rules_scala//scala:default_toolchain //aspect/testing/tests/src/com/google/idea/blaze/aspect/scala/... } dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) diff --git a/test_rules_scala.sh b/test_rules_scala.sh index ae80baa7f..8ebd87a38 100755 --- a/test_rules_scala.sh +++ b/test_rules_scala.sh @@ -667,6 +667,10 @@ test_scala_import_expect_failure_on_missing_direct_deps_warn_mode() { test_expect_failure_or_warning_on_missing_direct_deps_with_expected_message "${expected_message1}" ${test_target} "--strict_java_deps=warn" "ne" "${expected_message2}" } +test_scalaopts_from_scala_toolchain() { + action_should_fail build --extra_toolchains="//test_expect_failure/scalacopts_from_toolchain:failing_scala_toolchain" //test_expect_failure/scalacopts_from_toolchain:failing_build +} + dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) # shellcheck source=./test_runner.sh . "${dir}"/test_runner.sh @@ -735,3 +739,4 @@ $runner test_scala_library_expect_failure_on_missing_direct_deps_warn_mode_java $runner test_scala_library_expect_better_failure_message_on_missing_transitive_dependency_labels_from_other_jvm_rules $runner test_scala_import_expect_failure_on_missing_direct_deps_warn_mode $runner bazel build "test_expect_failure/missing_direct_deps/internal_deps/... --strict_java_deps=warn" +$runner test_scalaopts_from_scala_toolchain