in antlir/compiler/items_for_features.py [0:0]
def replace_targets_by_paths(x: Any, ctx: GenFeaturesContext):
"""
Converts target_tagger.bzl sigils to buck-out paths or Subvol objects.
JSON-serialized image features store single-item dicts of the form
{'__BUCK{_LAYER,}_TARGET': '//target:path'} whenever the compiler
requires a path to another target. This is because actual paths would
break Buck caching, and would not survive repo moves. Then, at runtime,
the compiler receives a dictionary of target-to-path mappings as
`--child-dependencies`, and performs the substitution in any image
feature JSON it consumes.
If `ctx.subvolumes_dir` is None, layer targets will not be replaced by
their corresponding subvolumes, and will instead be left as-is.
If `ctx.ignore_missing_paths` is True, the target will simply be
returned if it is not found in `target_to_path`.
"""
if type(x) is dict:
if "__BUCK_TARGET" in x or "__BUCK_LAYER_TARGET" in x:
assert len(x) == 1, x
((sigil, target),) = x.items()
if sigil == "__BUCK_LAYER_TARGET" and ctx.subvolumes_dir is None:
return target # pragma: no cover
path = ctx.target_to_path.get(target)
if not path:
if ctx.ignore_missing_paths: # pragma: no cover
return UnknownTarget(target)
raise RuntimeError(f"{target} not in {ctx.target_to_path}")
return (
path
if sigil == "__BUCK_TARGET"
else find_built_subvol(path, subvolumes_dir=ctx.subvolumes_dir)
)
return {k: replace_targets_by_paths(v, ctx) for k, v in x.items()}
elif type(x) is list:
return [replace_targets_by_paths(v, ctx) for v in x]
elif type(x) in [int, float, str, bool, type(None)]:
return x
raise AssertionError(f"Unknown {type(x)} for {x}") # pragma: no cover