rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.56k stars 2.38k forks source link

Ability to specify CARGO_HOME via file #6452

Open tyranron opened 5 years ago

tyranron commented 5 years ago

Describe the problem you are trying to solve

Currently, the $CARGO_HOME env var may be set to specify the location of cargo "caches" (fetched crates, binaries installed, etc). When we do not want to use the global one, we can override this for local project by providing directly to cargo commands:

CARGO_HOME=.cache/cargo cargo fetch

# or
export CARGO_HOME=.cache/cargo
cargo build

While this works OK, it's still not ergonomic enough for certain situations. For example:
I'm developing HTTP daemon and using Docker. I want $CARGO_HOME being reused both for normal builds in terminal or IDE (via cargo build) and for those ones inside Dockerfile. This makes me:

The problem with docker build that I cannot pass arbitrary directory to the build context, only those dirs which are inside cwd. So, I should persist $CARGO_HOME inside my project root and do it only when using this project specifically. I want no bothering and just run cargo build or docker build without any crates refetches.

Describe the solution you'd like

Simply allow to override the $CARGO_HOME for the current directory with some sort of configuration file: either .cargo/config, or Cargo.toml. It will allow to declare the desired value once and just don't bother, while playing well with both cargo build/docker build experiences at the same time.

The feature is not new and already exists in package managers for other languages. For example, I can specify the packages cache folder in:

lukaslueg commented 5 years ago

One can use autoenv to that effect.

tyranron commented 5 years ago

@lukaslueg Docker images has no zsh, however. Win users, generally, too.

jonhoo commented 3 years ago

I suppose the tricky part here is that by changing CARGO_HOME you change what configuration files cargo reads (it'll now have to read $CARGO_HOME2/.cargo/config). Imagine something like the following:

# ~/.cargo/config
home = "/path/to/a"

[build]
target = "foo"

Now imagine you invoke cargo from the directory b without CARGO_HOME set. What should the target directory be? ~/.cargo/config says that it should be "foo", but it also says that CARGO_HOME should have a different value. And if it had that different value, then ~/.cargo/config would never have been read, which means that the target was never set. It's a little contrived, but suggests there are some weird corner-cases here.

One way to get around this is to have cargo home no be set in the normal configuration files, but instead with a different file under .cargo. For example, imagine a .cargo/home which should hold the path that CARGO_HOME should be set to. cargo should first check CARGO_HOME, and use that if set. If not set, it should search up the tree for .cargo/home, stopping at the first one it finds and using that as the cargo home. And otherwise, it should use ~/.cargo like today. Only after that process has completed should it start reading configuration files. I think that gets around any weird circular definitions or other recursive shenanigans.

jonhoo commented 3 years ago

I filed a PR that implements the .cargo/home idea: https://github.com/rust-lang/cargo/pull/9154

epage commented 10 months ago

In light of https://internals.rust-lang.org/t/pre-rfc-split-cargo-home/19747, I assume what would be wanted is CARGO_CACHE_HOME. I suspect that is something we could make overrideable in .cargo/config.toml.