cargo
cargo copied to clipboard
cargo subcommands do not pick up [env]
Problem
The [env] configuration section (https://github.com/rust-lang/cargo/issues/9539) does not currently impact subcommand invocations. It's not entirely clear whether this is a bug or by design. My instinct is that it's the former, since otherwise setting, say, PATH in ~/.cargo/config.toml won't affect which subcommands are available, but it could also be argued that it should be up to subcommands whether they want to pick up the current configuration (e.g., they may to reload the config rooted somewhere else, which would mean not picking up [env] from ./.cargo/config.toml).
If this is a bug, it should be fixed.
If it's by design, the documentation should be updated to make it clear that these environment variables do not affect subcommands.
Steps
echo '#!/bin/bash' > ~/.cargo/bin/cargo-issue-10094
echo 'env' >> ~/.cargo/bin/cargo-issue-10094
chmod +x ~/.cargo/bin/cargo-issue-10094
rm -rf cargo-issue-10094-repro
cargo new cargo-issue-10094-repro
pushd cargo-issue-10094-repro
mkdir .cargo
echo '[env]' > .cargo/config.toml
echo 'CARGO_ISSUE_10094 = "1"' >> .cargo/config.toml
env=$(cargo issue-10094)
popd
rm -r cargo-issue-10094-repro
rm ~/.cargo/bin/cargo-issue-10094
# Notice that this produces no output
echo "$env" | grep CARGO_ISSUE_10094
Possible Solution(s)
The code here
https://github.com/rust-lang/cargo/blob/ad50d0d266213e0cc4f6e526a39d96faae9a3842/src/bin/cargo/main.rs#L171-L174
needs to pick up environment variables from the config in the same way as is done for compilation invocations in
https://github.com/rust-lang/cargo/blob/ad50d0d266213e0cc4f6e526a39d96faae9a3842/src/cargo/core/compiler/compilation.rs#L348-L358
Or, if the decision is to update the documentation instead, this paragraph should be updated
https://github.com/rust-lang/cargo/blob/ad50d0d266213e0cc4f6e526a39d96faae9a3842/src/doc/src/reference/config.md?plain=1#L485-L486
Notes
No response
Version
cargo 1.56.0 (4ed5d137b 2021-10-04)
release: 1.56.0
commit-hash: 4ed5d137baff5eccf1bae5a7b2ae4b57efad4a7d
commit-date: 2021-10-04
A couple of notes from today's Cargo meeting:
- This seems reasonable; we should set the environment variables for third-party subcommands too.
- What happens if you set
PATH? Does that affect finding the subcommands? - What happens if you set
CARGO_HOME? Do we read.cargo/config.tomlfrom the new location? - What happens if you set configuration environment variables?
We should definitely fix this, but in doing so, we should address corner cases like those.
Personally, I would propose that setting PATH should work, setting CARGO_HOME should not (to avoid dealing with recursion), setting configuration environment variables should not (since people can just as easily set those elsewhere in the same .cargo/config.toml), and overriding environment variables cargo sets for crates should not work.
I agree on all points.
For those last two, I would actually suggest that those should never work, not just for subcommands, and that those cases should error out in the code that reads the environment variables from the config in the first place.
@jonhoo Right, those were meant to be things that should always be true about [env], not just things that should be true for subcommands.
Picking up the discussion from #10780 here.
My implementation: https://github.com/rust-lang/cargo/compare/master...lovesegfault:cargo:fix-10094
Regarding the questions posed by @joshtriplett:
-
we should set the environment variables for third-party subcommands too.
- This is now the case, the implementation is here. Note, however, that I did not change the default behavior. See note below.
-
What happens if you set PATH? Does that affect finding the subcommands?
-
What happens if you set CARGO_HOME? Do we read .cargo/config.toml from the new location?
- Setting any
CARGO_vars in[env]is now forbidden. I think it's just too difficult to make sure they all work without making Cargo recursive, which I suspect we don't want to do.
- Setting any
-
What happens if you set configuration environment variables?
- They're forbidden. At least the
CARGO_ones, I wasn't certain whether we wanted to forbid any other prefixes or specific vars.
- They're forbidden. At least the
One remaining question is what should the default behavior be, we have two options:
- Apply
[env]to subcommands, allow opting-out by settingin_subcommands = false.
- This is less surprising, and arguably more correct, but would be a breaking change.
- Don't apply
[env]to subcommands, allow opting-in by settingin_subcommands = true.
- This is the current behavior, and it is surprising, but would let us get away without a breaking change.
In my current PR, I took the route of (2). Changing it to (1) is trivial, all I need is to flip this value.
Which option should we take?
There's also the smaller question of what the option for retaining the old behavior should be named. And arguably, if we're willing to make a breaking change (so option 1), whether there even should be an option for retaining the current behavior. I happen to have a specific use-case where I explicitly want the current behavior, so would strongly prefer the option to be included regardless of whether we change the default or not.
As for naming, I like in-subcommands. Some other suggestions for bikeshedding:
subcommandsinclude-subcommandsapplies-to: cargo | subcommands | ["cargo", "subcommands"]
Another note for later: we'll want to make sure that cargo --list and cargo --list --verbose also pick up on [env.PATH] if set for the purposes of discovering subcommands.
We had a pretty lengthy discussion about this issue today, but unfortunately didn't come to a direct conclusion.
One thing we would like to see is an overview of alternatives so that we can consider the merits of setting the environment for external subcommands versus other solutions.
One concern is that if the environment was set, external subcommands would then begin behaving differently than cargo itself. Cargo doesn't read the [env] table for its own environment (see #11589). If the [env] was set for subcommands, they would then see a different environment than cargo itself. If cargo were to start reading the [env] table for itself, then it would probably make a lot more sense for it to set it for external subcommands.
An alternative is to make it easier for external subcommands to access cargo's config. If that were easier, then external subcommands can decide if they want the [env] table or not by reading it themselves. (That wouldn't address the PATH issue, though.)
Another idea is to somehow make this an opt-in behavior for external subcommands.
Perhaps others could share some comments if there are other considerations or ideas?