use std::{env, process::Command, str};
pub(crate) fn rustc_version() -> Option<Version> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).args(&["--version", "--verbose"]).output().ok()?;
let verbose_version = str::from_utf8(&output.stdout).ok()?;
Version::parse(verbose_version)
}
pub(crate) struct Version {
pub(crate) minor: u32,
pub(crate) nightly: bool,
commit_date: Date,
}
impl Version {
pub(crate) const LATEST: Self = Self::stable(69);
const fn stable(minor: u32) -> Self {
Self { minor, nightly: false, commit_date: Date::UNKNOWN }
}
pub(crate) fn probe(&self, minor: u32, year: u16, month: u8, day: u8) -> bool {
if self.nightly {
self.minor > minor || self.commit_date >= Date::new(year, month, day)
} else {
self.minor >= minor
}
}
pub(crate) fn parse(verbose_version: &str) -> Option<Self> {
let mut release = verbose_version
.lines()
.find(|line| line.starts_with("release: "))
.map(|line| &line["release: ".len()..])?
.splitn(2, '-');
let version = release.next().unwrap();
let channel = release.next().unwrap_or_default();
let mut digits = version.splitn(3, '.');
let major = digits.next()?.parse::<u32>().ok()?;
if major != 1 {
return None;
}
let minor = digits.next()?.parse::<u32>().ok()?;
let _patch = digits.next().unwrap_or("0").parse::<u32>().ok()?;
let nightly = channel == "nightly" || channel == "dev";
if nightly {
let commit_date = (|| {
let mut commit_date = verbose_version
.lines()
.find(|line| line.starts_with("commit-date: "))
.map(|line| &line["commit-date: ".len()..])?
.splitn(3, '-');
let year = commit_date.next()?.parse::<u16>().ok()?;
let month = commit_date.next()?.parse::<u8>().ok()?;
let day = commit_date.next()?.parse::<u8>().ok()?;
if month > 12 || day > 31 {
return None;
}
Some(Date::new(year, month, day))
})();
Some(Version { minor, nightly, commit_date: commit_date.unwrap_or(Date::UNKNOWN) })
} else {
Some(Version::stable(minor))
}
}
}
#[derive(PartialEq, PartialOrd)]
struct Date {
year: u16,
month: u8,
day: u8,
}
impl Date {
const UNKNOWN: Self = Self::new(0, 0, 0);
const fn new(year: u16, month: u8, day: u8) -> Self {
Self { year, month, day }
}
}