Skip to content

Commit c2db7da

Browse files
committed
Rework toolchain file parsing
1 parent 15642fe commit c2db7da

File tree

4 files changed

+105
-110
lines changed

4 files changed

+105
-110
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
415415
```
416416

417417
If the TOML format is used, the `[toolchain]` section is mandatory,
418-
but all its entries are optional.
418+
and at least one property must be specified.
419419

420420
The `rust-toolchain` file is suitable to check in to source control.
421421
This file has to be encoded in US-ASCII (if you are on

src/config.rs

Lines changed: 94 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -555,32 +555,24 @@ impl Cfg {
555555
// Then look for 'rust-toolchain'
556556
let toolchain_file = d.join("rust-toolchain");
557557
if let Ok(contents) = utils::read_file("toolchain file", &toolchain_file) {
558-
if let (Some(override_file), toml_err) = Cfg::parse_override_file(contents) {
559-
if let Some(toolchain_name) = &override_file.toolchain.channel {
560-
let all_toolchains = self.list_toolchains()?;
561-
if !all_toolchains.iter().any(|s| s == toolchain_name) {
562-
// The given name is not resolvable as a toolchain, so
563-
// instead check it's plausible for installation later
564-
let mut validation = dist::validate_channel_name(&toolchain_name)
565-
.chain_err(|| {
566-
format!(
567-
"error parsing override file as legacy format: invalid channel name '{}' in '{}'",
568-
toolchain_name,
569-
toolchain_file.display()
570-
)
571-
});
572-
// If there was an error parsing the toolchain file as TOML, report it now.
573-
// This can help if the toolchain file is actually TOML but there was a syntax error.
574-
if let Some(err) = toml_err {
575-
validation = validation.chain_err(|| err);
576-
}
577-
validation?;
578-
}
558+
let override_file = Cfg::parse_override_file(contents)?;
559+
if let Some(toolchain_name) = &override_file.toolchain.channel {
560+
let all_toolchains = self.list_toolchains()?;
561+
if !all_toolchains.iter().any(|s| s == toolchain_name) {
562+
// The given name is not resolvable as a toolchain, so
563+
// instead check it's plausible for installation later
564+
dist::validate_channel_name(&toolchain_name).chain_err(|| {
565+
format!(
566+
"invalid channel name '{}' in '{}'",
567+
toolchain_name,
568+
toolchain_file.display()
569+
)
570+
})?;
579571
}
580-
581-
let reason = OverrideReason::ToolchainFile(toolchain_file);
582-
return Ok(Some((override_file, reason)));
583572
}
573+
574+
let reason = OverrideReason::ToolchainFile(toolchain_file);
575+
return Ok(Some((override_file, reason)));
584576
}
585577

586578
dir = d.parent();
@@ -589,27 +581,30 @@ impl Cfg {
589581
Ok(None)
590582
}
591583

592-
fn parse_override_file<S: AsRef<str>>(
593-
contents: S,
594-
) -> (Option<OverrideFile>, Option<ErrorKind>) {
584+
fn parse_override_file<S: AsRef<str>>(contents: S) -> Result<OverrideFile> {
595585
let contents = contents.as_ref();
596586

597-
// Avoid TOML parsing error for backwards compatibility with the legacy format
598-
if contents.is_empty() {
599-
return (None, None);
600-
}
587+
match contents.lines().count() {
588+
0 => return Err(ErrorKind::EmptyOverrideFile.into()),
589+
1 => {
590+
let channel = contents.trim();
601591

602-
// Try to parse as TOML ...
603-
match toml::from_str::<OverrideFile>(contents)
604-
.map(|file| if file.is_empty() { None } else { Some(file) })
605-
.map_err(ErrorKind::ParsingOverride)
606-
{
607-
Ok(override_file) => (override_file, None),
608-
// ... in case of error, try to parse as the legacy format
609-
Err(toml_err) => (
610-
contents.lines().next().map(|line| line.trim().into()),
611-
Some(toml_err),
612-
),
592+
if channel.is_empty() {
593+
Err(ErrorKind::EmptyOverrideFile.into())
594+
} else {
595+
Ok(channel.into())
596+
}
597+
}
598+
_ => {
599+
let override_file = toml::from_str::<OverrideFile>(contents)
600+
.map_err(ErrorKind::ParsingOverrideFile)?;
601+
602+
if override_file.is_empty() {
603+
Err(ErrorKind::InvalidOverrideFile.into())
604+
} else {
605+
Ok(override_file)
606+
}
607+
}
613608
}
614609
}
615610

@@ -881,32 +876,31 @@ mod tests {
881876
fn parse_legacy_toolchain_file() {
882877
let contents = "nightly-2020-07-10";
883878

884-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
879+
let result = Cfg::parse_override_file(contents);
885880
assert_eq!(
886-
override_file,
887-
Some(OverrideFile {
881+
result.unwrap(),
882+
OverrideFile {
888883
toolchain: ToolchainSection {
889884
channel: Some(contents.into()),
890-
..Default::default()
885+
components: None,
886+
targets: None,
891887
}
892-
})
888+
}
893889
);
894-
assert!(toml_err.is_some());
895890
}
896891

897892
#[test]
898893
fn parse_toml_toolchain_file() {
899-
let contents = r#"
900-
[toolchain]
894+
let contents = r#"[toolchain]
901895
channel = "nightly-2020-07-10"
902896
components = [ "rustfmt", "rustc-dev" ]
903897
targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
904898
"#;
905899

906-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
900+
let result = Cfg::parse_override_file(contents);
907901
assert_eq!(
908-
override_file,
909-
Some(OverrideFile {
902+
result.unwrap(),
903+
OverrideFile {
910904
toolchain: ToolchainSection {
911905
channel: Some("nightly-2020-07-10".into()),
912906
components: Some(vec!["rustfmt".into(), "rustc-dev".into()]),
@@ -915,95 +909,86 @@ targets = [ "wasm32-unknown-unknown", "thumbv2-none-eabi" ]
915909
"thumbv2-none-eabi".into()
916910
]),
917911
}
918-
})
912+
}
919913
);
920-
assert!(toml_err.is_none());
921914
}
922915

923916
#[test]
924917
fn parse_toml_toolchain_file_only_channel() {
925-
let contents = r#"
926-
[toolchain]
918+
let contents = r#"[toolchain]
927919
channel = "nightly-2020-07-10"
928920
"#;
929921

930-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
922+
let result = Cfg::parse_override_file(contents);
931923
assert_eq!(
932-
override_file,
933-
Some(OverrideFile {
924+
result.unwrap(),
925+
OverrideFile {
934926
toolchain: ToolchainSection {
935927
channel: Some("nightly-2020-07-10".into()),
936928
components: None,
937929
targets: None,
938930
}
939-
})
931+
}
940932
);
941-
assert!(toml_err.is_none());
942933
}
943934

944935
#[test]
945936
fn parse_toml_toolchain_file_empty_components() {
946-
let contents = r#"
947-
[toolchain]
937+
let contents = r#"[toolchain]
948938
channel = "nightly-2020-07-10"
949939
components = []
950940
"#;
951941

952-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
942+
let result = Cfg::parse_override_file(contents);
953943
assert_eq!(
954-
override_file,
955-
Some(OverrideFile {
944+
result.unwrap(),
945+
OverrideFile {
956946
toolchain: ToolchainSection {
957947
channel: Some("nightly-2020-07-10".into()),
958948
components: Some(vec![]),
959949
targets: None,
960950
}
961-
})
951+
}
962952
);
963-
assert!(toml_err.is_none());
964953
}
965954

966955
#[test]
967956
fn parse_toml_toolchain_file_empty_targets() {
968-
let contents = r#"
969-
[toolchain]
957+
let contents = r#"[toolchain]
970958
channel = "nightly-2020-07-10"
971959
targets = []
972960
"#;
973961

974-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
962+
let result = Cfg::parse_override_file(contents);
975963
assert_eq!(
976-
override_file,
977-
Some(OverrideFile {
964+
result.unwrap(),
965+
OverrideFile {
978966
toolchain: ToolchainSection {
979967
channel: Some("nightly-2020-07-10".into()),
980968
components: None,
981969
targets: Some(vec![]),
982970
}
983-
})
971+
}
984972
);
985-
assert!(toml_err.is_none());
986973
}
987974

988975
#[test]
989976
fn parse_toml_toolchain_file_no_channel() {
990-
let contents = r#"
991-
[toolchain]
977+
let contents = r#"[toolchain]
992978
components = [ "rustfmt" ]
993979
"#;
994980

995-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
981+
let result = Cfg::parse_override_file(contents);
996982
assert_eq!(
997-
override_file,
998-
Some(OverrideFile {
983+
result.unwrap(),
984+
OverrideFile {
999985
toolchain: ToolchainSection {
1000986
channel: None,
1001987
components: Some(vec!["rustfmt".into()]),
1002988
targets: None,
1003989
}
1004-
})
990+
}
1005991
);
1006-
assert!(toml_err.is_none());
1007992
}
1008993

1009994
#[test]
@@ -1012,18 +997,33 @@ components = [ "rustfmt" ]
1012997
[toolchain]
1013998
"#;
1014999

1015-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
1016-
assert!(override_file.is_none());
1017-
assert!(toml_err.is_none());
1000+
let result = Cfg::parse_override_file(contents);
1001+
assert!(matches!(
1002+
result.unwrap_err().kind(),
1003+
ErrorKind::InvalidOverrideFile
1004+
));
10181005
}
10191006

10201007
#[test]
10211008
fn parse_empty_toolchain_file() {
10221009
let contents = "";
10231010

1024-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
1025-
assert!(override_file.is_none());
1026-
assert!(toml_err.is_none());
1011+
let result = Cfg::parse_override_file(contents);
1012+
assert!(matches!(
1013+
result.unwrap_err().kind(),
1014+
ErrorKind::EmptyOverrideFile
1015+
));
1016+
}
1017+
1018+
#[test]
1019+
fn parse_whitespace_toolchain_file() {
1020+
let contents = " ";
1021+
1022+
let result = Cfg::parse_override_file(contents);
1023+
assert!(matches!(
1024+
result.unwrap_err().kind(),
1025+
ErrorKind::EmptyOverrideFile
1026+
));
10271027
}
10281028

10291029
#[test]
@@ -1032,16 +1032,10 @@ components = [ "rustfmt" ]
10321032
channel = nightly
10331033
"#;
10341034

1035-
let (override_file, toml_err) = Cfg::parse_override_file(contents);
1036-
assert_eq!(
1037-
override_file,
1038-
Some(OverrideFile {
1039-
toolchain: ToolchainSection {
1040-
channel: Some("[toolchain]".into()),
1041-
..Default::default()
1042-
}
1043-
})
1044-
);
1045-
assert!(toml_err.is_some());
1035+
let result = Cfg::parse_override_file(contents);
1036+
assert!(matches!(
1037+
result.unwrap_err().kind(),
1038+
ErrorKind::ParsingOverrideFile(..)
1039+
));
10461040
}
10471041
}

src/errors.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,6 @@ error_chain! {
356356
ParsingSettings(e: toml::de::Error) {
357357
description("error parsing settings")
358358
}
359-
ParsingOverride(e: toml::de::Error) {
360-
description("error parsing override file as TOML")
361-
}
362359
NoExeName {
363360
description("couldn't determine self executable name")
364361
}
@@ -377,6 +374,15 @@ error_chain! {
377374
BrokenPartialFile {
378375
description("partially downloaded file may have been damaged and was removed, please try again")
379376
}
377+
EmptyOverrideFile {
378+
description("empty toolchain override file detected. Please remove it, or else specify the desired toolchain properties in the file")
379+
}
380+
InvalidOverrideFile {
381+
description("missing toolchain properties in toolchain override file")
382+
}
383+
ParsingOverrideFile(e: toml::de::Error) {
384+
description("error parsing override file")
385+
}
380386
}
381387
}
382388

tests/cli-rustup.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,12 +1706,7 @@ fn bad_file_override() {
17061706
expect_err(
17071707
config,
17081708
&["rustc", "--version"],
1709-
"error parsing override file as legacy format: invalid channel name 'gumbo' in",
1710-
);
1711-
expect_err(
1712-
config,
1713-
&["rustc", "--version"],
1714-
"error parsing override file as TOML",
1709+
"invalid channel name 'gumbo' in",
17151710
);
17161711
});
17171712
}

0 commit comments

Comments
 (0)