diff --git a/CHANGELOG.md b/CHANGELOG.md index 3673829..1e77749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ A title is required for publishing a github release, so all versions should have ## Unreleased +### Added +- Give detailed error messages when version parsing fails. + Causes our version parsing to diverge from upstream rustversion. + ## 0.3.0 - 2026-07-24 Remove deprecated `maybe_const_fn!` macro. diff --git a/src/build/mod.rs b/src/build/mod.rs index 2ecea48..0c6bd53 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -65,7 +65,7 @@ pub fn determine_version() -> Result { is_mirai = true; continue; }, - rustc::ParseResult::Unrecognized + rustc::ParseResult::Unrecognized(desc) | rustc::ParseResult::OopsClippy | rustc::ParseResult::OopsMirai => { return Err(crate::VersionDetectionError::new(format!( diff --git a/src/build/rustc.rs b/src/build/rustc.rs index 25b97bd..964854f 100644 --- a/src/build/rustc.rs +++ b/src/build/rustc.rs @@ -4,7 +4,7 @@ pub enum ParseResult { Success(RustVersion), OopsClippy, OopsMirai, - Unrecognized, + Unrecognized(Option), } pub fn parse(string: &str) -> ParseResult { @@ -15,13 +15,18 @@ pub fn parse(string: &str) -> ParseResult { Some("rustc") => {} Some(word) if word.starts_with("clippy") => return ParseResult::OopsClippy, Some("mirai") => return ParseResult::OopsMirai, - Some(_) | None => return ParseResult::Unrecognized, + Some(word) => return ParseResult::Unrecognized(Some(format!("Unknown word {word:?}"))), + None => return ParseResult::Unregonized(Some("Missing initial word".into())), } - parse_words(&mut words).map_or(ParseResult::Unrecognized, ParseResult::Success) + match parse_words(&mut words) { + None => ParseResult::Unrecognized(None), + Some(Ok(version)) => ParseResult::Success(version), + Some(Err(desc)) => ParseResult::Unrecognized(Some(desc)), + } } -fn parse_words(words: &mut dyn Iterator) -> Option { +fn parse_words(words: &mut dyn Iterator) -> Option> { use crate::Channel::{Stable, Development, Beta, Nightly}; let mut version_channel = words.next()?.split('-'); @@ -33,6 +38,7 @@ fn parse_words(words: &mut dyn Iterator) -> Option { let minor = digits.next()?.parse().ok()?; let patch = digits.next().unwrap_or("0").parse().ok()?; + let bad_nightly_fmt_err = Some(Err("Unexpected nightly version format".into())); let channel = match channel { None => Stable, Some("dev") => Development, @@ -43,23 +49,23 @@ fn parse_words(words: &mut dyn Iterator) -> Option { Some(date) if date.ends_with(')') => { match date[..date.len() - 1].parse::() { Ok(date) => Nightly { date }, - Err(_) => return None, + Err(cause) => return Some(Err(format!("Failed to parse date: {cause}"))), } } - None | Some(_) => return None, + None | Some(_) => return bad_nightly_fmt_err, }, - Some(_) => return None, + Some(_) => return bad_nightly_fmt_err, None => Development, }, - Some(_) => return None, + Some(other) => return Some(Err(format!("Unknown channel {other:?}"))), }; - Some(RustVersion { + Some(Ok(RustVersion { major, minor, patch, channel, - }) + })) } /// Mirrors the `tests/test_parse.rs` integration test in rustversion. @@ -171,8 +177,11 @@ mod test { for (string, expected) in cases { match parse(string) { ParseResult::Success(version) => assert_eq!(version, *expected), - ParseResult::OopsClippy | ParseResult::OopsMirai | ParseResult::Unrecognized => { + ParseResult::OopsClippy | ParseResult::OopsMirai | ParseResult::Unrecognized(None) => { panic!("unrecognized: {:?}", string); + }, + ParseResult::Unrecognized(Some(desc)) => { + panic!("unrecognized: {:?} ({desc})", string); } } }