Cargo allows local configuration for a particular package as well as global configuration. It looks for configuration files in the current directory and all parent directories.
This makes it extremely hard to precisely control what config Cargo is actually using if you want to run it in a hermetic way. Aside from actually running it in a container or something, you need to run it in a directory where you're certain none of the parents have a stray .cargo directory (and simply overriding CARGO_HOME doesn't seem to be enough).
Even if you wanted Cargo's "accumulate configs" behaviour, making it strictly a result of the directory hierarchy makes it hard to use if your project structure isn't laid out in a matching way. For example, I'm experimenting with "out of line vendor dirs", where a .cargo/config.toml in an adjacent directory can define a vendor dir.
It seems to me that all these problems could be solved by implementing a CARGO_CONFIG_PATH environment variable which contains an explicit path of directories to search for config files, in a specific order. (If not set, the existing behaviour holds.)
Would this be useful? Or is there some other way of achieving the same effect?
I guess the first question to ask is whether this is fixing a problem you've encountered in the real world and had to put in effort to work around, or whether it is a hypothetical issue that you can foresee someone possibly encountering?
In practice I haven't really seen people creating a rogue .cargo/config higher up in the directory tree (the /tmp/ example from the GitHub issue), and I don't see a real reason why someone would want to do that in the first place.
It also feels odd for people to go against established convention by putting .cargo/config.toml in a non-standard place, although I don't know enough about your "out of line vendor dirs" experiment and it may be that.
I would propose that if you want truly self-contained, reproducible builds you should use something which will ensure they are self-contained and reproducible.
I don't know about you, but I tend to have lots of random things installed on my laptop, so I'd consider it to be a non-hermetic environment. When I want a clean environment to do something in I'll do it inside a container.
Sorry if this sounds a bit confrontational. I'm just trying to find out whether the benefits of a new feature are greater than the cost of implementing and maintaining and having more complex behaviour which people will need to remember when troubleshooting.
Yes, this has been a real problem. In my case, I'm committing .cargo/config.toml files generated by cargo vendor into source control adjacent to the vendor/ directory. I can't be completely sure where someone else might check the repo out (say, somewhere in their home directory), and some may have stray ~/.cargo/config.toml.
We're not using Cargo as the principle build tool for Rust in this environment (we're using Buck); uses of Cargo are primarily for interfacing with crates.io, or for code which is intended to be open-sourced and needs to be also Cargo-buildable. For the latter, they are in some other part of the tree from the vendor directory; I would like to be able to control Cargo's config-finding so that it picks up the vendoring config, while leaving the code itself still buildable externally without using vendoring.
I've basically found this whole behavior to do exactly the opposite of anything I would ever want it to do when trying to use it.
but since cargo only reads the config.toml where invoked when building from the top-level it won't "accumulate" configs in workspace members.
[workspace]
members = ["configdir1/foo", "configdir2/bar"]
then creating configdir1/.cargo/config.toml, I've always figured it does this whole searching upwards merely out of spite.
I agree, this would be very useful. In our case we need to ensure
that all Rust projects only ever access the local registry. The
way to do this per project is to override [source.crates-io] in a crate’s .cargo/config but to
accomplish that globally this file needs to be written by the
build system.
This causes a lot of pain when multiple build systems overlap, e.
g. we have rpmbuild for constructing packages in a clean
environment. The RPM tooling takes care of writing the config,
but this only works for package builds. To compile individual
projects we use CMake thus in order to set the registry during
incremental builds, CMake too needs to write a config before
invoking cargo. Likewise for any other build system you might be
using in projects that are being oxidized gradually.
All this could be solved if there was a system wide config say /etc/cargo/config or a drop-in directory for config files
where cargo looks first before even considering any project-local
configuration file. Alternatively, the CARGO_CONFIG_PATH
variable proposed by @jsgf would also work.