Skip to content

Commit a106b1d

Browse files
committed
Implement 11036 cargo changes
1 parent 1ff2723 commit a106b1d

File tree

2 files changed

+193
-38
lines changed

2 files changed

+193
-38
lines changed

src/cargo/ops/cargo_install.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
22
use std::path::{Path, PathBuf};
33
use std::sync::Arc;
4-
use std::{env, fs};
4+
use std::{env, fmt, fs};
55

66
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput};
77
use crate::core::{Dependency, Edition, Package, PackageId, SourceId, Target, Workspace};
@@ -14,6 +14,7 @@ use crate::util::errors::CargoResult;
1414
use crate::util::{Filesystem, GlobalContext, Rustc};
1515
use crate::{drop_println, ops};
1616

17+
use annotate_snippets::Level;
1718
use anyhow::{Context as _, bail};
1819
use cargo_util::paths;
1920
use cargo_util_schemas::core::PartialVersion;
@@ -39,6 +40,42 @@ impl Drop for Transaction {
3940
}
4041
}
4142

43+
enum RustupToolchainSource {
44+
Default,
45+
Environment,
46+
CommandLine,
47+
OverrideDB,
48+
ToolchainFile,
49+
Other(String),
50+
}
51+
52+
#[allow(dead_code)]
53+
impl RustupToolchainSource {
54+
fn is_default_or_cli_override(&self) -> Option<bool> {
55+
match self {
56+
Self::Default => Some(true),
57+
Self::Environment => Some(false),
58+
Self::CommandLine => Some(true),
59+
Self::OverrideDB => Some(false),
60+
Self::ToolchainFile => Some(false),
61+
Self::Other(_) => None,
62+
}
63+
}
64+
}
65+
66+
impl fmt::Display for RustupToolchainSource {
67+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68+
f.write_str(match self {
69+
Self::Default => "default",
70+
Self::Environment => "env",
71+
Self::CommandLine => "cli",
72+
Self::OverrideDB => "path-override",
73+
Self::ToolchainFile => "toolchain-file",
74+
Self::Other(other) => other,
75+
})
76+
}
77+
}
78+
4279
struct InstallablePackage<'gctx> {
4380
gctx: &'gctx GlobalContext,
4481
opts: ops::CompileOptions,
@@ -316,6 +353,27 @@ impl<'gctx> InstallablePackage<'gctx> {
316353
fn install_one(mut self, dry_run: bool) -> CargoResult<bool> {
317354
self.gctx.shell().status("Installing", &self.pkg)?;
318355

356+
if let Some(source) = self.get_rustup_toolchain_source()
357+
&& source.is_default_or_cli_override() != Some(true)
358+
{
359+
#[expect(
360+
clippy::disallowed_methods,
361+
reason = "config should not set `RUSTUP` environment variables"
362+
)]
363+
let maybe_toolchain = env::var("RUSTUP_TOOLCHAIN")
364+
.ok()
365+
.map(|toolchain| format!(" `{toolchain}`"))
366+
.unwrap_or_default();
367+
let report = &[Level::WARNING
368+
.secondary_title(format!(
369+
"using non-default toolchain{maybe_toolchain} overridden by {source}"
370+
))
371+
.element(Level::HELP.message(format!(
372+
"use `cargo +stable install` if you meant to use the stable toolchain."
373+
)))];
374+
self.gctx.shell().print_report(report, false)?;
375+
}
376+
319377
// Normalize to absolute path for consistency throughout.
320378
// See: https://github.com/rust-lang/cargo/issues/16023
321379
let dst = self.root.join("bin").into_path_unlocked();
@@ -593,6 +651,23 @@ impl<'gctx> InstallablePackage<'gctx> {
593651
}
594652
}
595653

654+
fn get_rustup_toolchain_source(&self) -> Option<RustupToolchainSource> {
655+
#[expect(
656+
clippy::disallowed_methods,
657+
reason = "config should not set `RUSTUP` environment variables"
658+
)]
659+
let source = std::env::var("RUSTUP_TOOLCHAIN_SOURCE").ok()?;
660+
let source = match source.as_str() {
661+
"default" => RustupToolchainSource::Default,
662+
"env" => RustupToolchainSource::Environment,
663+
"cli" => RustupToolchainSource::CommandLine,
664+
"path-override" => RustupToolchainSource::OverrideDB,
665+
"toolchain-file" => RustupToolchainSource::ToolchainFile,
666+
other => RustupToolchainSource::Other(other.to_owned()),
667+
};
668+
Some(source)
669+
}
670+
596671
fn check_yanked_install(&self) -> CargoResult<()> {
597672
if self.ws.ignore_lock() || !self.ws.root().join("Cargo.lock").exists() {
598673
return Ok(());

tests/testsuite/rustup.rs

Lines changed: 117 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,27 @@ fn real_rustc_wrapper(bin_dir: &Path, message: &str) -> PathBuf {
5959
// The toolchain rustc needs to call the real rustc. In order to do that,
6060
// it needs to restore or clear the RUSTUP environment variables so that
6161
// if rustup is installed, it will call the correct rustc.
62+
let rustup_toolchain_source_setup = match std::env::var_os("RUSTUP_TOOLCHAIN_SOURCE") {
63+
Some(t) => format!(
64+
".env(\"RUSTUP_TOOLCHAIN_SOURCE\", \"{}\")",
65+
t.into_string().unwrap()
66+
),
67+
None => String::new(),
68+
};
6269
let rustup_toolchain_setup = match std::env::var_os("RUSTUP_TOOLCHAIN") {
6370
Some(t) => format!(
6471
".env(\"RUSTUP_TOOLCHAIN\", \"{}\")",
6572
t.into_string().unwrap()
6673
),
67-
None => format!(".env_remove(\"RUSTUP_TOOLCHAIN\")"),
74+
None => String::new(),
6875
};
6976
let mut env = vec![("CARGO_RUSTUP_TEST_real_rustc", real_rustc)];
7077
let rustup_home_setup = match std::env::var_os("RUSTUP_HOME") {
7178
Some(h) => {
7279
env.push(("CARGO_RUSTUP_TEST_RUSTUP_HOME", h.into()));
7380
format!(".env(\"RUSTUP_HOME\", env!(\"CARGO_RUSTUP_TEST_RUSTUP_HOME\"))")
7481
}
75-
None => format!(".env_remove(\"RUSTUP_HOME\")"),
82+
None => String::new(),
7683
};
7784
make_exe(
7885
bin_dir,
@@ -82,6 +89,7 @@ fn real_rustc_wrapper(bin_dir: &Path, message: &str) -> PathBuf {
8289
eprintln!("{message}");
8390
let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_real_rustc"))
8491
.args(std::env::args_os().skip(1))
92+
{rustup_toolchain_source_setup}
8593
{rustup_toolchain_setup}
8694
{rustup_home_setup}
8795
.status();
@@ -322,58 +330,157 @@ custom toolchain rustc running
322330
/// rustup environment. The purpose is to verify the warning that is emitted.
323331
#[cargo_test]
324332
fn cargo_install_with_toolchain_source_unset() {
325-
cargo_install_with_toolchain_source(None, &warning_with_optional_rust_toolchain_source(None));
333+
cargo_install_with_toolchain_source(
334+
None,
335+
str![[r#"
336+
[..]/cargo[EXE]` proxy running
337+
[UPDATING] `dummy-registry` index
338+
[DOWNLOADING] crates ...
339+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
340+
[INSTALLING] foo v0.0.1
341+
[COMPILING] foo v0.0.1
342+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
343+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
344+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
345+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
346+
347+
"#]],
348+
);
326349
}
327350

328351
#[cargo_test]
329352
fn cargo_install_with_toolchain_source_default() {
330353
cargo_install_with_toolchain_source(
331354
Some("default"),
332-
&warning_with_optional_rust_toolchain_source(None),
355+
str![[r#"
356+
[..]/cargo[EXE]` proxy running
357+
[UPDATING] `dummy-registry` index
358+
[DOWNLOADING] crates ...
359+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
360+
[INSTALLING] foo v0.0.1
361+
[COMPILING] foo v0.0.1
362+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
363+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
364+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
365+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
366+
367+
"#]],
333368
);
334369
}
335370

336371
#[cargo_test]
337372
fn cargo_install_with_toolchain_source_cli() {
338373
cargo_install_with_toolchain_source(
339374
Some("cli"),
340-
&warning_with_optional_rust_toolchain_source(None),
375+
str![[r#"
376+
[..]/cargo[EXE]` proxy running
377+
[UPDATING] `dummy-registry` index
378+
[DOWNLOADING] crates ...
379+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
380+
[INSTALLING] foo v0.0.1
381+
[COMPILING] foo v0.0.1
382+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
383+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
384+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
385+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
386+
387+
"#]],
341388
);
342389
}
343390

344391
#[cargo_test]
345392
fn cargo_install_with_toolchain_source_env() {
346393
cargo_install_with_toolchain_source(
347394
Some("env"),
348-
&warning_with_optional_rust_toolchain_source(None),
395+
str![[r#"
396+
[..]/cargo[EXE]` proxy running
397+
[UPDATING] `dummy-registry` index
398+
[DOWNLOADING] crates ...
399+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
400+
[INSTALLING] foo v0.0.1
401+
[WARNING] using non-default toolchain `test-toolchain` overridden by env
402+
|
403+
= [HELP] use `cargo +stable install` if you meant to use the stable toolchain.
404+
[COMPILING] foo v0.0.1
405+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
406+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
407+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
408+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
409+
410+
"#]],
349411
);
350412
}
351413

352414
#[cargo_test]
353415
fn cargo_install_with_toolchain_source_path_override() {
354416
cargo_install_with_toolchain_source(
355417
Some("path-override"),
356-
&warning_with_optional_rust_toolchain_source(None),
418+
str![[r#"
419+
[..]/cargo[EXE]` proxy running
420+
[UPDATING] `dummy-registry` index
421+
[DOWNLOADING] crates ...
422+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
423+
[INSTALLING] foo v0.0.1
424+
[WARNING] using non-default toolchain `test-toolchain` overridden by path-override
425+
|
426+
= [HELP] use `cargo +stable install` if you meant to use the stable toolchain.
427+
[COMPILING] foo v0.0.1
428+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
429+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
430+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
431+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
432+
433+
"#]],
357434
);
358435
}
359436

360437
#[cargo_test]
361438
fn cargo_install_with_toolchain_source_toolchain_file() {
362439
cargo_install_with_toolchain_source(
363440
Some("toolchain-file"),
364-
&warning_with_optional_rust_toolchain_source(None),
441+
str![[r#"
442+
[..]/cargo[EXE]` proxy running
443+
[UPDATING] `dummy-registry` index
444+
[DOWNLOADING] crates ...
445+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
446+
[INSTALLING] foo v0.0.1
447+
[WARNING] using non-default toolchain `test-toolchain` overridden by toolchain-file
448+
|
449+
= [HELP] use `cargo +stable install` if you meant to use the stable toolchain.
450+
[COMPILING] foo v0.0.1
451+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
452+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
453+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
454+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
455+
456+
"#]],
365457
);
366458
}
367459

368460
#[cargo_test]
369461
fn cargo_install_with_toolchain_source_unrecognized() {
370462
cargo_install_with_toolchain_source(
371463
Some("unrecognized"),
372-
&warning_with_optional_rust_toolchain_source(None),
464+
str![[r#"
465+
[..]/cargo[EXE]` proxy running
466+
[UPDATING] `dummy-registry` index
467+
[DOWNLOADING] crates ...
468+
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
469+
[INSTALLING] foo v0.0.1
470+
[WARNING] using non-default toolchain `test-toolchain` overridden by unrecognized
471+
|
472+
= [HELP] use `cargo +stable install` if you meant to use the stable toolchain.
473+
[COMPILING] foo v0.0.1
474+
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
475+
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
476+
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
477+
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
478+
479+
"#]],
373480
);
374481
}
375482

376-
fn cargo_install_with_toolchain_source(source: Option<&str>, stderr: &str) {
483+
fn cargo_install_with_toolchain_source(source: Option<&str>, stderr: impl snapbox::IntoData) {
377484
let mut builder = RustupEnvironmentBuilder::new();
378485
builder.call_cargo_under_test();
379486
builder.env("RUSTUP_TOOLCHAIN", "test-toolchain");
@@ -398,30 +505,3 @@ fn cargo_install_with_toolchain_source(source: Option<&str>, stderr: &str) {
398505
.run();
399506
assert_has_installed_exe(cargo_home(), "foo");
400507
}
401-
402-
fn warning_with_optional_rust_toolchain_source(source: Option<&str>) -> String {
403-
let maybe_warning = if let Some(source) = source {
404-
format!(
405-
r#"[WARNING] using non-default toolchain `test-toolchain` overridden by {}
406-
|
407-
= [HELP] use `cargo +stable install` if you meant to use the stable toolchain.
408-
"#,
409-
source
410-
)
411-
} else {
412-
String::new()
413-
};
414-
format!(
415-
r#"`[..]/cargo[EXE]` proxy running
416-
[UPDATING] `dummy-registry` index
417-
[DOWNLOADING] crates ...
418-
[DOWNLOADED] foo v0.0.1 (registry `dummy-registry`)
419-
[INSTALLING] foo v0.0.1
420-
{maybe_warning}[COMPILING] foo v0.0.1
421-
[FINISHED] `release` profile [optimized] target(s) in [ELAPSED]s
422-
[INSTALLING] [ROOT]/home/.cargo/bin/foo[EXE]
423-
[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
424-
[WARNING] be sure to add `[ROOT]/home/.cargo/bin` to your PATH to be able to run the installed binaries
425-
"#
426-
)
427-
}

0 commit comments

Comments
 (0)