Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cli/proxy_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub async fn main(arg0: &str, current_dir: PathBuf, process: &Process) -> Result
.skip(1 + toolchain.is_some() as usize)
.collect();

let cfg = Cfg::from_env(current_dir, false, process)?;
let cfg = Cfg::from_env(current_dir, false, true, process)?;
let (toolchain, source) = cfg
.local_toolchain(match toolchain {
Some(name) => Some((
Expand Down
115 changes: 80 additions & 35 deletions src/cli/rustup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,15 +631,41 @@ pub async fn main(

update_console_filter(process, &console_filter, matches.quiet, matches.verbose);

let cfg = &mut Cfg::from_env(current_dir, matches.quiet, process)?;
cfg.toolchain_override = matches.plus_toolchain;

let Some(subcmd) = matches.subcmd else {
let help = Rustup::command().render_long_help();
writeln!(process.stderr().lock(), "{}", help.ansi())?;
return Ok(ExitCode::FAILURE);
};

let allow_auto_install = match subcmd {
// These subcommands execute or rely on the active toolchain, so auto-installing it when
// missing may be reasonable depending on the user's decision.
#[cfg(not(windows))]
RustupSubcmd::Man { .. } => true,
RustupSubcmd::Doc { .. } | RustupSubcmd::Run { .. } => true,

// These subcommands don't require the active toolchain, so auto-installing it should be
// disabled to avoid surprises.
RustupSubcmd::Check { .. }
| RustupSubcmd::Completions { .. }
| RustupSubcmd::Component { .. }
| RustupSubcmd::Default { .. }
| RustupSubcmd::DumpTestament
| RustupSubcmd::Install { .. }
| RustupSubcmd::Override { .. }
| RustupSubcmd::Self_ { .. }
| RustupSubcmd::Set { .. }
| RustupSubcmd::Show { .. }
| RustupSubcmd::Target { .. }
| RustupSubcmd::Toolchain { .. }
| RustupSubcmd::Uninstall { .. }
| RustupSubcmd::Update { .. }
| RustupSubcmd::Which { .. } => false,
};
Comment on lines +640 to +664
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: suggest moving this into a method attached to RustupSubCmd?


Comment on lines +640 to +665
let cfg = &mut Cfg::from_env(current_dir, matches.quiet, allow_auto_install, process)?;
cfg.toolchain_override = matches.plus_toolchain;

match subcmd {
RustupSubcmd::DumpTestament => common::dump_testament(process),
RustupSubcmd::Install { opts } => update(cfg, opts, true).await,
Expand Down Expand Up @@ -1146,21 +1172,6 @@ async fn show(cfg: &Cfg<'_>, verbose: bool) -> Result<ExitCode> {
.map(|atar| (&atar.0, &atar.1))
.unzip();

let active_toolchain_targets = match active_toolchain_name {
Some(ToolchainName::Official(desc)) => DistributableToolchain::new(cfg, desc.clone())?
.components()?
.into_iter()
.filter_map(|c| {
(c.installed && c.component.short_name() == "rust-std")
.then(|| c.component.target.expect("rust-std should have a target"))
})
.collect(),
Some(ToolchainName::Custom(name)) => {
Toolchain::new(cfg, LocalToolchainName::Named(name.into()))?.installed_targets()?
}
None => Vec::new(),
};

// show installed toolchains
{
let mut t = cfg.process.stdout();
Expand Down Expand Up @@ -1207,23 +1218,51 @@ async fn show(cfg: &Cfg<'_>, verbose: bool) -> Result<ExitCode> {

match active_toolchain_and_source {
Some((active_toolchain_name, active_source)) => {
let active_toolchain = Toolchain::with_source(
cfg,
active_toolchain_name.clone().into(),
&active_source,
)?;
writeln!(t.lock(), "name: {}", active_toolchain.name())?;
writeln!(t.lock(), "name: {active_toolchain_name}")?;
writeln!(t.lock(), "active because: {}", active_source.to_reason())?;
if verbose {
writeln!(t.lock(), "compiler: {}", active_toolchain.rustc_version())?;
writeln!(t.lock(), "path: {}", active_toolchain.path().display())?;
}

// show installed targets for the active toolchain
writeln!(t.lock(), "installed targets:")?;

Comment on lines +1195 to +1197
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks more or less unrelated, but feels related, maybe split it into a separate commit?

for target in active_toolchain_targets {
writeln!(t.lock(), " {target}")?;
match Toolchain::new(cfg, active_toolchain_name.clone().into()) {
Ok(active_toolchain) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, get this case out of the match if possible? By this point line 1218 is 13 levels deep which IMO is not a good state.

if verbose {
writeln!(t.lock(), "compiler: {}", active_toolchain.rustc_version())?;
writeln!(t.lock(), "path: {}", active_toolchain.path().display())?;
}

// show installed targets for the active toolchain
writeln!(t.lock(), "installed targets:")?;

let active_toolchain_targets = match active_toolchain_name {
ToolchainName::Official(desc) => {
DistributableToolchain::new(cfg, desc.clone())?
.components()?
.into_iter()
.filter_map(|c| {
(c.installed && c.component.short_name() == "rust-std")
.then(|| {
c.component
.target
.expect("rust-std should have a target")
})
})
.collect()
}
ToolchainName::Custom(name) => {
Toolchain::new(cfg, LocalToolchainName::Named(name.into()))?
.installed_targets()?
}
};

for target in active_toolchain_targets {
writeln!(t.lock(), " {target}")?;
}
}
Err(
RustupError::ToolchainNotInstalled { .. }
| RustupError::PathToolchainNotInstalled(..),
) => {
info!("the active toolchain `{active_toolchain_name}` is not installed");
}
Err(e) => return Err(e.into()),
}
}
None => {
Expand Down Expand Up @@ -1973,8 +2012,8 @@ fn output_completion_script(
}

async fn display_version(current_dir: PathBuf, process: &Process) -> Result<()> {
info!("This is the version for the rustup toolchain manager, not the rustc compiler.");
let mut cfg = Cfg::from_env(current_dir, true, process)?;
info!("this is the version for the rustup toolchain manager, not the rustc compiler");
let mut cfg = Cfg::from_env(current_dir, true, false, process)?;
cfg.toolchain_override = cfg
.process
.args()
Expand All @@ -1987,6 +2026,12 @@ async fn display_version(current_dir: PathBuf, process: &Process) -> Result<()>
"the currently active `rustc` version is `{}`",
tc.rustc_version()
),
Err(RustupError::ToolchainNotInstalled {
name,
is_active: true,
}) => {
info!("the active toolchain `{name}` is not installed");
}
Err(err) => error!("failed to display the current `rustc` version: {err}"),
},
Ok(None) => info!("no `rustc` is currently active"),
Expand Down
2 changes: 1 addition & 1 deletion src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1462,7 +1462,7 @@ mod tests {
home.apply(&mut vars);
let tp = TestProcess::with_vars(vars);
let mut cfg =
Cfg::from_env(tp.process.current_dir().unwrap(), false, &tp.process).unwrap();
Cfg::from_env(tp.process.current_dir().unwrap(), false, true, &tp.process).unwrap();

let opts = InstallOpts {
default_host_tuple: None,
Expand Down
2 changes: 1 addition & 1 deletion src/cli/setup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,6 @@ pub async fn main(
targets: &target.iter().map(|s| &**s).collect::<Vec<_>>(),
};

let mut cfg = Cfg::from_env(current_dir, quiet, process)?;
let mut cfg = Cfg::from_env(current_dir, quiet, false, process)?;
self_update::install(no_prompt, opts, &mut cfg).await
}
14 changes: 14 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,19 @@ pub(crate) struct Cfg<'a> {
pub quiet: bool,
pub current_dir: PathBuf,
pub process: &'a Process,

/// If this flag is set to `false`, it can stop `rustup` from automatically installing the
/// active toolchain in certain undesired cases, such as under `rustup component` and `rustup
/// target` subcommands. This effect has higher precedence than the `RUSTUP_AUTO_INSTALL`
/// environment variable and the `rustup set auto-install` setting.
pub allow_auto_install: bool,
}

impl<'a> Cfg<'a> {
pub(crate) fn from_env(
current_dir: PathBuf,
quiet: bool,
allow_auto_install: bool,
process: &'a Process,
) -> Result<Self> {
// Set up the rustup home directory
Expand Down Expand Up @@ -316,6 +323,7 @@ impl<'a> Cfg<'a> {
quiet,
current_dir,
process,
allow_auto_install,
};

// Run some basic checks against the constructed configuration
Expand Down Expand Up @@ -372,6 +380,10 @@ impl<'a> Cfg<'a> {
}

pub(crate) fn should_auto_install(&self) -> Result<bool> {
if !self.allow_auto_install {
return Ok(false);
}

if let Ok(mode) = self.process.var("RUSTUP_AUTO_INSTALL") {
Ok(mode != "0")
} else {
Expand Down Expand Up @@ -958,6 +970,7 @@ impl Debug for Cfg<'_> {
dist_root_url,
quiet,
current_dir,
allow_auto_install,
process: _,
} = self;

Expand All @@ -975,6 +988,7 @@ impl Debug for Cfg<'_> {
.field("dist_root_url", dist_root_url)
.field("quiet", quiet)
.field("current_dir", current_dir)
.field("allow_auto_install", allow_auto_install)
.finish()
}
}
Expand Down
12 changes: 6 additions & 6 deletions tests/suite/cli_misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async fn version_mentions_rustc_version_confusion() {
.await
.with_stderr(snapbox::str![[r#"
...
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: this is the version for the rustup toolchain manager, not the rustc compiler
...
"#]])
.is_ok();
Expand Down Expand Up @@ -1383,11 +1383,11 @@ async fn which_asking_uninstalled_toolchain() {
cx.config
.expect(["rustup", "which", "--toolchain=nightly", "rustc"])
.await
.with_stdout(snapbox::str![[r#"
[..]/toolchains/nightly-[HOST_TUPLE]/bin/rustc[EXE]

.with_stderr(snapbox::str![[r#"
error: toolchain 'nightly-[HOST_TUPLE]' is not installed
...
"#]])
.is_ok();
.is_err();
}

#[tokio::test]
Expand Down Expand Up @@ -1512,7 +1512,7 @@ active because: overridden by +toolchain on the command line
.expect(["rustup", "+foo", "which", "rustc"])
.await
.with_stderr(snapbox::str![[r#"
error: override toolchain 'foo' is not installed: the +toolchain on the command line specifies an uninstalled toolchain
error:[..] toolchain 'foo' is not installed[..]

"#]])
.is_err();
Expand Down
28 changes: 10 additions & 18 deletions tests/suite/cli_rustup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1218,14 +1218,21 @@ async fn show_toolchain_toolchain_file_override_not_installed() {
Default host: [HOST_TUPLE]
rustup home: [RUSTUP_DIR]

installed toolchains
--------------------
stable-[HOST_TUPLE] (default)

active toolchain
----------------
name: nightly-[HOST_TUPLE]
active because: overridden by '[TOOLCHAIN_FILE]'

"#]])
.with_stderr(snapbox::str![[r#"
error: toolchain 'nightly-[HOST_TUPLE]' is not installed
help: run `rustup toolchain install` to install it
info: the active toolchain `nightly-[HOST_TUPLE]` is not installed

"#]])
.is_err();
.is_ok();
}

#[tokio::test]
Expand Down Expand Up @@ -1254,22 +1261,9 @@ active toolchain
----------------
name: nightly-[HOST_TUPLE]
active because: directory override for '[..]'
installed targets:
[HOST_TUPLE]

"#]])
.is_ok();
cx.config
.expect(["rustup", "component", "list", "--installed"])
.await
.is_ok()
.with_stdout(snapbox::str![[r#"
cargo-[HOST_TUPLE]
rust-docs-[HOST_TUPLE]
rust-std-[HOST_TUPLE]
rustc-[HOST_TUPLE]

"#]]);
}

#[tokio::test]
Expand Down Expand Up @@ -1370,8 +1364,6 @@ active toolchain
----------------
name: nightly-[HOST_TUPLE]
active because: overridden by environment variable RUSTUP_TOOLCHAIN
installed targets:
[HOST_TUPLE]

"#]]);
}
Expand Down
6 changes: 3 additions & 3 deletions tests/suite/cli_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ async fn set_auto_install_disable() {
.await
.is_ok();
cx.config
.expect(["rustup", "target", "list", "--toolchain=nightly"])
.expect(["cargo", "+nightly", "--version"])
.await
.with_stderr(snapbox::str![[r#"
...
Expand All @@ -1220,7 +1220,7 @@ error: toolchain 'nightly-[HOST_TUPLE]' is not installed
.is_err();
cx.config
.expect_with_env(
["rustup", "target", "list", "--toolchain=nightly"],
["cargo", "+nightly", "--version"],
[("RUSTUP_AUTO_INSTALL", "0")],
)
.await
Expand All @@ -1233,7 +1233,7 @@ error: toolchain 'nightly-[HOST_TUPLE]' is not installed
// The environment variable takes precedence over the setting.
cx.config
.expect_with_env(
["rustup", "target", "list", "--toolchain=nightly"],
["cargo", "+nightly", "--version"],
[("RUSTUP_AUTO_INSTALL", "1")],
)
.await
Expand Down
Loading