| """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 |