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