Skip to main content
Glama
common.bzl11.6 kB
# Copyright (c) Meta Platforms, Inc. and affiliates. # # This source code is licensed under both the MIT license found in the # LICENSE-MIT file in the root directory of this source tree and the Apache # License, Version 2.0 found in the LICENSE-APACHE file in the root directory # of this source tree. load("@prelude//:asserts.bzl", "asserts") load(":asserts.bzl", "verify_normalized_modifier") load( ":types.bzl", "ConditionalModifierInfo", "Modifier", "ModifierBuckconfigLocation", "ModifierCliLocation", "ModifierInfo", "ModifierLocation", "ModifierPackageLocation", "ModifierTargetLocation", "ModifiersMatchInfo", "TaggedModifiers", "is_modifiers_match", ) MODIFIER_METADATA_KEY = "buck.cfg_modifiers" _TARGET_LOCATION_STR = "`metadata` attribute of target" _CLI_LOCATION_STR = "command line" def location_to_string(location: ModifierLocation) -> str: if isinstance(location, ModifierPackageLocation): return location.package_path if isinstance(location, ModifierTargetLocation): return _TARGET_LOCATION_STR if isinstance(location, ModifierCliLocation): return _CLI_LOCATION_STR if isinstance(location, ModifierBuckconfigLocation): return "buckconfig {}.{}".format(location.section, location.property) fail("Internal error. Unrecognized location type `{}` for location `{}`".format(type(location), location)) def get_tagged_modifiers( cfg_modifiers: list[Modifier], extra_cfg_modifiers_per_rule: dict[str, list[Modifier]], location: ModifierLocation) -> list[TaggedModifiers]: for modifier in cfg_modifiers: verify_normalized_modifier(modifier) for _, modifiers in extra_cfg_modifiers_per_rule.items(): for modifier in modifiers: verify_normalized_modifier(modifier) # Aggreggate all tagged modifiers in a PACKAGE in a single list. # Per-rule modifiers come the global modifiers so that they are processed later. return [ TaggedModifiers( modifiers = cfg_modifiers, location = location, rule_name = None, ), ] + [ TaggedModifiers( modifiers = modifiers, location = location, rule_name = rule_name, ) for rule_name, modifiers in extra_cfg_modifiers_per_rule.items() ] def get_constraint_setting(constraint_settings: dict[TargetLabel, None], modifier: Modifier, location: ModifierLocation) -> TargetLabel: if len(constraint_settings) == 0: fail("`modifiers.match` cannot be empty. Found empty `modifiers.match` at `{}`".format(location_to_string(location))) if len(constraint_settings) > 1: fail( "A single modifier can only modify a single constraint setting.\n" + "Modifier `{}` from `{}` is found to modify the following constraint settings:\n".format( modifier, location_to_string(location), ) + "\n".join([str(k) for k in constraint_settings.keys()]), ) return list(constraint_settings.keys())[0] def get_modifier_info( refs: dict[str, ProviderCollection], modifier: Modifier, location: ModifierLocation) -> ((TargetLabel, ModifierInfo) | None): # Gets a modifier info from a modifier based on providers from `refs`. if modifier == None: return None if is_modifiers_match(modifier): default = None modifiers_match_info = [] constraint_settings = {} # Used like a set for key, sub_modifier in modifier.items(): if key == "DEFAULT": if sub_modifier: default_constraint_setting, default = get_modifier_info(refs, sub_modifier, location) constraint_settings[default_constraint_setting] = None else: default = None elif key != "_type": cfg_info = refs[key][ConfigurationInfo] if sub_modifier: sub_constraint_setting, sub_modifier_info = get_modifier_info(refs, sub_modifier, location) constraint_settings[sub_constraint_setting] = None else: sub_modifier_info = None modifiers_match_info.append((cfg_info, sub_modifier_info)) constraint_setting = get_constraint_setting(constraint_settings, modifier, location) return constraint_setting, ModifiersMatchInfo( default = default, selector = modifiers_match_info, ) if isinstance(modifier, str): modifier_info = refs[modifier] if ConditionalModifierInfo in modifier_info: conditional_modifier_info = modifier_info[ConditionalModifierInfo] return conditional_modifier_info.key, conditional_modifier_info.inner cfg_info = modifier_info[ConfigurationInfo] asserts.true(len(cfg_info.constraints) == 1, "Modifier should only be a single constraint value. Found multiple or none in `{}`".format(modifier)) constraint_value_info = list(cfg_info.constraints.values())[0] return constraint_value_info.setting.label, constraint_value_info fail("Internal error: Found unexpected modifier `{}` type `{}`".format(modifier, type(modifier))) def _is_subset(a: ConfigurationInfo, b: ConfigurationInfo) -> bool: for (constraint_setting, a_constraint_value) in a.constraints.items(): b_constraint_value = b.constraints.get(constraint_setting) if a_constraint_value != b_constraint_value: return False return True def resolve_modifier(cfg: ConfigurationInfo, modifier: ModifierInfo) -> ConstraintValueInfo | None: # Resolve the modifier and return the constraint value to add to the configuration, if there is one if modifier == None: return None if isinstance(modifier, ModifiersMatchInfo): for key, sub_modifier in modifier.selector: if _is_subset(key, cfg): # If constraints in key of the select are a subset of the constraints in the # current configuration, then it's a match. return resolve_modifier(cfg, sub_modifier) if modifier.default: return resolve_modifier(cfg, modifier.default) return None if isinstance(modifier, ConstraintValueInfo): return modifier fail("Internal error: Found unexpected modifier `{}` type `{}`".format(modifier, type(modifier))) def modifier_to_refs(modifier: Modifier, location: ModifierLocation) -> list[str]: # Obtain a list of targets to analyze from a modifier. refs = [] if modifier == None: pass elif is_modifiers_match(modifier): for key, sub_modifier in modifier.items(): if key != "_type": if key != "DEFAULT": refs.append(key) refs.extend(modifier_to_refs(sub_modifier, location)) elif isinstance(modifier, str): refs.append(modifier) else: fail("Internal error: Found unexpected modifier `{}` type `{}`".format(modifier, type(modifier))) return refs def tagged_modifiers_to_json(tagged_modifiers: TaggedModifiers) -> dict[str, typing.Any]: return { "location": _location_to_json(tagged_modifiers.location), "modifiers": tagged_modifiers.modifiers, "rule_name": tagged_modifiers.rule_name, "_type": "TaggedModifiers", } def _location_to_json(location: ModifierLocation) -> dict[str, str]: if isinstance(location, ModifierPackageLocation): return {"package_path": location.package_path, "_type": "ModifierPackageLocation"} if isinstance(location, ModifierTargetLocation): return {"_type": "ModifierTargetLocation"} fail("Internal error: unknown location `{}` with type `{}`".format(location, type(location))) def json_to_tagged_modifiers(j: dict[str, typing.Any]) -> TaggedModifiers: if j["_type"] != "TaggedModifiers": fail("Internal error: `{}` is not a `TaggedModifiers`".format(j)) return TaggedModifiers( location = _json_to_location(j["location"]), modifiers = j["modifiers"], rule_name = j["rule_name"], ) def _json_to_location(j: dict[str, str]) -> ModifierLocation: modifier_type = j.pop("_type") if modifier_type == "ModifierPackageLocation": return ModifierPackageLocation(package_path = j["package_path"]) if modifier_type == "ModifierTargetLocation": return ModifierTargetLocation() fail("Internal error: cannot deserialize location `{}`".format(j)) def resolve_alias(modifier: Modifier, aliases: struct) -> list[Modifier]: if isinstance(modifier, ModifiersMatchInfo): fail("It should not be possible to specify a conditional modifier from command line") if ":" in modifier: # This is a target and not an alias return [modifier] resolved = getattr(aliases, modifier, None) if resolved: return resolved if isinstance(resolved, list) else [resolved] fail("Found invalid modifier alias `{}`. A list of valid modifier aliases is in buck2/cfg/experimental/alias.bzl".format(modifier)) def _get_constraint_setting_deps( modifier_info: ModifierInfo) -> list[TargetLabel]: deps = [] if isinstance(modifier_info, ModifiersMatchInfo): for key, sub_modifier in modifier_info.selector: for constraint_setting in key.constraints: deps.append(constraint_setting) deps += _get_constraint_setting_deps(sub_modifier) if modifier_info.default: deps += _get_constraint_setting_deps(modifier_info.default) return deps def get_constraint_setting_deps( modifier_info: ModifierInfo) -> list[TargetLabel]: # Get all constraint settings depended on by a modifier (from keys of `modifier_select`). The modifiers # for these constraint settings must be resolved before this modifier can be resolved. return dedupe(_get_constraint_setting_deps(modifier_info)) def add_to_constraint_setting_to_modifier_infos( constraint_setting_to_modifier_infos: dict[TargetLabel, list[ModifierInfo]], constraint_setting_label: TargetLabel, modifier_info: ModifierInfo): modifier_infos = constraint_setting_to_modifier_infos.get(constraint_setting_label) or [] modifier_infos.append(modifier_info) constraint_setting_to_modifier_infos[constraint_setting_label] = modifier_infos def get_and_insert_modifier_info( constraint_setting_to_modifier_infos: dict[TargetLabel, list[ModifierInfo]], refs: dict[str, ProviderCollection], modifier: Modifier, location: ModifierLocation) -> (TargetLabel, ModifierInfo): constraint_setting_label, modifier_info = get_modifier_info( refs = refs, modifier = modifier, location = location, ) add_to_constraint_setting_to_modifier_infos(constraint_setting_to_modifier_infos, constraint_setting_label, modifier_info) return (constraint_setting_label, modifier_info) def apply_buckconfig_backed_modifiers( constraint_setting_to_modifier_infos: dict[TargetLabel, list[ModifierInfo]], modifiers: list[ConditionalModifierInfo]): for conditional_modifier_info in modifiers: add_to_constraint_setting_to_modifier_infos( constraint_setting_to_modifier_infos = constraint_setting_to_modifier_infos, constraint_setting_label = conditional_modifier_info.key, modifier_info = conditional_modifier_info.inner, )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server