|
| 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