Background
Hey all, I've been looking at integrating cargo
with the ROS 2 build tool, colcon
, as part of the ros2_rust
project. Without getting too deep into it, colcon
is a python tool which will invoke various build systems (cmake, setuptools, cargo). Here we've got a cargo crate, which will depend on message_package
(not through cargo, but rather an adjacent ROS specific way), and colcon will make sure that message_package
is built first.
.
└── ros_workspace/
└── src/
├── message_package/ (cmake)
└── my_crate/ (cargo)
As a result of the message_package
build, a rust crate will be generated
.
└── ros_workspace/
├── src/
│ ├── message_package/ (cmake)
│ └── my_crate/ (cargo)
└── install/
└── message_package/
└── share/
└── message_package/
└── rust/
├── src/
├── build.rs
└── Cargo.toml
Current Approach
Currently, we consume this generated crate by patching in a .cargo/config.toml
that colcon
creates. So my_crate/Cargo.toml
declares the dependency like this
[dependencies]
message_package = "*"
And the generated .cargo/config.toml
section looks like this
[patch.crates-io.message_package]
path = "<$HOME>/ros_workspace/install/message_package/share/message_package/rust"
I would like us to get away from this for various reasons, but to keep it succinct here, its confusing for our users, and will generate warnings if we don't actually use the patched dependencies.
Alternatives
So with that preamble out of the way, I am interested in using a local registry of some kind for these generated crates.
[dependencies]
message_package = { version = "*" registry="local" }
I've looked at cargo-local-registry and cargo vendor, but I don't believe either really accomplish what I'm looking for. I do not want to completely vendor all dependencies from crates.io, only a specific few that a developer opt's into.
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
# or if using local-registry
# local-registry = "/path/to/vendor"
If I try to do source replacement without a registry (either directory
or local-registry
)
[source.local]
directory = "/path/to/generated/crates/"
# local-registry = "..."
I get this error
Caused by:
registry index was not found in any configuration: `local`
It seems like any sort of source replacement still requires a registry with an index. I can actually define an index locally, by using a file URI to point to a dir containing a config.json
, which then has a dl
key that points to a local file URI for the requested crate.
[registries.local]
index = "file://<$HOME>/ros_workspace/install/index"
.
└── ros_workspace/
└── install/
├── ...
└── index/
└── .git/
├── me/
│ └── ss/
│ └── message_package
├── ...
└── config.json
config.json
at that path
{
"dl": "file://localhost/<$HOME>/ros_workspace/install/{crate}/share/{crate}/rust/{crate}-{version}.crate"
}
This requires me to create a local git repo for the associated index, populate said index, and create .crate
files for the generated crates. Additionally, this approach caches quite a bit in ~/.cargo/registry/
. The generated crates will likely change contents without updating version numbers (i.e. local development) and will then fail a checksum.
What I Would Like
Ideally, I would like to be able to define an index locally, that points to the generated crates in the install/
folder. These crates would not have any checksum checks, wouldn't need to be packaged into .crate
s, and can be looked up in a similar way that their download paths are found via indexes (i.e. the dl
key in the config.json
).
.
└── ros_workspace/
└── install/
├── ...
└── config.json
{
"dl": "file://localhost/<$HOME>/ros_workspace/install/{crate}/share/{crate}/rust/{crate}-{version}"
}
It's not my birthday, but it would also be awesome if I could define this via an env var, like CARGO_REGISTRIES_<NAME>_INDEX
Am I Missing Something?
If you made it this far, thanks for hearing me out! With that said, is there some way to get closer to my ideal without any new features in cargo? Did I miss anything?