| """ | |
| This module extension creates git_repositories loaded from a json file. | |
| It is important to separate the implementation from the actual data because | |
| the MODULE.bazel.lock file has a checksum of the .bzl files | |
| """ | |
| load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") | |
| load("//bazel/external/dawn:dawn_repo.bzl", "dawn_repo") | |
| # https://bazel.build/rules/lib/globals/bzl.html#tag_class | |
| _from_file_tag = tag_class( | |
| doc = "A JSON file containing attributes for git_repository", | |
| attrs = { | |
| "deps_json": attr.label( | |
| doc = "The deps.json file to read and create repos from.", | |
| ), | |
| }, | |
| ) | |
| # ctx is https://bazel.build/rules/lib/builtins/module_ctx | |
| def _cpp_modules_impl(ctx): | |
| all_deps = set() | |
| direct_deps = [] | |
| # https://bazel.build/rules/lib/builtins/bazel_module.html | |
| for module in ctx.modules: | |
| #https://bazel.build/rules/lib/builtins/bazel_module_tags | |
| if len(module.tags.from_file) != 1: | |
| fail("Must have exactly one from_file attribute set") | |
| json_file_label = module.tags.from_file[0].deps_json | |
| # https://bazel.build/rules/lib/builtins/module_ctx#read | |
| json_content = ctx.read(ctx.path(json_file_label)) | |
| data = json.decode(json_content) | |
| if "direct" not in data: | |
| fail("JSON file must contain a 'direct' list: {}".format(json_file_label)) | |
| if "indirect" not in data: | |
| fail("JSON file must contain a 'indirect' list (even if it's empty): {}".format(json_file_label)) | |
| for repo_data in data["direct"]: | |
| name = repo_data.get("name") | |
| if name not in all_deps: | |
| if name == "dawn": | |
| dawn_repo( | |
| build_file = repo_data.get("build_file"), | |
| commit = repo_data.get("commit"), | |
| generator_py = "//bazel/external/dawn:generate_dawn_files.py", | |
| name = name, | |
| remote = repo_data.get("remote"), | |
| ) | |
| else: | |
| git_repository( | |
| build_file = repo_data.get("build_file"), | |
| commit = repo_data.get("commit"), | |
| name = name, | |
| patch_args = repo_data.get("patch_args", []), | |
| patch_cmds = repo_data.get("patch_cmds"), | |
| patch_cmds_win = repo_data.get("patch_cmds_win"), | |
| patches = repo_data.get("patches"), | |
| remote = repo_data.get("remote"), | |
| ) | |
| direct_deps.append(name) | |
| all_deps.add(name) | |
| for repo_data in data["indirect"]: | |
| name = repo_data.get("name") | |
| if name not in all_deps: | |
| git_repository( | |
| build_file = repo_data.get("build_file"), | |
| commit = repo_data.get("commit"), | |
| name = name, | |
| patch_args = repo_data.get("patch_args", []), | |
| patch_cmds = repo_data.get("patch_cmds"), | |
| patch_cmds_win = repo_data.get("patch_cmds_win"), | |
| patches = repo_data.get("patches"), | |
| remote = repo_data.get("remote"), | |
| ) | |
| all_deps.add(name) | |
| # https://bazel.build/rules/lib/builtins/module_ctx#extension_metadata | |
| return ctx.extension_metadata( | |
| # By specifying the direct dependencies, bazel mod tidy will automatically | |
| # update the use_repo call to add or remove dependencies to the list. | |
| root_module_direct_deps = direct_deps, | |
| root_module_direct_dev_deps = [], | |
| # By setting this line, we are telling Bazel that the generated rules are | |
| # hermetic all on their own and that Bazel doesn't need to track the deps.json | |
| # file (e.g. via a sha256 checksum hash). This *is* the case because we are | |
| # generating git_repository rules, which include a specific commit, which is | |
| # effectively a hash of all the input contents. | |
| # This is a big deal because it means our autorollers can update only the deps.json | |
| # file and don't have to update anything in the MODULE.bazel.lock file after. | |
| reproducible = True, | |
| ) | |
| cpp_modules = module_extension( | |
| implementation = _cpp_modules_impl, | |
| tag_classes = { | |
| "from_file": _from_file_tag, | |
| }, | |
| ) |