Richard Levasseur | b8f1645 | 2023-07-08 09:58:12 -0700 | [diff] [blame] | 1 | # Copyright 2023 The Bazel Authors. All rights reserved. |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
Richard Levasseur | 2893d85 | 2023-02-15 20:08:22 -0800 | [diff] [blame] | 15 | """Functionality shared by multiple pieces of code.""" |
| 16 | |
Richard Levasseur | 2df3259 | 2023-05-02 09:38:02 -0700 | [diff] [blame] | 17 | load("@bazel_skylib//lib:types.bzl", "types") |
Richard Levasseur | 416bd4c | 2024-09-26 15:21:50 -0700 | [diff] [blame] | 18 | load("@rules_python_internal//:rules_python_config.bzl", "config") |
Richard Levasseur | 2df3259 | 2023-05-02 09:38:02 -0700 | [diff] [blame] | 19 | |
Richard Levasseur | 2893d85 | 2023-02-15 20:08:22 -0800 | [diff] [blame] | 20 | def copy_propagating_kwargs(from_kwargs, into_kwargs = None): |
| 21 | """Copies args that must be compatible between two targets with a dependency relationship. |
| 22 | |
| 23 | This is intended for when one target depends on another, so they must have |
| 24 | compatible settings such as `testonly` and `compatible_with`. This usually |
| 25 | happens when a macro generates multiple targets, some of which depend |
| 26 | on one another, so their settings must be compatible. |
| 27 | |
| 28 | Args: |
| 29 | from_kwargs: keyword args dict whose common kwarg will be copied. |
| 30 | into_kwargs: optional keyword args dict that the values from `from_kwargs` |
| 31 | will be copied into. The values in this dict will take precedence |
| 32 | over the ones in `from_kwargs` (i.e., if this has `testonly` already |
| 33 | set, then it won't be overwritten). |
| 34 | NOTE: THIS WILL BE MODIFIED IN-PLACE. |
| 35 | |
| 36 | Returns: |
| 37 | Keyword args to use for the depender target derived from the dependency |
| 38 | target. If `into_kwargs` was passed in, then that same object is |
| 39 | returned; this is to facilitate easy `**` expansion. |
| 40 | """ |
| 41 | if into_kwargs == None: |
| 42 | into_kwargs = {} |
| 43 | |
| 44 | # Include tags because people generally expect tags to propagate. |
| 45 | for attr in ("testonly", "tags", "compatible_with", "restricted_to"): |
| 46 | if attr in from_kwargs and attr not in into_kwargs: |
| 47 | into_kwargs[attr] = from_kwargs[attr] |
| 48 | return into_kwargs |
Richard Levasseur | 3b9c85e | 2023-03-23 12:59:58 -0700 | [diff] [blame] | 49 | |
| 50 | # The implementation of the macros and tagging mechanism follows the example |
| 51 | # set by rules_cc and rules_java. |
| 52 | |
| 53 | _MIGRATION_TAG = "__PYTHON_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__" |
| 54 | |
| 55 | def add_migration_tag(attrs): |
Richard Levasseur | 2df3259 | 2023-05-02 09:38:02 -0700 | [diff] [blame] | 56 | """Add a special tag to `attrs` to aid migration off native rles. |
| 57 | |
| 58 | Args: |
| 59 | attrs: dict of keyword args. The `tags` key will be modified in-place. |
| 60 | |
| 61 | Returns: |
| 62 | The same `attrs` object, but modified. |
| 63 | """ |
Richard Levasseur | 416bd4c | 2024-09-26 15:21:50 -0700 | [diff] [blame] | 64 | if not config.enable_pystar: |
| 65 | add_tag(attrs, _MIGRATION_TAG) |
Richard Levasseur | b8f1645 | 2023-07-08 09:58:12 -0700 | [diff] [blame] | 66 | return attrs |
| 67 | |
| 68 | def add_tag(attrs, tag): |
| 69 | """Adds `tag` to `attrs["tags"]`. |
| 70 | |
| 71 | Args: |
| 72 | attrs: dict of keyword args. It is modified in place. |
| 73 | tag: str, the tag to add. |
| 74 | """ |
Richard Levasseur | 3b9c85e | 2023-03-23 12:59:58 -0700 | [diff] [blame] | 75 | if "tags" in attrs and attrs["tags"] != None: |
Richard Levasseur | 2df3259 | 2023-05-02 09:38:02 -0700 | [diff] [blame] | 76 | tags = attrs["tags"] |
| 77 | |
| 78 | # Preserve the input type: this allows a test verifying the underlying |
| 79 | # rule can accept the tuple for the tags argument. |
| 80 | if types.is_tuple(tags): |
Richard Levasseur | b8f1645 | 2023-07-08 09:58:12 -0700 | [diff] [blame] | 81 | attrs["tags"] = tags + (tag,) |
Richard Levasseur | 2df3259 | 2023-05-02 09:38:02 -0700 | [diff] [blame] | 82 | else: |
Richard Levasseur | b8f1645 | 2023-07-08 09:58:12 -0700 | [diff] [blame] | 83 | # List concatenation is necessary because the original value |
| 84 | # may be a frozen list. |
| 85 | attrs["tags"] = tags + [tag] |
Richard Levasseur | 3b9c85e | 2023-03-23 12:59:58 -0700 | [diff] [blame] | 86 | else: |
Richard Levasseur | b8f1645 | 2023-07-08 09:58:12 -0700 | [diff] [blame] | 87 | attrs["tags"] = [tag] |
Richard Levasseur | 69abe80 | 2023-11-24 11:21:20 -0800 | [diff] [blame] | 88 | |
Richard Levasseur | 2d34f6c | 2024-09-26 04:00:51 -0700 | [diff] [blame] | 89 | # Helper to make the provider definitions not crash under Bazel 5.4: |
| 90 | # Bazel 5.4 doesn't support the `init` arg of `provider()`, so we have to |
| 91 | # not pass that when using Bazel 5.4. But, not passing the `init` arg |
| 92 | # changes the return value from a two-tuple to a single value, which then |
| 93 | # breaks Bazel 6+ code. |
| 94 | # This isn't actually used under Bazel 5.4, so just stub out the values |
| 95 | # to get past the loading phase. |
| 96 | def define_bazel_6_provider(doc, fields, **kwargs): |
| 97 | """Define a provider, or a stub for pre-Bazel 7.""" |
| 98 | if not IS_BAZEL_6_OR_HIGHER: |
| 99 | return provider("Stub, not used", fields = []), None |
| 100 | return provider(doc = doc, fields = fields, **kwargs) |
| 101 | |
Mark Elliot | f40038e | 2024-10-30 12:11:53 -0400 | [diff] [blame] | 102 | IS_BAZEL_7_4_OR_HIGHER = hasattr(native, "legacy_globals") |
| 103 | |
Richard Levasseur | 69abe80 | 2023-11-24 11:21:20 -0800 | [diff] [blame] | 104 | IS_BAZEL_7_OR_HIGHER = hasattr(native, "starlark_doc_extract") |
| 105 | |
| 106 | # Bazel 5.4 has a bug where every access of testing.ExecutionInfo is a |
| 107 | # different object that isn't equal to any other. This is fixed in bazel 6+. |
| 108 | IS_BAZEL_6_OR_HIGHER = testing.ExecutionInfo == testing.ExecutionInfo |
Ziad Shaban | 8ecad9d | 2024-01-14 09:54:22 +0100 | [diff] [blame] | 109 | |
| 110 | _marker_rule_to_detect_bazel_6_4_or_higher = rule(implementation = lambda ctx: None) |
| 111 | |
| 112 | # Bazel 6.4 and higher have a bug fix where rule names show up in the str() |
| 113 | # of a rule. See |
| 114 | # https://github.com/bazelbuild/bazel/commit/002490b9a2376f0b2ea4a37102c5e94fc50a65ba |
| 115 | # https://github.com/bazelbuild/bazel/commit/443cbcb641e17f7337ccfdecdfa5e69bc16cae55 |
| 116 | # This technique is done instead of using native.bazel_version because, |
| 117 | # under stardoc, the native.bazel_version attribute is entirely missing, which |
| 118 | # prevents doc generation from being able to correctly generate docs. |
| 119 | IS_BAZEL_6_4_OR_HIGHER = "_marker_rule_to_detect_bazel_6_4_or_higher" in str( |
| 120 | _marker_rule_to_detect_bazel_6_4_or_higher, |
| 121 | ) |