bazel-lib/lib/private/directory_path.bzl

134 lines
3.8 KiB
Python

"""Rule and corresponding provider that joins a label pointing to a TreeArtifact
with a path nested within that directory
"""
load("//lib:utils.bzl", _to_label = "to_label")
DirectoryPathInfo = provider(
doc = "Joins a label pointing to a TreeArtifact with a path nested within that directory.",
fields = {
"directory": "a TreeArtifact (ctx.actions.declare_directory)",
"path": "path relative to the directory",
},
)
def _directory_path(ctx):
if not ctx.file.directory.is_directory:
msg = "Expected directory to be a TreeArtifact (ctx.actions.declare_directory) but {} is either a source file or does not exist.".format(ctx.file.directory)
fail(msg)
return [DirectoryPathInfo(path = ctx.attr.path, directory = ctx.file.directory)]
directory_path = rule(
doc = """Provide DirectoryPathInfo to reference some path within a directory.
Otherwise there is no way to give a Bazel label for it.""",
implementation = _directory_path,
attrs = {
"directory": attr.label(
doc = "a TreeArtifact (ctx.actions.declare_directory)",
mandatory = True,
allow_single_file = True,
),
"path": attr.string(
doc = "path relative to the directory",
mandatory = True,
),
},
provides = [DirectoryPathInfo],
)
def make_directory_path(name, directory, path, **kwargs):
"""Helper function to generate a directory_path target and return its label.
Args:
name: unique name for the generated `directory_path` target
directory: `directory` attribute passed to generated `directory_path` target
path: `path` attribute passed to generated `directory_path` target
**kwargs: parameters to pass to generated `output_files` target
Returns:
The label `name`
"""
directory_path(
name = name,
directory = directory,
path = path,
**kwargs
)
return _to_label(name)
def make_directory_paths(name, dict, **kwargs):
"""Helper function to convert a dict of directory to path mappings to directory_path targets and labels.
For example,
```
make_directory_paths("my_name", {
"//directory/artifact:target_1": "file/path",
"//directory/artifact:target_2": ["file/path1", "file/path2"],
})
```
generates the targets,
```
directory_path(
name = "my_name_0",
directory = "//directory/artifact:target_1",
path = "file/path"
)
directory_path(
name = "my_name_1",
directory = "//directory/artifact:target_2",
path = "file/path1"
)
directory_path(
name = "my_name_2",
directory = "//directory/artifact:target_2",
path = "file/path2"
)
```
and the list of targets is returned,
```
[
"my_name_0",
"my_name_1",
"my_name_2",
]
```
Args:
name: The target name to use for the generated targets & labels.
The names are generated as zero-indexed `name + "_" + i`
dict: The dictionary of directory keys to path or path list values.
**kwargs: additional parameters to pass to each generated target
Returns:
The label of the generated `directory_path` targets named `name + "_" + i`
"""
labels = []
pairs = []
for directory, val in dict.items():
if type(val) == "list":
for path in val:
pairs.append((directory, path))
elif type(val) == "string":
pairs.append((directory, val))
else:
fail("Value must be a list or string")
for i, pair in enumerate(pairs):
directory, path = pair
labels.append(make_directory_path(
"%s_%d" % (name, i),
directory,
path,
**kwargs
))
return labels