-
-
Notifications
You must be signed in to change notification settings - Fork 288
Add toolchain options API to WORKSPACE and Bzlmod #1730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add toolchain options API to WORKSPACE and Bzlmod #1730
Conversation
5e15e88 to
d30ddbb
Compare
|
@meteorcloudy I've noticed the cla/google check hanging today when pushing commits to this branch. Is this a consequence of the move to the bazel-contrib org? |
82e3f4e to
6588c32
Compare
|
@alexeagle took off the cla/google check, since the bazel-contrib org doesn't require it, so that's no longer blocking anything. @simuons Separate from this pull request, I've continued to experiment a bit with generating toolchains from the module extension in the new bzlmod-toolchains-experiment branch of mbland/rules_scala. I've managed to generate a separate toolchain in This confirms that, after this pull request lands, and after the new release, we can indeed expand the tag classes to pass through more parameters and/or generate new toolchains in |
Updates `scala_toolchains()` to accept either boolean or dict arguments for specific toolchains, and updates `//scala/extensions:deps.bzl` to generate them from tag classes. Part of bazel-contrib#1482. Notable qualities: - Adds toolchain options support to the `scala_toolchains()` parameters `scalafmt`, `scala_proto`, and `twitter_scrooge`, and to the `scalafmt` tag class. - Eliminates the `scalafmt_default_config`, `scala_proto_options`, and `twitter_scrooge_deps` option parameters from `scala_toolchains()`. - Provides uniform, strict evaluation and validation of toolchain options passed to `scala_toolchains()`. - Configures enabled toolchains using root module settings or the default toolchain settings only. - Introduces the shared `TOOLCHAIN_DEFAULTS` dict in `//scala/private:toolchains_defaults.bzl` to aggregate individual `TOOLCHAIN_DEFAULTS` macro parameter dicts. This change also: - Replaces the non-dev dependency `scala_deps.scala()` tag instantiation in `MODULE.bazel` with `dev_deps.scala()`. - Renames the `options` parameter of the `scala_deps.scala_proto` tag class to `default_gen_opts` to match `setup_scala_proto_toolchain()`. - Introduces `_stringify_args()` to easily pass all toolchain macro args compiled from `scala_toolchains_repo()` attributes through to the generated `BUILD` file. - Extracts `_DEFAULT_TOOLCHAINS_REPO_NAME` and removes the `scala_toolchains_repo()` macro. - Includes docstrings for the new private implementation functions, and updates all other docstrings, `README.md`, and other relevant documentation accordingly. --- Inspired by @simuons's suggestion to replace toolchain macros with a module extension in: - bazel-contrib#1722 (comment) Though a full replacement is a ways off, this is a step in that direction that surfaced several immediate improvements. First, extensibility and maintainability: - The new implementation enables adding options support for other toolchains in the future while maintaining backward compatibility, for both the `WORKSPACE` and Bzlmod APIs. Adding this support will only require a minor release, not a major one. - The `scala_deps` module extension implementation is easier to read, since all toolchains now share the `_toolchain_settings` mechanism. Next, improved consistency of the API and implementation: - Toolchain options parameters should present all the same parameters as the macros to which they correspond, ensured by the `TOOLCHAIN_DEFAULTS` mechanism. This is to make it easier for users and maintainers to see the direct relationship between these separate sets of parameters. (They can also define additional parameters to those required by the macro, like `default_config` from the `scalafmt` options.) This principle drove the renaming of the `scala_deps.scala_proto` tag class parameter from `options` to `default_gen_opts`. It also inspired updating `scala_toolchains_repo()` to pass toolchain options through `_stringify_args()` to generate `BUILD` macro arguments. - The consolidated `TOOLCHAIN_DEFAULTS` dict reduces duplication between the `scala/extensions/deps.bzl` and `scala/toolchains.bzl` files. It ensures consistency between tag class `attr` default values for Bzlmod users and the `scala_toolchains()` default parameter values for `WORKSPACE` users. The `TOOLCHAINS_DEFAULTS` dicts corresponding to each toolchain macro do duplicate the information in the macro argument lists. However, the duplicated values in this case are physically adjacent to one another, minimizing the risk of drift. - Extracting `_DEFAULT_TOOLCHAINS_REPO_NAME` is a step towards enabling customized repositories based on the builtin toolchains, while specifying different options. This extraction revealed the fact that the `scala_toolchains_repo()` macro was no longer necessary, since only `scala_toolchains()` ever called it. Finally, fixes for the following design bugs: - Previously, `scala_deps.scala_proto(options = [...])` compiled the list of `default_gen_opts` from all tag instances in the module graph. This might've been convenient, but didn't generalize to other options for other toolchains. In particular, it differed from the previous `toolchains`, `scalafmt`, and `twitter_scrooge` tag class behavior. The new semantics are unambiguous, consistent, and apply to all toolchains equally; they do not show a preference for any one toolchain over the others. They also maintain the existing `scalafmt` and `twitter_scrooge` tag class semantics, but now using a generic mechanism, simplifying the implementation. - Instantating `scala_deps.scala()` was a bug left over from the decision in bazel-contrib#1722 _not_ to enable the builtin Scala toolchain by default under Bzlmod. The previous `scala_deps.toolchains()` tag class had a default `scala = True` parameter. The user could set `scala = False` to disable the builtin Scala toolchain. After replacing `toolchains()` with individual tag classes, the documented behavior was that the user must enable the builtin Scala toolchain by instantiating `scala_deps.scala()`. By instantiating `scala_deps.scala()` in our own `MODULE.bazel` file, we ensured that `rules_scala` would always instantiate the builtin Scala toolchain. While relatively harmless, it violated the intention of allowing the user to avoid instantiating the toolchain altogether.
Touched up documentation for the `scalafmt` and `scala_proto` toolchains.
This avoids the need for the user to use `exports_files` so `@rules_scala_toolchains//scalafmt:config` can access the config file. Essentially restores the API from before bazel-contrib#1725, but still fixes the same bug as bazel-contrib#1725.
Updates the Scalafmt documentation to reflect the current API. Adds a check to `scala_toolchains_repo` to `fail` if the Scalafmt `default_config` file doesn't exist. The previous commit doesn't actually restore the exact pre-bazel-contrib#1725 API. It eliminates the `exports_files` requirement, but still requires a `Label` or a relative path string, not an optional `.scalafmt.conf` in the root directory. After experimenting a bit and thinking this through, dropping support for an optional `.scalafmt.conf` provides the most robust and reliable interface. Specifically, supporting it requires detecting whether it actually exists before falling back to the default. Having users explicitly specify their own config seems a small burden to impose for a more straightforward and correct implementation. At the same time, I saw the opportunity to provide the user with explicit feedback if the specified config file doesn't exist. Hence the new check and `fail()` message. Also renamed the generated `.scalafmt.conf` file in `@rules_scala_toolchains//scalafmt` to `scalafmt.conf`. No need for it to be a hidden file in that context.
The `scala_deps` docstring now more accurately describes the behavior implemented by `_toolchain_settings()`.
6588c32 to
47d2d58
Compare
Caught this after doing an `--enable_workspace --noenable_bzlmod` build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @mbland
Makes it clear that `WORKSPACE` users must use a target `Label` string with the `default_config` option for the `scalafmt` argument of `scala_toolchains`. Notes that the specified config file must exist within a package, including but not limited to having a `BUILD` file in the repository root. --- @gergelyfabian noticed this while building gergelyfabian/bazel-scala-example after bazel-contrib#1730 landed. This isn't fixable in code. With this call: ```py scala_toolchains( # Other toolchains... scalafmt = {"default_config": ".scalafmt.conf"}, ) ``` - `scala_toolchains` looks for the file under `external/.scalafmt.conf`. - Updating `scala_toolchains` to wrap `default_config` in a `Label` makes it relative to `@rules_scala//scala`. This because `scala_toolchains` resides in `@rules_scala//scala:toolchains.bzl`. - `native.package_relative_label` is only available when called from a `BUILD` file. Hence `default_config` values under `WORKSPACE` must be valid target labels. The problem doesn't exist under Bzlmod; plain file paths will work fine, so long as a `BUILD` file exists at the repository root.
Makes it clear that `WORKSPACE` users must use a target `Label` string with the `default_config` option for the `scalafmt` argument of `scala_toolchains`. Notes that the specified config file must exist within a package, including but not limited to having a `BUILD` file in the repository root. --- @gergelyfabian noticed this while building gergelyfabian/bazel-scala-example after #1730 landed. This isn't fixable in code. With this call: ```py scala_toolchains( # Other toolchains... scalafmt = {"default_config": ".scalafmt.conf"}, ) ``` - `scala_toolchains` looks for the file under `external/.scalafmt.conf`. - Updating `scala_toolchains` to wrap `default_config` in a `Label` makes it relative to `@rules_scala//scala`. This because `scala_toolchains` resides in `@rules_scala//scala:toolchains.bzl`. - `native.package_relative_label` is only available when called from a `BUILD` file. Hence `default_config` values under `WORKSPACE` must be valid target labels. The problem doesn't exist under Bzlmod; plain file paths will work fine, so long as a `BUILD` file exists at the repository root.
Description
Updates
scala_toolchains()to accept either boolean or dict arguments for specific toolchains, and updates//scala/extensions:deps.bzlto generate them from tag classes. Part of #1482.Notable qualities:
Adds toolchain options support to the
scala_toolchains()parametersscalafmt,scala_proto, andtwitter_scrooge, and to thescalafmttag class.Eliminates the
scalafmt_default_config,scala_proto_options, andtwitter_scrooge_depsoption parameters fromscala_toolchains().Provides uniform, strict evaluation and validation of toolchain options passed to
scala_toolchains().Configures enabled toolchains using root module settings or the default toolchain settings only.
Introduces the shared
TOOLCHAIN_DEFAULTSdict in//scala/private:toolchains_defaults.bzlto aggregate individualTOOLCHAIN_DEFAULTSmacro parameter dicts.This change also:
Replaces the non-dev dependency
scala_deps.scala()tag instantiation inMODULE.bazelwithdev_deps.scala().Renames the
optionsparameter of thescala_deps.scala_prototag class todefault_gen_optsto matchsetup_scala_proto_toolchain().Introduces
_stringify_args()to easily pass all toolchain macro args compiled fromscala_toolchains_repo()attributes through to the generatedBUILDfile.Extracts
_DEFAULT_TOOLCHAINS_REPO_NAMEand removes thescala_toolchains_repo()macro.Includes docstrings for the new private implementation functions, and updates all other docstrings,
README.md, and other relevant documentation accordingly.Motivation
Inspired by @simuons's suggestion to replace toolchain macros with a module extension in:
Though a full replacement is a ways off, this is a step in that direction that surfaced several immediate improvements.
First, extensibility and maintainability:
The new implementation enables adding options support for other toolchains in the future while maintaining backward compatibility, for both the
WORKSPACEand Bzlmod APIs. Adding this support will only require a minor release, not a major one.The
scala_depsmodule extension implementation is easier to read, since all toolchains now share the_toolchain_settingsmechanism.Next, improved consistency of the API and implementation:
Toolchain options parameters should present all the same parameters as the macros to which they correspond, ensured by the
TOOLCHAIN_DEFAULTSmechanism. This is to make it easier for users and maintainers to see the direct relationship between these separate sets of parameters. (They can also define additional parameters to those required by the macro, likedefault_configfrom thescalafmtoptions.)This principle drove the renaming of the
scala_deps.scala_prototag class parameter fromoptionstodefault_gen_opts. It also inspired updatingscala_toolchains_repo()to pass toolchain options through_stringify_args()to generateBUILDmacro arguments.The consolidated
TOOLCHAIN_DEFAULTSdict reduces duplication between thescala/extensions/deps.bzlandscala/toolchains.bzlfiles. It ensures consistency between tag classattrdefault values for Bzlmod users and thescala_toolchains()default parameter values forWORKSPACEusers.The
TOOLCHAINS_DEFAULTSdicts corresponding to each toolchain macro do duplicate the information in the macro argument lists. However, the duplicated values in this case are physically adjacent to one another, minimizing the risk of drift.Extracting
_DEFAULT_TOOLCHAINS_REPO_NAMEis a step towards enabling customized repositories based on the builtin toolchains, while specifying different options. This extraction revealed the fact that thescala_toolchains_repo()macro was no longer necessary, since onlyscala_toolchains()ever called it.Finally, fixes for the following design bugs:
Previously,
scala_deps.scala_proto(options = [...])compiled the list ofdefault_gen_optsfrom all tag instances in the module graph. This might've been convenient, but didn't generalize to other options for other toolchains. In particular, it differed from the previoustoolchains,scalafmt, andtwitter_scroogetag class behavior.The new semantics are unambiguous, consistent, and apply to all toolchains equally; they do not show a preference for any one toolchain over the others. They also maintain the existing
scalafmtandtwitter_scroogetag class semantics, but now using a generic mechanism, simplifying the implementation.Instantating
scala_deps.scala()was a bug left over from the decision in Enable Bzlmod #1722 not to enable the builtin Scala toolchain by default under Bzlmod.The previous
scala_deps.toolchains()tag class had a defaultscala = Trueparameter. The user could setscala = Falseto disable the builtin Scala toolchain. After replacingtoolchains()with individual tag classes, the documented behavior was that the user must enable the builtin Scala toolchain by instantiatingscala_deps.scala().By instantiating
scala_deps.scala()in our ownMODULE.bazelfile, we ensured thatrules_scalawould always instantiate the builtin Scala toolchain. While relatively harmless, it violated the intention of allowing the user to avoid instantiating the toolchain altogether.