| """ |
| 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") |
| |
| # 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: |
| git_repository( |
| build_file = repo_data.get("build_file"), |
| commit = repo_data.get("commit"), |
| name = name, |
| 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_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, |
| }, |
| ) |