kythe.io@v0.0.68-0.20240422202219-7225dbc01741/tools/build_rules/extra_aspects/actions.bzl (about) 1 # Copyright 2023 The Kythe 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 15 """Starlark utilities for selecting actions.""" 16 17 load("@bazel_skylib//lib:sets.bzl", "sets") 18 19 def select_target_actions(target, rule, config): 20 """Given a target and a rule, finds actions matching the specified config. 21 22 Args: 23 target: The Target object provided to an aspect implementation. 24 rule: The rule_attributes from an aspect's ctx.rule parameter. 25 config: A KytheActionSelectionInfo instance, configuring action selection. 26 27 Returns: 28 A list of actions selected by the provided configuration. 29 """ 30 actions = [] 31 if sets.length(config.rules) == 0 or sets.contains(config.rules, rule.kind): 32 actions.extend(_filter_actions(target.actions, config.mnemonics, config.exclude_input_extensions)) 33 for attr in config.aspect_rule_attrs.get(rule.kind, []): 34 for dep in getattr(rule.attr, attr, []): 35 # {lang}_proto_library targets are implemented as aspects 36 # with a single "dep" pointing at original proto_library target. 37 # All of the actions come from the aspect as applied to the dep, 38 # which is not a top-level dep, so we need to inspect those as well. 39 # TODO(shahms): It would be nice if there was some way to tell whether or 40 # not an action came from an aspect or the underlying rule. We could then 41 # more generally inspect deps to find actions rather than limiting it to 42 # allowlisted kinds. 43 # This could be accomplished by having `aspect_ids` populated on deps. 44 # We could look specifically for "<merged target" in the string-ified dep, 45 # but that's pretty ugly. 46 # It looks like adding an "aspect_ids" list attribute should be straightforward. 47 # https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java#L54 48 # It could also just use ActionOwner information. 49 if str(dep).startswith("<merged target") and hasattr(dep, "actions"): 50 actions.extend(_filter_actions(dep.actions, config.mnemonics, config.exclude_input_extensions)) 51 return actions 52 53 def config(rules, aspect_rule_attrs, mnemonics, exclude_input_extensions): 54 """Create an action selection config. 55 56 Args: 57 rules: A Skylib set of rule kinds from which to select actions. 58 aspect_rule_attrs: A dict of {kind: [attrs]} of rule kind attributes from which to select actions. 59 mnemonics: A Skylib set of action mnemonics to select. 60 exclude_input_extensions: A Skylib set of file extensions to whose actions to exclude. 61 62 Returns: 63 A struct with corresponding attributes. 64 """ 65 return struct( 66 rules = rules, 67 aspect_rule_attrs = aspect_rule_attrs, 68 mnemonics = mnemonics, 69 exclude_input_extensions = exclude_input_extensions, 70 ) 71 72 def _has_extension(inputs, extensions): 73 if not extensions or sets.length(extensions) == 0: 74 return False 75 for input in inputs.to_list(): 76 if sets.contains(extensions, input.extension): 77 return True 78 return False 79 80 def _filter_actions(actions, mnemonics, exclude_extensions = None): 81 return [ 82 a 83 for a in actions 84 if sets.contains(mnemonics, a.mnemonic) and 85 not _has_extension(a.inputs, exclude_extensions) 86 ]