Skip to content

Commit 8d6ebff

Browse files
committed
Allow .toml extension for rust-toolchain files
Only the TOML format is supported in `rust-toolchain.toml` files. If both `rust-toolchain` and `rust-toolchain.toml` are present in a folder, rustup prints a warning and uses `rust-toolchain`.
1 parent 019b9b4 commit 8d6ebff

File tree

2 files changed

+78
-19
lines changed

2 files changed

+78
-19
lines changed

src/config.rs

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -567,10 +567,36 @@ impl Cfg {
567567
return Ok(Some((name.into(), reason)));
568568
}
569569

570-
// Then look for 'rust-toolchain'
571-
let toolchain_file = d.join("rust-toolchain");
572-
if let Ok(contents) = utils::read_file("toolchain file", &toolchain_file) {
573-
let override_file = Cfg::parse_override_file(contents)?;
570+
// Then look for 'rust-toolchain' or 'rust-toolchain.toml'
571+
let path_rust_toolchain = d.join("rust-toolchain");
572+
let path_rust_toolchain_toml = d.join("rust-toolchain.toml");
573+
574+
let (toolchain_file, contents, parse_mode) = match (
575+
utils::read_file("toolchain file", &path_rust_toolchain),
576+
utils::read_file("toolchain file", &path_rust_toolchain_toml),
577+
) {
578+
(contents, Err(_)) => {
579+
// no `rust-toolchain.toml` exists
580+
(path_rust_toolchain, contents, ParseMode::Both)
581+
}
582+
(Err(_), Ok(contents)) => {
583+
// only `rust-toolchain.toml` exists
584+
(path_rust_toolchain_toml, Ok(contents), ParseMode::OnlyToml)
585+
}
586+
(Ok(contents), Ok(_)) => {
587+
// both `rust-toolchain` and `rust-toolchain.toml` exist
588+
589+
notify(Notification::DuplicateToolchainFile {
590+
rust_toolchain: &path_rust_toolchain,
591+
rust_toolchain_toml: &path_rust_toolchain_toml,
592+
});
593+
594+
(path_rust_toolchain, Ok(contents), ParseMode::Both)
595+
}
596+
};
597+
598+
if let Ok(contents) = contents {
599+
let override_file = Cfg::parse_override_file(contents, parse_mode)?;
574600
if let Some(toolchain_name) = &override_file.toolchain.channel {
575601
let all_toolchains = self.list_toolchains()?;
576602
if !all_toolchains.iter().any(|s| s == toolchain_name) {
@@ -590,12 +616,15 @@ impl Cfg {
590616
Ok(None)
591617
}
592618

593-
fn parse_override_file<S: AsRef<str>>(contents: S) -> Result<OverrideFile> {
619+
fn parse_override_file<S: AsRef<str>>(
620+
contents: S,
621+
parse_mode: ParseMode,
622+
) -> Result<OverrideFile> {
594623
let contents = contents.as_ref();
595624

596-
match contents.lines().count() {
597-
0 => Err(ErrorKind::EmptyOverrideFile.into()),
598-
1 => {
625+
match (contents.lines().count(), parse_mode) {
626+
(0, _) => Err(ErrorKind::EmptyOverrideFile.into()),
627+
(1, ParseMode::Both) => {
599628
let channel = contents.trim();
600629

601630
if channel.is_empty() {
@@ -898,6 +927,20 @@ impl Cfg {
898927
}
899928
}
900929

930+
/// Specifies how a `rust-toolchain`/`rust-toolchain.toml` configuration file should be parsed.
931+
enum ParseMode {
932+
/// Only permit TOML format in a configuration file.
933+
///
934+
/// This variant is used for `rust-toolchain.toml` files (with `.toml` extension).
935+
OnlyToml,
936+
/// Permit both the legacy format (i.e. just the channel name) and the TOML format in
937+
/// a configuration file.
938+
///
939+
/// This variant is used for `rust-toolchain` files (no file extension) for backwards
940+
/// compatibility.
941+
Both,
942+
}
943+
901944
#[cfg(test)]
902945
mod tests {
903946
use super::*;
@@ -906,7 +949,7 @@ mod tests {
906949
fn parse_legacy_toolchain_file() {
907950
let contents = "nightly-2020-07-10";
908951

909-
let result = Cfg::parse_override_file(contents);
952+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
910953
assert_eq!(
911954
result.unwrap(),
912955
OverrideFile {
@@ -929,7 +972,7 @@ targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
929972
profile = "default"
930973
"#;
931974

932-
let result = Cfg::parse_override_file(contents);
975+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
933976
assert_eq!(
934977
result.unwrap(),
935978
OverrideFile {
@@ -952,7 +995,7 @@ profile = "default"
952995
channel = "nightly-2020-07-10"
953996
"#;
954997

955-
let result = Cfg::parse_override_file(contents);
998+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
956999
assert_eq!(
9571000
result.unwrap(),
9581001
OverrideFile {
@@ -973,7 +1016,7 @@ channel = "nightly-2020-07-10"
9731016
components = []
9741017
"#;
9751018

976-
let result = Cfg::parse_override_file(contents);
1019+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
9771020
assert_eq!(
9781021
result.unwrap(),
9791022
OverrideFile {
@@ -994,7 +1037,7 @@ channel = "nightly-2020-07-10"
9941037
targets = []
9951038
"#;
9961039

997-
let result = Cfg::parse_override_file(contents);
1040+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
9981041
assert_eq!(
9991042
result.unwrap(),
10001043
OverrideFile {
@@ -1014,7 +1057,7 @@ targets = []
10141057
components = [ "rustfmt" ]
10151058
"#;
10161059

1017-
let result = Cfg::parse_override_file(contents);
1060+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
10181061
assert_eq!(
10191062
result.unwrap(),
10201063
OverrideFile {
@@ -1034,7 +1077,7 @@ components = [ "rustfmt" ]
10341077
[toolchain]
10351078
"#;
10361079

1037-
let result = Cfg::parse_override_file(contents);
1080+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
10381081
assert!(matches!(
10391082
result.unwrap_err().kind(),
10401083
ErrorKind::InvalidOverrideFile
@@ -1045,7 +1088,7 @@ components = [ "rustfmt" ]
10451088
fn parse_empty_toolchain_file() {
10461089
let contents = "";
10471090

1048-
let result = Cfg::parse_override_file(contents);
1091+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
10491092
assert!(matches!(
10501093
result.unwrap_err().kind(),
10511094
ErrorKind::EmptyOverrideFile
@@ -1056,7 +1099,7 @@ components = [ "rustfmt" ]
10561099
fn parse_whitespace_toolchain_file() {
10571100
let contents = " ";
10581101

1059-
let result = Cfg::parse_override_file(contents);
1102+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
10601103
assert!(matches!(
10611104
result.unwrap_err().kind(),
10621105
ErrorKind::EmptyOverrideFile
@@ -1069,7 +1112,7 @@ components = [ "rustfmt" ]
10691112
channel = nightly
10701113
"#;
10711114

1072-
let result = Cfg::parse_override_file(contents);
1115+
let result = Cfg::parse_override_file(contents, ParseMode::Both);
10731116
assert!(matches!(
10741117
result.unwrap_err().kind(),
10751118
ErrorKind::ParsingOverrideFile(..)

src/notifications.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ pub enum Notification<'a> {
3333
UpgradeRemovesToolchains,
3434
MissingFileDuringSelfUninstall(PathBuf),
3535
PlainVerboseMessage(&'a str),
36+
/// Both `rust-toolchain` and `rust-toolchain.toml` exist within a directory
37+
DuplicateToolchainFile {
38+
rust_toolchain: &'a Path,
39+
rust_toolchain_toml: &'a Path,
40+
},
3641
}
3742

3843
impl<'a> From<crate::dist::Notification<'a>> for Notification<'a> {
@@ -77,7 +82,9 @@ impl<'a> Notification<'a> {
7782
| UpgradingMetadata(_, _)
7883
| MetadataUpgradeNotNeeded(_) => NotificationLevel::Info,
7984
NonFatalError(_) => NotificationLevel::Error,
80-
UpgradeRemovesToolchains | MissingFileDuringSelfUninstall(_) => NotificationLevel::Warn,
85+
UpgradeRemovesToolchains
86+
| MissingFileDuringSelfUninstall(_)
87+
| DuplicateToolchainFile { .. } => NotificationLevel::Warn,
8188
}
8289
}
8390
}
@@ -130,6 +137,15 @@ impl<'a> Display for Notification<'a> {
130137
p.display()
131138
),
132139
PlainVerboseMessage(r) => write!(f, "{}", r),
140+
DuplicateToolchainFile {
141+
rust_toolchain,
142+
rust_toolchain_toml,
143+
} => write!(
144+
f,
145+
"both `{0}` and `{1}` exist. Using `{0}`",
146+
rust_toolchain.display(),
147+
rust_toolchain_toml.display()
148+
),
133149
}
134150
}
135151
}

0 commit comments

Comments
 (0)