Skip to content

Commit 8158717

Browse files
authored
Provide select_for_scala_version utility macro (#1563)
* Start documenting "From config setting" section * Provide `select_for_scala_version` utility macro
1 parent 61bb9bd commit 8158717

File tree

2 files changed

+161
-1
lines changed

2 files changed

+161
-1
lines changed

cross-compilation-doc.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,69 @@ def _rule_impl(ctx):
5252
```
5353

5454
### From config setting
55-
TODO
55+
In BUILD files, you need to use the config settings with `select()`.
56+
Majority of use cases is covered by the `select_for_scala_version` utility macro.
57+
If more flexibility is needed, you can always write the select manually.
58+
59+
#### With select macro
60+
See example usage of the `select_for_scala_version`:
61+
62+
```starlark
63+
load("@io_bazel_rules_scala//:scala_cross_version_select.bzl", "select_for_scala_version")
64+
65+
scala_library(
66+
...
67+
srcs = select_for_scala_version(
68+
before_3_1 = [
69+
# for Scala version < 3.1
70+
],
71+
between_3_1_and_3_2 = [
72+
# for 3.1 ≤ Scala version < 3.2
73+
],
74+
between_3_2_and_3_3_1 = [
75+
# for 3.2 ≤ Scala version < 3.3.1
76+
],
77+
since_3_3_1 = [
78+
# for 3.3.1 ≤ Scala version
79+
],
80+
)
81+
...
82+
)
83+
```
84+
85+
See complete documentation in the [scala_cross_version_select.bzl](scala/scala_cross_version_select.bzl) file
86+
87+
#### Manually
88+
An example usage of `select()` to provide custom dependency for specific Scala version:
89+
```starlark
90+
deps = select({
91+
"@io_bazel_rules_scala_config//:scala_version_3_3_1": [...],
92+
...
93+
})
94+
```
95+
96+
For more complex logic, you can extract it to a `.bzl` file:
97+
```starlark
98+
def srcs(scala_version):
99+
if scala_version.startswith("2"):
100+
...
101+
...
102+
```
103+
and then in the `BUILD` file:
104+
```starlark
105+
load("@io_bazel_rules_scala//:scala_cross_version.bzl", "version_suffix")
106+
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
107+
load("....bzl", "srcs")
108+
109+
scala_library(
110+
...
111+
srcs = select({
112+
"@io_bazel_rules_scala_config//:scala_version" + version_suffix(v): srcs(v)
113+
for v in SCALA_VERSIONS
114+
}),
115+
...
116+
)
117+
```
56118

57119

58120
## Toolchains
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
load("@io_bazel_rules_scala_config//:config.bzl", "SCALA_VERSIONS")
2+
load(":scala_cross_version.bzl", "version_suffix")
3+
4+
def select_for_scala_version(default = [], **kwargs):
5+
"""
6+
User-friendly macro replacement for select() conditioned on Scala versions.
7+
8+
Example usage:
9+
```
10+
srcs = select_for_scala_version(
11+
before_3_1 = [
12+
# for Scala version < 3.1
13+
],
14+
between_3_1_and_3_2 = [
15+
# for 3.1 ≤ Scala version < 3.2
16+
],
17+
between_3_2_and_3_3_1 = [
18+
# for 3.2 ≤ Scala version < 3.3.1
19+
],
20+
since_3_3_1 = [
21+
# for 3.3.1 ≤ Scala version
22+
],
23+
)
24+
```
25+
26+
This function parses the provided keyword argument names.
27+
Each argument name starts with the matcher name and is followed by matcher argument (the version to compare against).
28+
All versions must have their "." replaced with "_".
29+
30+
Available matchers:
31+
* `before`, `after` – that will match any version strictly lower / strictly greater than provided;
32+
* `until`, `since` – that will match any version lower or equal / greater or equal than provided;
33+
* `any` – that will match any version equal to provided;
34+
* `between` – requires two versions separated by `_and_`, combines `since` and `before`.
35+
36+
If only a part of a version, e.g. "2.13", is provided, the remaining part will be ignored during comparison.
37+
Therefore "any_2" is interpreted as a wildcard "2.*.*".
38+
39+
Unlike the traditional `select()`, all matches will be respected.
40+
`default` is applied for versions not matched by any matcher.
41+
"""
42+
43+
return select({
44+
"@io_bazel_rules_scala_config//:scala_version" + version_suffix(scala_version): _matches_for_version(scala_version, kwargs, default)
45+
for scala_version in SCALA_VERSIONS
46+
})
47+
48+
def _matches_for_version(scala_version, kwargs, default_value):
49+
matches = []
50+
default = True
51+
for matcher, value in kwargs.items():
52+
matcher_name, matcher_args = matcher.split("_", 1)
53+
matcher_args = matcher_args.split("_and_")
54+
if _MATCHERS[matcher_name](scala_version, *matcher_args):
55+
matches.extend(value)
56+
default = False
57+
if default:
58+
matches.extend(default_value)
59+
return matches
60+
61+
def _match_one_arg(scala_version, matcher_scala_version, compare):
62+
# Some rudimentary version parsing to allow a lexicographical compare later.
63+
# Works for versions containing numbers only.
64+
scala_version = tuple([int(x) for x in scala_version.split(".")])
65+
matcher_scala_version = tuple([int(x) for x in matcher_scala_version.split("_")])
66+
67+
# Compare only a part of version – to allow wildcarding.
68+
return compare(scala_version[:len(matcher_scala_version)], matcher_scala_version)
69+
70+
def _build_matcher(compare):
71+
def matcher(scala_version, matcher_scala_version):
72+
return _match_one_arg(scala_version, matcher_scala_version, compare)
73+
74+
return matcher
75+
76+
_match_any = _build_matcher(lambda x, y: x == y)
77+
_match_before = _build_matcher(lambda x, y: x < y)
78+
_match_after = _build_matcher(lambda x, y: x > y)
79+
_match_until = _build_matcher(lambda x, y: x <= y)
80+
_match_since = _build_matcher(lambda x, y: x >= y)
81+
82+
def _match_between(scala_version, since_scala_version, until_scala_version):
83+
return _match_since(scala_version, since_scala_version) and \
84+
_match_before(scala_version, until_scala_version)
85+
86+
_MATCHERS = {
87+
# Exclusive matchers:
88+
"before": _match_before,
89+
"after": _match_after,
90+
91+
# Inclusive matchers:
92+
"any": _match_any,
93+
"until": _match_until,
94+
"since": _match_since,
95+
96+
# Mixed matchers:
97+
"between": _match_between, # (inclusive-exclusive)
98+
}

0 commit comments

Comments
 (0)