async def addresses_with_origins_from_address_specs( address_mapper: AddressMapper, address_specs: AddressSpecs) -> AddressesWithOrigins: """Given an AddressMapper and list of AddressSpecs, return matching AddressesWithOrigins. :raises: :class:`ResolveError` if there were no matching AddressFamilies or no targets were matched. """ # Snapshot all BUILD files covered by the AddressSpecs, then group by directory. snapshot = await Get( Snapshot, PathGlobs, address_specs.to_path_globs( build_patterns=address_mapper.build_patterns, build_ignore_patterns=address_mapper.build_ignore_patterns, ), ) dirnames = {os.path.dirname(f) for f in snapshot.files} address_families = await MultiGet( Get(AddressFamily, Dir(d)) for d in dirnames) address_family_by_directory = {af.namespace: af for af in address_families} matched_addresses: OrderedSet[Address] = OrderedSet() addr_to_origin: Dict[Address, AddressSpec] = {} for address_spec in address_specs: # These may raise ResolveError, depending on the type of spec. addr_families_for_spec = address_spec.matching_address_families( address_family_by_directory) addr_target_pairs_for_spec = address_spec.matching_addresses( addr_families_for_spec) if isinstance(address_spec, SingleAddress) and not addr_target_pairs_for_spec: addr_family = assert_single_element(addr_families_for_spec) raise _did_you_mean_exception(addr_family, address_spec.name) for addr, _ in addr_target_pairs_for_spec: # A target might be covered by multiple specs, so we take the most specific one. addr_to_origin[addr] = AddressSpecs.more_specific( addr_to_origin.get(addr), address_spec) matched_addresses.update( addr for (addr, tgt) in addr_target_pairs_for_spec if (address_specs.filter_by_global_options is False or address_mapper.matches_filter_options(addr, tgt))) return AddressesWithOrigins( AddressWithOrigin(address=addr, origin=addr_to_origin[addr]) for addr in matched_addresses)
async def addresses_with_origins_from_address_specs( address_specs: AddressSpecs, global_options: GlobalOptions, specs_filter: AddressSpecsFilter ) -> AddressesWithOrigins: """Given an AddressMapper and list of AddressSpecs, return matching AddressesWithOrigins. :raises: :class:`ResolveError` if the provided specs fail to match targets, and those spec types expect to have matched something. """ matched_addresses: OrderedSet[Address] = OrderedSet() addr_to_origin: Dict[Address, AddressSpec] = {} filtering_disabled = address_specs.filter_by_global_options is False # First convert all `AddressLiteralSpec`s. Some of the resulting addresses may be file # addresses. This will raise an exception if any of the addresses are not valid. literal_addresses = await MultiGet( Get(Address, AddressInput(spec.path_component, spec.target_component)) for spec in address_specs.literals ) literal_target_adaptors = await MultiGet( Get(TargetAdaptor, Address, addr.maybe_convert_to_base_target()) for addr in literal_addresses ) # We convert to targets for the side effect of validating that any file addresses actually # belong to the specified base targets. await Get( UnexpandedTargets, Addresses(addr for addr in literal_addresses if not addr.is_base_target) ) for literal_spec, addr, target_adaptor in zip( address_specs.literals, literal_addresses, literal_target_adaptors ): addr_to_origin[addr] = literal_spec if filtering_disabled or specs_filter.matches(addr, target_adaptor): matched_addresses.add(addr) # Then, convert all `AddressGlobSpecs`. Snapshot all BUILD files covered by the specs, then # group by directory. snapshot = await Get( Snapshot, PathGlobs, address_specs.to_path_globs( build_patterns=global_options.options.build_patterns, build_ignore_patterns=global_options.options.build_ignore, ), ) dirnames = {os.path.dirname(f) for f in snapshot.files} address_families = await MultiGet(Get(AddressFamily, Dir(d)) for d in dirnames) address_family_by_directory = {af.namespace: af for af in address_families} for glob_spec in address_specs.globs: # These may raise ResolveError, depending on the type of spec. addr_families_for_spec = glob_spec.matching_address_families(address_family_by_directory) addr_target_pairs_for_spec = glob_spec.matching_addresses(addr_families_for_spec) for addr, _ in addr_target_pairs_for_spec: # A target might be covered by multiple specs, so we take the most specific one. addr_to_origin[addr] = AddressSpecs.more_specific(addr_to_origin.get(addr), glob_spec) matched_addresses.update( addr for (addr, tgt) in addr_target_pairs_for_spec if filtering_disabled or specs_filter.matches(addr, tgt) ) return AddressesWithOrigins( AddressWithOrigin(address=addr, origin=addr_to_origin[addr]) for addr in matched_addresses )
def test_address_specs_more_specific() -> None: literal_addr = AddressLiteralSpec(path_component="foo/bar", target_component="baz") sibling_addresses = SiblingAddresses(directory="foo/bar") ascendant_addresses = AscendantAddresses(directory="foo/bar") descendant_addresses = DescendantAddresses(directory="foo/bar") assert literal_addr == AddressSpecs.more_specific(literal_addr, None) assert literal_addr == AddressSpecs.more_specific(literal_addr, sibling_addresses) assert literal_addr == AddressSpecs.more_specific(literal_addr, ascendant_addresses) assert literal_addr == AddressSpecs.more_specific(literal_addr, descendant_addresses) assert literal_addr == AddressSpecs.more_specific(None, literal_addr) assert literal_addr == AddressSpecs.more_specific(sibling_addresses, literal_addr) assert literal_addr == AddressSpecs.more_specific(ascendant_addresses, literal_addr) assert literal_addr == AddressSpecs.more_specific(descendant_addresses, literal_addr) assert sibling_addresses == AddressSpecs.more_specific( sibling_addresses, None) assert sibling_addresses == AddressSpecs.more_specific( sibling_addresses, ascendant_addresses) assert sibling_addresses == AddressSpecs.more_specific( sibling_addresses, descendant_addresses) assert sibling_addresses == AddressSpecs.more_specific( None, sibling_addresses) assert sibling_addresses == AddressSpecs.more_specific( ascendant_addresses, sibling_addresses) assert sibling_addresses == AddressSpecs.more_specific( descendant_addresses, sibling_addresses) assert ascendant_addresses == AddressSpecs.more_specific( ascendant_addresses, None) assert ascendant_addresses == AddressSpecs.more_specific( ascendant_addresses, descendant_addresses) assert ascendant_addresses == AddressSpecs.more_specific( None, ascendant_addresses) assert ascendant_addresses == AddressSpecs.more_specific( descendant_addresses, ascendant_addresses) assert descendant_addresses == AddressSpecs.more_specific( descendant_addresses, None) assert descendant_addresses == AddressSpecs.more_specific( None, descendant_addresses)
def test_address_specs_more_specific() -> None: single_address = SingleAddress(directory="foo/bar", name="baz") sibling_addresses = SiblingAddresses(directory="foo/bar") ascendant_addresses = AscendantAddresses(directory="foo/bar") descendant_addresses = DescendantAddresses(directory="foo/bar") assert single_address == AddressSpecs.more_specific(single_address, None) assert single_address == AddressSpecs.more_specific(single_address, sibling_addresses) assert single_address == AddressSpecs.more_specific(single_address, ascendant_addresses) assert single_address == AddressSpecs.more_specific(single_address, descendant_addresses) assert single_address == AddressSpecs.more_specific(None, single_address) assert single_address == AddressSpecs.more_specific(sibling_addresses, single_address) assert single_address == AddressSpecs.more_specific(ascendant_addresses, single_address) assert single_address == AddressSpecs.more_specific(descendant_addresses, single_address) assert sibling_addresses == AddressSpecs.more_specific(sibling_addresses, None) assert sibling_addresses == AddressSpecs.more_specific(sibling_addresses, ascendant_addresses) assert sibling_addresses == AddressSpecs.more_specific(sibling_addresses, descendant_addresses) assert sibling_addresses == AddressSpecs.more_specific(None, sibling_addresses) assert sibling_addresses == AddressSpecs.more_specific(ascendant_addresses, sibling_addresses) assert sibling_addresses == AddressSpecs.more_specific(descendant_addresses, sibling_addresses) assert ascendant_addresses == AddressSpecs.more_specific(ascendant_addresses, None) assert ascendant_addresses == AddressSpecs.more_specific( ascendant_addresses, descendant_addresses ) assert ascendant_addresses == AddressSpecs.more_specific(None, ascendant_addresses) assert ascendant_addresses == AddressSpecs.more_specific( descendant_addresses, ascendant_addresses ) assert descendant_addresses == AddressSpecs.more_specific(descendant_addresses, None) assert descendant_addresses == AddressSpecs.more_specific(None, descendant_addresses)