bazelbuild / rules_rust

Rust rules for Bazel
https://bazelbuild.github.io/rules_rust/
Apache License 2.0
666 stars 428 forks source link

Get list of manifests to use with crates_repository #2724

Open nmattia opened 3 months ago

nmattia commented 3 months ago

I have a project with a Cargo workspace with 100+ members, meaning it's not practical to list every single manifest manually when calling crates_repository. Maybe I'm going the wrong way about it, but I'm wondering how to get a list of all manifests to give crates_repository, much like all_crate_deps does for dependencies.

Right now I'm using this hacky (& brittle) repository rule that reads the top-level Cargo.toml and exports a list of labels:

"""
A repository rule that creates a repo exporting the list of all Cargo manifests
(excluding the top-level one) as MANIFESTS
"""

def _impl(repository_ctx):
    # Assume a Cargo.toml in the root
    contents = repository_ctx.read(repository_ctx.attr.manifest)

    repository_ctx.report_progress("Fetching manifests")
    # Read the Cargo.toml's `members`; does this by reading
    # all lines between 'members = [' and the closing ']'
    [_, contents] = contents.split("members = [\n")
    [contents,_] = contents.split("]",1)
    packages = contents.splitlines()

    # turn the manifest path into a Bazel label
    def package_to_label(package):
        [_, rest] = package.split("\"", 1)
        [rest, _] = rest.split("\"", 1)
        return "\"//" + rest + ":Cargo.toml\","

    labels = [package_to_label(p) for p in packages]
    manifests = "".join(labels)
    repository_ctx.file("BUILD.bazel", content = "\n", executable = False)
    repository_ctx.file("defs.bzl", "MANIFESTS = [ {manifests} ]\n".format(manifests = manifests), executable = False)

_manifests = repository_rule(
    implementation = _impl,
    attrs = {
        "manifest": attr.label(mandatory = True),
    },
)

def manifests_repository(name, manifest):
    _manifests(name = name, manifest = manifest)

and in the WORKSPACE:

load("//bazel/manifests:defs.bzl", "manifests_repository")

manifests_repository(name = "manifests")

and in the BUILD.bazel file with crates_repository:

load("@manifests//:defs.bzl", "MANIFESTS")

crates_repository(
    ...
    manifests = ["//:Cargo.toml"] + MANIFESTS
    )

Is there a better/recommended way of doing this?

rbtcollins commented 3 months ago

We just list all the manifests - what you've done is probably nicer. You could shift the parsing to a https://github.com/gnprice/toml-cli query or similar I guess.