"""A module defining a repository rule for vendoring the dependencies of a crate in the current workspace. """ load("@rules_rust//rust:repositories.bzl", "DEFAULT_RUST_VERSION", "load_arbitrary_tool") def _impl(repository_ctx): # Link cxx repository into @third-party. lockfile = repository_ctx.path(repository_ctx.attr.lockfile) workspace = lockfile.dirname.dirname repository_ctx.symlink(workspace, "workspace") # Copy third-party/Cargo.lock since those are the crate versions that the # BUILD file is written against. vendor_lockfile = repository_ctx.path("workspace/third-party/Cargo.lock") root_lockfile = repository_ctx.path("workspace/Cargo.lock") _copy_file(repository_ctx, src = vendor_lockfile, dst = root_lockfile) # Figure out which version of cargo to use. if repository_ctx.attr.target_triple: target_triple = repository_ctx.attr.target_triple elif "mac" in repository_ctx.os.name: target_triple = "x86_64-apple-darwin" elif "windows" in repository_ctx.os.name: target_triple = "x86_64-pc-windows-msvc" else: target_triple = "x86_64-unknown-linux-gnu" # Download cargo. load_arbitrary_tool( ctx = repository_ctx, tool_name = "cargo", tool_subdirectories = ["cargo"], version = repository_ctx.attr.cargo_version, iso_date = repository_ctx.attr.cargo_iso_date, target_triple = target_triple, ) cmd = ["{}/bin/cargo".format(repository_ctx.path(".")), "vendor", "--versioned-dirs", "third-party/vendor"] result = repository_ctx.execute( cmd, quiet = True, working_directory = "workspace", ) _log_cargo_vendor(repository_ctx, result) if result.return_code != 0: fail("failed to execute `{}`".format(" ".join(cmd))) # Copy lockfile back to third-party/Cargo.lock to reflect any modification # performed by Cargo. _copy_file(repository_ctx, src = root_lockfile, dst = vendor_lockfile) # Produce a token for third_party_glob to depend on so that the necessary # sequencing is visible to Bazel. repository_ctx.file("BUILD", executable = False) repository_ctx.file("vendor.bzl", "vendored = True", executable = False) def _copy_file(repository_ctx, *, src, dst): content = repository_ctx.read(src) if not dst.exists or content != repository_ctx.read(dst): repository_ctx.file(dst, content = content, executable = False) def _log_cargo_vendor(repository_ctx, result): relevant = "" for line in result.stderr.splitlines(True): if line.strip() and not line.startswith("To use vendored sources,"): relevant += line if relevant: # Render it as command output. # If we just use print(), Bazel will cache and repeat the output even # when not rerunning the command. print = ["echo", relevant] repository_ctx.execute(print, quiet = False) vendor = repository_rule( doc = "A rule used to vendor the dependencies of a crate in the current workspace", attrs = { "cargo_version": attr.string( doc = "The version of cargo to use", default = DEFAULT_RUST_VERSION, ), "cargo_iso_date": attr.string( doc = "The date of the tool (or None, if the version is a specific version)", ), "target_triple": attr.string( doc = "The target triple of the cargo binary to download", ), "lockfile": attr.label( doc = "A lockfile providing the set of crates to vendor", ), }, local = True, implementation = _impl, )