1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
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)),
))
}
}
|