1"""A module defining a repository rule for vendoring the dependencies 2of a crate in the current workspace. 3""" 4 5def _impl(repository_ctx): 6 # Link cxx repository into @third-party. 7 lockfile = repository_ctx.path(repository_ctx.attr.lockfile) 8 workspace = lockfile.dirname.dirname 9 repository_ctx.symlink(workspace, "workspace") 10 11 # Copy third-party/Cargo.lock since those are the crate versions that the 12 # BUILD file is written against. 13 vendor_lockfile = repository_ctx.path("workspace/third-party/Cargo.lock") 14 root_lockfile = repository_ctx.path("workspace/Cargo.lock") 15 _copy_file(repository_ctx, src = vendor_lockfile, dst = root_lockfile) 16 17 # Execute cargo vendor. 18 cmd = ["cargo", "vendor", "--versioned-dirs", "third-party/vendor"] 19 result = repository_ctx.execute( 20 cmd, 21 quiet = True, 22 working_directory = "workspace", 23 ) 24 _log_cargo_vendor(repository_ctx, result) 25 if result.return_code != 0: 26 fail("failed to execute `{}`".format(" ".join(cmd))) 27 28 # Copy lockfile back to third-party/Cargo.lock to reflect any modification 29 # performed by Cargo. 30 _copy_file(repository_ctx, src = root_lockfile, dst = vendor_lockfile) 31 32 # Produce a token for third_party_glob to depend on so that the necessary 33 # sequencing is visible to Bazel. 34 repository_ctx.file("BUILD", executable = False) 35 repository_ctx.file("vendor.bzl", "vendored = True", executable = False) 36 37def _copy_file(repository_ctx, *, src, dst): 38 content = repository_ctx.read(src) 39 if not dst.exists or content != repository_ctx.read(dst): 40 repository_ctx.file(dst, content = content, executable = False) 41 42def _log_cargo_vendor(repository_ctx, result): 43 relevant = "" 44 for line in result.stderr.splitlines(True): 45 if line.strip() and not line.startswith("To use vendored sources,"): 46 relevant += line 47 if relevant: 48 # Render it as command output. 49 # If we just use print(), Bazel will cache and repeat the output even 50 # when not rerunning the command. 51 print = ["echo", relevant] 52 repository_ctx.execute(print, quiet = False) 53 54vendor = repository_rule( 55 doc = "A rule used to vendor the dependencies of a crate in the current workspace", 56 attrs = { 57 "lockfile": attr.label( 58 doc = "A lockfile providing the set of crates to vendor", 59 ), 60 }, 61 local = True, 62 implementation = _impl, 63) 64