Skip to content

Commit 6d00230

Browse files
committed
Auto-install toolchains more consistently
This combines all auto-installation logic to the root of the codepaths leading to running a binary, which should lead to auto-installation happening for all cases, as long as a toolchain has been selected. Config.find_default no longer verifies the toolchain in order to permit this auto-installation to take place in one location; the callers of find_default do not generally need verified toolchains, so this should be fine.
1 parent 6de2f76 commit 6d00230

File tree

5 files changed

+90
-69
lines changed

5 files changed

+90
-69
lines changed

src/cli/rustup_mode.rs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -928,22 +928,19 @@ fn show(cfg: &Cfg) -> Result<()> {
928928

929929
let cwd = utils::current_dir()?;
930930
let installed_toolchains = cfg.list_toolchains()?;
931-
let active_toolchain = cfg.find_override_toolchain_or_default(&cwd);
931+
// XXX: we may want a find_without_install capability for show.
932+
let active_toolchain = cfg.find_or_install_override_toolchain_or_default(&cwd);
932933

933934
// active_toolchain will carry the reason we don't have one in its detail.
934935
let active_targets = if let Ok(ref at) = active_toolchain {
935-
if let Some((ref t, _)) = *at {
936-
match t.list_components() {
937-
Ok(None) => vec![],
938-
Ok(Some(cs_vec)) => cs_vec
939-
.into_iter()
940-
.filter(|c| c.component.short_name_in_manifest() == "rust-std")
941-
.filter(|c| c.installed)
942-
.collect(),
943-
Err(_) => vec![],
944-
}
945-
} else {
946-
vec![]
936+
match at.0.list_components() {
937+
Ok(None) => vec![],
938+
Ok(Some(cs_vec)) => cs_vec
939+
.into_iter()
940+
.filter(|c| c.component.short_name_in_manifest() == "rust-std")
941+
.filter(|c| c.installed)
942+
.collect(),
943+
Err(_) => vec![],
947944
}
948945
} else {
949946
vec![]
@@ -1013,18 +1010,18 @@ fn show(cfg: &Cfg) -> Result<()> {
10131010

10141011
match active_toolchain {
10151012
Ok(atc) => match atc {
1016-
Some((ref toolchain, Some(ref reason))) => {
1013+
(ref toolchain, Some(ref reason)) => {
10171014
writeln!(t, "{} ({})", toolchain.name(), reason)?;
10181015
writeln!(t, "{}", toolchain.rustc_version())?;
10191016
}
1020-
Some((ref toolchain, None)) => {
1017+
(ref toolchain, None) => {
10211018
writeln!(t, "{} (default)", toolchain.name())?;
10221019
writeln!(t, "{}", toolchain.rustc_version())?;
10231020
}
1024-
None => {
1025-
writeln!(t, "no active toolchain")?;
1026-
}
10271021
},
1022+
Err(rustup::Error(rustup::ErrorKind::ToolchainNotSelected, _)) => {
1023+
writeln!(t, "no active toolchain")?;
1024+
}
10281025
Err(err) => {
10291026
if let Some(cause) = err.source() {
10301027
writeln!(t, "(error: {}, {})", err, cause)?;
@@ -1053,11 +1050,15 @@ fn show(cfg: &Cfg) -> Result<()> {
10531050

10541051
fn show_active_toolchain(cfg: &Cfg) -> Result<()> {
10551052
let cwd = utils::current_dir()?;
1056-
if let Some((toolchain, reason)) = cfg.find_override_toolchain_or_default(&cwd)? {
1057-
if let Some(reason) = reason {
1058-
println!("{} ({})", toolchain.name(), reason);
1059-
} else {
1060-
println!("{} (default)", toolchain.name());
1053+
match cfg.find_or_install_override_toolchain_or_default(&cwd) {
1054+
Err(rustup::Error(rustup::ErrorKind::ToolchainNotSelected, _)) => {}
1055+
Err(e) => return Err(e.into()),
1056+
Ok((toolchain, reason)) => {
1057+
if let Some(reason) = reason {
1058+
println!("{} ({})", toolchain.name(), reason);
1059+
} else {
1060+
println!("{} (default)", toolchain.name());
1061+
}
10611062
}
10621063
}
10631064
Ok(())

src/config.rs

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,8 @@ impl Cfg {
309309
}
310310

311311
pub fn which_binary(&self, path: &Path, binary: &str) -> Result<Option<PathBuf>> {
312-
if let Some((toolchain, _)) = self.find_override_toolchain_or_default(path)? {
313-
Ok(Some(toolchain.binary_file(binary)))
314-
} else {
315-
Ok(None)
316-
}
312+
let (toolchain, _) = self.find_or_install_override_toolchain_or_default(path)?;
313+
Ok(Some(toolchain.binary_file(binary)))
317314
}
318315

319316
pub fn upgrade_data(&self) -> Result<()> {
@@ -370,10 +367,7 @@ impl Cfg {
370367
.with(|s| Ok(s.default_toolchain.clone()))?;
371368

372369
if let Some(name) = opt_name {
373-
let toolchain = self
374-
.verify_toolchain(&name)
375-
.chain_err(|| ErrorKind::ToolchainNotInstalled(name.to_string()))?;
376-
370+
let toolchain = Toolchain::from(self, &name)?;
377371
Ok(Some(toolchain))
378372
} else {
379373
Ok(None)
@@ -427,24 +421,18 @@ impl Cfg {
427421
),
428422
};
429423

430-
match self.get_toolchain(&name, false) {
431-
Ok(toolchain) => {
432-
if toolchain.exists() {
433-
Ok(Some((toolchain, reason)))
434-
} else if toolchain.is_custom() {
435-
// Strip the confusing NotADirectory error and only mention that the
436-
// override toolchain is not installed.
437-
Err(Error::from(reason_err)).chain_err(|| {
438-
ErrorKind::OverrideToolchainNotInstalled(name.to_string())
439-
})
440-
} else {
441-
toolchain.install_from_dist(true, false, &[], &[])?;
442-
Ok(Some((toolchain, reason)))
443-
}
444-
}
445-
Err(e) => Err(e)
446-
.chain_err(|| Error::from(reason_err))
447-
.chain_err(|| ErrorKind::OverrideToolchainNotInstalled(name.to_string())),
424+
let toolchain = Toolchain::from(self, &name)?;
425+
// Overridden toolchains can be literally any string, but only
426+
// distributable toolchains will be auto-installed by the wrapping
427+
// code; provide a nice error for this common case. (default could
428+
// be set badly too, but that is much less common).
429+
if !toolchain.exists() && toolchain.is_custom() {
430+
// Strip the confusing NotADirectory error and only mention that the
431+
// override toolchain is not installed.
432+
Err(Error::from(reason_err))
433+
.chain_err(|| ErrorKind::OverrideToolchainNotInstalled(name.to_string()))
434+
} else {
435+
Ok(Some((toolchain, reason)))
448436
}
449437
} else {
450438
Ok(None)
@@ -495,17 +483,30 @@ impl Cfg {
495483
Ok(None)
496484
}
497485

498-
pub fn find_override_toolchain_or_default(
486+
pub fn find_or_install_override_toolchain_or_default(
499487
&self,
500488
path: &Path,
501-
) -> Result<Option<(Toolchain<'_>, Option<OverrideReason>)>> {
502-
Ok(
489+
) -> Result<(Toolchain<'_>, Option<OverrideReason>)> {
490+
if let Some((toolchain, reason)) =
503491
if let Some((toolchain, reason)) = self.find_override(path)? {
504492
Some((toolchain, Some(reason)))
505493
} else {
506494
self.find_default()?.map(|toolchain| (toolchain, None))
507-
},
508-
)
495+
}
496+
{
497+
if !toolchain.exists() {
498+
if toolchain.is_custom() {
499+
return Err(
500+
ErrorKind::ToolchainNotInstalled(toolchain.name().to_string()).into(),
501+
);
502+
}
503+
toolchain.install_from_dist(true, false, &[], &[])?;
504+
}
505+
Ok((toolchain, reason))
506+
} else {
507+
// No override and no default set
508+
Err(ErrorKind::ToolchainNotSelected.into())
509+
}
509510
}
510511

511512
pub fn get_default(&self) -> Result<Option<String>> {
@@ -581,8 +582,7 @@ impl Cfg {
581582
&self,
582583
path: &Path,
583584
) -> Result<(Toolchain<'_>, Option<OverrideReason>)> {
584-
self.find_override_toolchain_or_default(path)
585-
.and_then(|r| r.ok_or_else(|| "no default toolchain configured".into()))
585+
self.find_or_install_override_toolchain_or_default(path)
586586
}
587587

588588
pub fn create_command_for_dir(&self, path: &Path, binary: &str) -> Result<Command> {

src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ error_chain! {
300300
description("toolchain is not installed")
301301
display("toolchain '{}' is not installed", t)
302302
}
303+
ToolchainNotSelected {
304+
description("toolchain is not selected")
305+
display("no override and no default toolchain set")
306+
}
303307
OverrideToolchainNotInstalled(t: String) {
304308
description("override toolchain is not installed")
305309
display("override toolchain '{}' is not installed", t)

tests/cli-v1.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ pub fn setup(f: &dyn Fn(&mut Config)) {
2222
#[test]
2323
fn rustc_no_default_toolchain() {
2424
setup(&|config| {
25-
expect_err(config, &["rustc"], "no default toolchain configured");
25+
expect_err(
26+
config,
27+
&["rustc"],
28+
"no override and no default toolchain set",
29+
);
2630
});
2731
}
2832

@@ -158,14 +162,14 @@ fn remove_toolchain() {
158162
}
159163

160164
#[test]
161-
fn remove_default_toolchain_err_handling() {
165+
fn remove_default_toolchain_autoinstalls() {
162166
setup(&|config| {
163167
expect_ok(config, &["rustup", "default", "nightly"]);
164168
expect_ok(config, &["rustup", "toolchain", "remove", "nightly"]);
165-
expect_err(
169+
expect_stderr_ok(
166170
config,
167-
&["rustc"],
168-
for_host!("toolchain 'nightly-{0}' is not installed"),
171+
&["rustc", "--version"],
172+
"info: installing component",
169173
);
170174
});
171175
}
@@ -304,7 +308,11 @@ fn remove_override_no_default() {
304308
config.change_dir(tempdir.path(), &|| {
305309
expect_ok(config, &["rustup", "override", "add", "nightly"]);
306310
expect_ok(config, &["rustup", "override", "remove"]);
307-
expect_err(config, &["rustc"], "no default toolchain configured");
311+
expect_err(
312+
config,
313+
&["rustc"],
314+
"no override and no default toolchain set",
315+
);
308316
});
309317
});
310318
}

tests/cli-v2.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ pub fn setup_complex(f: &dyn Fn(&mut Config)) {
3030
#[test]
3131
fn rustc_no_default_toolchain() {
3232
setup(&|config| {
33-
expect_err(config, &["rustc"], "no default toolchain configured");
33+
expect_err(
34+
config,
35+
&["rustc"],
36+
"no override and no default toolchain set",
37+
);
3438
});
3539
}
3640

@@ -245,14 +249,14 @@ fn add_remove_multiple_toolchains() {
245249
}
246250

247251
#[test]
248-
fn remove_default_toolchain_err_handling() {
252+
fn remove_default_toolchain_autoinstalls() {
249253
setup(&|config| {
250254
expect_ok(config, &["rustup", "default", "nightly"]);
251255
expect_ok(config, &["rustup", "toolchain", "remove", "nightly"]);
252-
expect_err(
256+
expect_stderr_ok(
253257
config,
254-
&["rustc"],
255-
for_host!("toolchain 'nightly-{0}' is not installed"),
258+
&["rustc", "--version"],
259+
"info: installing component",
256260
);
257261
});
258262
}
@@ -446,7 +450,11 @@ fn remove_override_no_default() {
446450
config.change_dir(tempdir.path(), &|| {
447451
expect_ok(config, &["rustup", "override", "add", "nightly"]);
448452
expect_ok(config, &["rustup", "override", "remove"]);
449-
expect_err(config, &["rustc"], "no default toolchain configured");
453+
expect_err(
454+
config,
455+
&["rustc"],
456+
"no override and no default toolchain set",
457+
);
450458
});
451459
});
452460
}

0 commit comments

Comments
 (0)