60 lines
2 KiB
Rust
60 lines
2 KiB
Rust
use std::path::Path;
|
|
use std::process::Command;
|
|
use std::str;
|
|
|
|
use super::{error, Error};
|
|
|
|
/// A version structure for making relative comparisons.
|
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Version {
|
|
major: usize,
|
|
minor: usize,
|
|
patch: usize,
|
|
}
|
|
|
|
impl Version {
|
|
/// Creates a `Version` instance for a specific `major.minor.patch` version.
|
|
pub fn new(major: usize, minor: usize, patch: usize) -> Self {
|
|
Version {
|
|
major: major,
|
|
minor: minor,
|
|
patch: patch,
|
|
}
|
|
}
|
|
|
|
pub fn from_rustc(rustc: &Path) -> Result<Self, Error> {
|
|
// Get rustc's verbose version
|
|
let output = try!(Command::new(rustc)
|
|
.args(&["--version", "--verbose"])
|
|
.output()
|
|
.map_err(error::from_io));
|
|
if !output.status.success() {
|
|
return Err(error::from_str("could not execute rustc"));
|
|
}
|
|
let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8));
|
|
|
|
// Find the release line in the verbose version output.
|
|
let release = match output.lines().find(|line| line.starts_with("release: ")) {
|
|
Some(line) => &line["release: ".len()..],
|
|
None => return Err(error::from_str("could not find rustc release")),
|
|
};
|
|
|
|
// Strip off any extra channel info, e.g. "-beta.N", "-nightly"
|
|
let version = match release.find('-') {
|
|
Some(i) => &release[..i],
|
|
None => release,
|
|
};
|
|
|
|
// Split the version into semver components.
|
|
let mut iter = version.splitn(3, '.');
|
|
let major = try!(iter.next().ok_or(error::from_str("missing major version")));
|
|
let minor = try!(iter.next().ok_or(error::from_str("missing minor version")));
|
|
let patch = try!(iter.next().ok_or(error::from_str("missing patch version")));
|
|
|
|
Ok(Version::new(
|
|
try!(major.parse().map_err(error::from_num)),
|
|
try!(minor.parse().map_err(error::from_num)),
|
|
try!(patch.parse().map_err(error::from_num)),
|
|
))
|
|
}
|
|
}
|