Skip to content

Commit 10abe8f

Browse files
authored
Merge pull request #3178 from ehuss/no-windows-bin-path
Don't add toolchain bin to PATH on Windows
2 parents 4094153 + 6df98f6 commit 10abe8f

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

src/toolchain.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,22 @@ impl<'a> InstalledCommonToolchain<'a> {
454454
}
455455

456456
if cfg!(target_os = "windows") {
457-
path_entries.push(self.0.path.join("bin"));
457+
// Historically rustup has included the bin directory in PATH to
458+
// work around some bugs (see
459+
// https://github.com/rust-lang/rustup/pull/3178 for more
460+
// information). This shouldn't be needed anymore, and it causes
461+
// problems because calling tools recursively (like `cargo
462+
// +nightly metadata` from within a cargo subcommand). The
463+
// recursive call won't work because it is not executing the
464+
// proxy, so the `+` toolchain override doesn't work.
465+
//
466+
// This is opt-in to allow us to get more real-world testing.
467+
if process()
468+
.var_os("RUSTUP_WINDOWS_PATH_ADD_BIN")
469+
.map_or(true, |s| s == "1")
470+
{
471+
path_entries.push(self.0.path.join("bin"));
472+
}
458473
}
459474

460475
env_var::prepend_path("PATH", path_entries, cmd);

tests/mock/mock_bin_src.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ fn main() {
6161
let rustc = &format!("rustc{}", EXE_SUFFIX);
6262
Command::new(rustc).arg("--version").status().unwrap();
6363
}
64+
Some("--recursive-cargo-subcommand") => {
65+
let status = Command::new("cargo-foo")
66+
.arg("--recursive-cargo")
67+
.status()
68+
.unwrap();
69+
assert!(status.success());
70+
}
71+
Some("--recursive-cargo") => {
72+
let status = Command::new("cargo")
73+
.args(&["+nightly", "--version"])
74+
.status()
75+
.unwrap();
76+
assert!(status.success());
77+
}
6478
Some("--echo-args") => {
6579
let mut out = io::stderr();
6680
for arg in args {
@@ -71,7 +85,7 @@ fn main() {
7185
let mut out = io::stderr();
7286
writeln!(out, "{}", std::env::var("PATH").unwrap()).unwrap();
7387
}
74-
_ => panic!("bad mock proxy commandline"),
88+
arg => panic!("bad mock proxy commandline: {:?}", arg),
7589
}
7690
}
7791

tests/suite/cli_rustup.rs

+57
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,63 @@ fn fallback_cargo_calls_correct_rustc() {
547547
});
548548
}
549549

550+
// Checks that cargo can recursively invoke itself with rustup shorthand (via
551+
// the proxy).
552+
//
553+
// This involves a series of chained commands:
554+
//
555+
// 1. Calls `cargo --recursive-cargo-subcommand`
556+
// 2. The rustup `cargo` proxy launches, and launches the "mock" nightly cargo exe.
557+
// 3. The nightly "mock" cargo sees --recursive-cargo-subcommand, and launches
558+
// `cargo-foo --recursive-cargo`
559+
// 4. `cargo-foo` sees `--recursive-cargo` and launches `cargo +nightly --version`
560+
// 5. The rustup `cargo` proxy launches, and launches the "mock" nightly cargo exe.
561+
// 6. The nightly "mock" cargo sees `--version` and prints the version.
562+
//
563+
// Previously, rustup would place the toolchain's `bin` directory in PATH for
564+
// Windows due to some DLL issues. However, those aren't necessary anymore.
565+
// If the toolchain `bin` directory is in PATH, then this test would fail in
566+
// step 5 because the `cargo` executable would be the "mock" nightly cargo,
567+
// and the first argument would be `+nightly` which would be an error.
568+
#[test]
569+
fn recursive_cargo() {
570+
test(&|config| {
571+
config.with_scenario(Scenario::ArchivesV2, &|config| {
572+
config.expect_ok(&["rustup", "default", "nightly"]);
573+
574+
// We need an intermediary to run cargo itself.
575+
// The "mock" cargo can't do that because on Windows it will check
576+
// for a `cargo.exe` in the current directory before checking PATH.
577+
//
578+
// The solution here is to copy from the "mock" `cargo.exe` into
579+
// `~/.cargo/bin/cargo-foo`. This is just for convenience to avoid
580+
// needing to build another executable just for this test.
581+
let output = config.run("rustup", &["which", "cargo"], &[]);
582+
let real_mock_cargo = output.stdout.trim();
583+
let cargo_bin_path = config.cargodir.join("bin");
584+
let cargo_subcommand = cargo_bin_path.join(format!("cargo-foo{}", EXE_SUFFIX));
585+
fs::create_dir_all(&cargo_bin_path).unwrap();
586+
fs::copy(&real_mock_cargo, &cargo_subcommand).unwrap();
587+
588+
// Verify the default behavior, which is currently broken on Windows.
589+
let args = &["cargo", "--recursive-cargo-subcommand"];
590+
if cfg!(windows) {
591+
config.expect_err(
592+
&["cargo", "--recursive-cargo-subcommand"],
593+
"bad mock proxy commandline",
594+
);
595+
}
596+
597+
// Try the opt-in, which should fix it.
598+
let out = config.run(args[0], &args[1..], &[("RUSTUP_WINDOWS_PATH_ADD_BIN", "0")]);
599+
if !out.ok || !out.stdout.contains("hash-nightly-2") {
600+
clitools::print_command(args, &out);
601+
panic!("expected hash-nightly-2 in output");
602+
}
603+
});
604+
});
605+
}
606+
550607
#[test]
551608
fn show_home() {
552609
test(&|config| {

0 commit comments

Comments
 (0)