1f1555e47Sopenharmony_ciuse std::path::Path; 2f1555e47Sopenharmony_ciuse std::process::Command; 3f1555e47Sopenharmony_ciuse std::str; 4f1555e47Sopenharmony_ci 5f1555e47Sopenharmony_ciuse super::{error, Error}; 6f1555e47Sopenharmony_ci 7f1555e47Sopenharmony_ci/// A version structure for making relative comparisons. 8f1555e47Sopenharmony_ci#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 9f1555e47Sopenharmony_cipub struct Version { 10f1555e47Sopenharmony_ci major: usize, 11f1555e47Sopenharmony_ci minor: usize, 12f1555e47Sopenharmony_ci patch: usize, 13f1555e47Sopenharmony_ci} 14f1555e47Sopenharmony_ci 15f1555e47Sopenharmony_ciimpl Version { 16f1555e47Sopenharmony_ci /// Creates a `Version` instance for a specific `major.minor.patch` version. 17f1555e47Sopenharmony_ci pub fn new(major: usize, minor: usize, patch: usize) -> Self { 18f1555e47Sopenharmony_ci Version { 19f1555e47Sopenharmony_ci major: major, 20f1555e47Sopenharmony_ci minor: minor, 21f1555e47Sopenharmony_ci patch: patch, 22f1555e47Sopenharmony_ci } 23f1555e47Sopenharmony_ci } 24f1555e47Sopenharmony_ci 25f1555e47Sopenharmony_ci pub fn from_rustc(rustc: &Path) -> Result<Self, Error> { 26f1555e47Sopenharmony_ci // Get rustc's verbose version 27f1555e47Sopenharmony_ci let output = try!(Command::new(rustc) 28f1555e47Sopenharmony_ci .args(&["--version", "--verbose"]) 29f1555e47Sopenharmony_ci .output() 30f1555e47Sopenharmony_ci .map_err(error::from_io)); 31f1555e47Sopenharmony_ci if !output.status.success() { 32f1555e47Sopenharmony_ci return Err(error::from_str("could not execute rustc")); 33f1555e47Sopenharmony_ci } 34f1555e47Sopenharmony_ci let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8)); 35f1555e47Sopenharmony_ci 36f1555e47Sopenharmony_ci // Find the release line in the verbose version output. 37f1555e47Sopenharmony_ci let release = match output.lines().find(|line| line.starts_with("release: ")) { 38f1555e47Sopenharmony_ci Some(line) => &line["release: ".len()..], 39f1555e47Sopenharmony_ci None => return Err(error::from_str("could not find rustc release")), 40f1555e47Sopenharmony_ci }; 41f1555e47Sopenharmony_ci 42f1555e47Sopenharmony_ci // Strip off any extra channel info, e.g. "-beta.N", "-nightly" 43f1555e47Sopenharmony_ci let version = match release.find('-') { 44f1555e47Sopenharmony_ci Some(i) => &release[..i], 45f1555e47Sopenharmony_ci None => release, 46f1555e47Sopenharmony_ci }; 47f1555e47Sopenharmony_ci 48f1555e47Sopenharmony_ci // Split the version into semver components. 49f1555e47Sopenharmony_ci let mut iter = version.splitn(3, '.'); 50f1555e47Sopenharmony_ci let major = try!(iter.next().ok_or(error::from_str("missing major version"))); 51f1555e47Sopenharmony_ci let minor = try!(iter.next().ok_or(error::from_str("missing minor version"))); 52f1555e47Sopenharmony_ci let patch = try!(iter.next().ok_or(error::from_str("missing patch version"))); 53f1555e47Sopenharmony_ci 54f1555e47Sopenharmony_ci Ok(Version::new( 55f1555e47Sopenharmony_ci try!(major.parse().map_err(error::from_num)), 56f1555e47Sopenharmony_ci try!(minor.parse().map_err(error::from_num)), 57f1555e47Sopenharmony_ci try!(patch.parse().map_err(error::from_num)), 58f1555e47Sopenharmony_ci )) 59f1555e47Sopenharmony_ci } 60f1555e47Sopenharmony_ci} 61