20
20
//! // This could be a cargo build script
21
21
//!
22
22
//! extern crate rustc_version;
23
- //! use rustc_version::{version, version_matches, version_meta, Channel};
23
+ //! use rustc_version::{version, version_meta, Channel, Version };
24
24
//!
25
25
//! fn main() {
26
26
//! // Assert we haven't travelled back in time
27
- //! assert!(version().major >= 1);
27
+ //! assert!(version().unwrap(). major >= 1);
28
28
//!
29
29
//! // Set cfg flags depending on release channel
30
- //! match version_meta().channel {
30
+ //! match version_meta().unwrap(). channel {
31
31
//! Channel::Stable => {
32
32
//! println!("cargo:rustc-cfg=RUSTC_IS_STABLE");
33
33
//! }
42
42
//! }
43
43
//! }
44
44
//!
45
- //! // Directly check a semver version requirment
46
- //! if version_matches(" >= 1.4.0") {
45
+ //! // Check for a minimum version
46
+ //! if version().unwrap() >= Version::parse(" 1.4.0").unwrap( ) {
47
47
//! println!("cargo:rustc-cfg=compiler_has_important_bugfix");
48
48
//! }
49
49
//! }
50
50
//! ```
51
51
52
52
extern crate semver;
53
- use semver:: { Version , VersionReq , Identifier } ;
53
+ use semver:: Identifier ;
54
54
use std:: process:: Command ;
55
- use std:: env;
55
+ use std:: { env, str } ;
56
56
use std:: ffi:: OsString ;
57
57
58
+ // Convenience re-export to allow version comparison without needing to add
59
+ // semver crate.
60
+ pub use semver:: Version ;
61
+
62
+ mod errors;
63
+ pub use errors:: { Error , Result } ;
64
+
58
65
/// Release channel of the compiler.
59
66
#[ derive( Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Hash , Debug ) ]
60
67
pub enum Channel {
@@ -69,7 +76,7 @@ pub enum Channel {
69
76
}
70
77
71
78
/// Rustc version plus metada like git short hash and build date.
72
- #[ derive( Clone , Eq , PartialEq , Ord , PartialOrd , Hash ) ]
79
+ #[ derive( Clone , Debug , Eq , PartialEq , Ord , PartialOrd , Hash ) ]
73
80
pub struct VersionMeta {
74
81
/// Version of the compiler
75
82
pub semver : Version ,
@@ -93,51 +100,60 @@ pub struct VersionMeta {
93
100
pub short_version_string : String ,
94
101
}
95
102
103
+ impl VersionMeta {
104
+ /// Returns the version metadata for `cmd`, which should be a `rustc` command.
105
+ pub fn for_command ( cmd : Command ) -> Result < VersionMeta > {
106
+ let mut cmd = cmd;
107
+
108
+ let out = match cmd. arg ( "-vV" ) . output ( ) {
109
+ Err ( e) => return Err ( Error :: CouldNotExecuteCommand ( e) ) ,
110
+ Ok ( out) => out,
111
+ } ;
112
+ let out = try!( str:: from_utf8 ( & out. stdout ) ) ;
113
+
114
+ version_meta_for ( out)
115
+ }
116
+ }
117
+
96
118
/// Returns the `rustc` SemVer version.
97
- pub fn version ( ) -> Version {
98
- version_meta ( ) . semver
119
+ pub fn version ( ) -> Result < Version > {
120
+ Ok ( try! ( version_meta ( ) ) . semver )
99
121
}
100
122
101
123
/// Returns the `rustc` SemVer version and additional metadata
102
124
/// like the git short hash and build date.
103
- pub fn version_meta ( ) -> VersionMeta {
125
+ pub fn version_meta ( ) -> Result < VersionMeta > {
104
126
let cmd = env:: var_os ( "RUSTC" ) . unwrap_or_else ( || OsString :: from ( "rustc" ) ) ;
105
127
106
- let out = Command :: new ( & cmd)
107
- . arg ( "-vV" )
108
- . output ( )
109
- . unwrap_or_else ( |e| { panic ! ( "failed to execute `RUSTC -vV`: {}" , e) } ) ;
128
+ VersionMeta :: for_command ( Command :: new ( cmd) )
110
129
111
- let out = String :: from_utf8 ( out. stdout )
112
- . ok ( )
113
- . expect ( "non utf8 output from RUSTC -vV" ) ;
114
-
115
- version_meta_for ( & out)
116
130
}
117
131
118
132
/// Parses a "rustc -vV" output string and returns
119
133
/// the SemVer version and additional metadata
120
134
/// like the git short hash and build date.
121
- pub fn version_meta_for ( verbose_version_string : & str ) -> VersionMeta {
135
+ pub fn version_meta_for ( verbose_version_string : & str ) -> Result < VersionMeta > {
122
136
let out: Vec < _ > = verbose_version_string. lines ( ) . collect ( ) ;
123
137
124
- const ERR_MSG : & ' static str = "unexpected -vV format" ;
125
-
126
- assert ! ( out . len ( ) >= 6 && out . len ( ) <= 8 , ERR_MSG ) ;
138
+ if ( out . len ( ) >= 6 && out . len ( ) <= 8 ) {
139
+ return Err ( Error :: UnexpectedVersionFormat ) ;
140
+ }
127
141
128
142
let short_version_string = out[ 0 ] ;
129
143
130
- fn expect_prefix < ' a > ( line : & ' a str , prefix : & str ) -> & ' a str {
131
- assert ! ( line. starts_with( prefix) , ERR_MSG ) ;
132
- & line[ prefix. len ( ) ..]
144
+ fn expect_prefix < ' a > ( line : & ' a str , prefix : & str ) -> Result < & ' a str > {
145
+ match line. starts_with ( prefix) {
146
+ true => Ok ( & line[ prefix. len ( ) ..] ) ,
147
+ false => Err ( Error :: UnexpectedVersionFormat ) ,
148
+ }
133
149
}
134
150
135
- let commit_hash = match expect_prefix ( out[ 2 ] , "commit-hash: " ) {
151
+ let commit_hash = match try! ( expect_prefix ( out[ 2 ] , "commit-hash: " ) ) {
136
152
"unknown" => None ,
137
153
hash => Some ( hash. to_owned ( ) ) ,
138
154
} ;
139
155
140
- let commit_date = match expect_prefix ( out[ 3 ] , "commit-date: " ) {
156
+ let commit_date = match try! ( expect_prefix ( out[ 3 ] , "commit-date: " ) ) {
141
157
"unknown" => None ,
142
158
hash => Some ( hash. to_owned ( ) ) ,
143
159
} ;
@@ -146,19 +162,18 @@ pub fn version_meta_for(verbose_version_string: &str) -> VersionMeta {
146
162
let mut idx = 4 ;
147
163
let mut build_date = None ;
148
164
if out[ idx] . starts_with ( "build-date" ) {
149
- build_date = match expect_prefix ( out[ idx] , "build-date: " ) {
165
+ build_date = match try! ( expect_prefix ( out[ idx] , "build-date: " ) ) {
150
166
"unknown" => None ,
151
167
s => Some ( s. to_owned ( ) ) ,
152
168
} ;
153
169
idx = idx + 1 ;
154
170
}
155
171
172
+ let host = try!( expect_prefix ( out[ idx] , "host: " ) ) ;
173
+ idx = idx + 1 ;
174
+ let release = try!( expect_prefix ( out[ idx] , "release: " ) ) ;
156
175
157
- let host = expect_prefix ( out[ idx] , "host: " ) ;
158
- idx = idx +1 ;
159
- let release = expect_prefix ( out[ idx] , "release: " ) ;
160
-
161
- let semver = Version :: parse ( release) . unwrap ( ) ;
176
+ let semver: Version = try!( release. parse ( ) ) ;
162
177
163
178
let channel = if semver. pre . is_empty ( ) {
164
179
Channel :: Stable
@@ -170,50 +185,48 @@ pub fn version_meta_for(verbose_version_string: &str) -> VersionMeta {
170
185
if s == "beta" => Channel :: Beta ,
171
186
Identifier :: AlphaNumeric ( ref s)
172
187
if s == "nightly" => Channel :: Nightly ,
173
- ref x => panic ! ( "Unknown pre-release tag {}" , x ) ,
188
+ ref x => return Err ( Error :: UnknownPreReleaseTag ( x . clone ( ) ) ) ,
174
189
}
175
190
} ;
176
191
177
- VersionMeta {
192
+ Ok ( VersionMeta {
178
193
semver : semver,
179
194
commit_hash : commit_hash,
180
195
commit_date : commit_date,
181
196
build_date : build_date,
182
197
channel : channel,
183
198
host : host. into ( ) ,
184
199
short_version_string : short_version_string. into ( ) ,
185
- }
186
- }
187
-
188
- /// Check wether the `rustc` version matches the given SemVer
189
- /// version requirement.
190
- pub fn version_matches ( req : & str ) -> bool {
191
- VersionReq :: parse ( req) . unwrap ( ) . matches ( & version ( ) )
200
+ } )
192
201
}
193
202
194
203
#[ test]
195
204
fn smoketest ( ) {
196
- let v = version ( ) ;
205
+ let v = version ( ) . unwrap ( ) ;
197
206
assert ! ( v. major >= 1 ) ;
198
207
199
- let v = version_meta ( ) ;
208
+ let v = version_meta ( ) . unwrap ( ) ;
200
209
assert ! ( v. semver. major >= 1 ) ;
201
210
202
- assert ! ( version_matches ( " >= 1.0.0") ) ;
211
+ assert ! ( version ( ) . unwrap ( ) >= Version :: parse ( " 1.0.0") . unwrap ( ) ) ;
203
212
}
204
213
205
214
#[ test]
206
- #[ should_panic( expected = "unexpected" ) ]
207
- // Characterization test for behavior on an unexpected key.
208
215
fn parse_unexpected ( ) {
209
- version_meta_for (
216
+ let res = version_meta_for (
210
217
"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
211
218
binary: rustc
212
219
commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e
213
220
commit-date: 2015-05-13
214
221
rust-birthday: 2015-05-14
215
222
host: x86_64-unknown-linux-gnu
216
223
release: 1.0.0" ) ;
224
+
225
+ assert ! ( match res {
226
+ Err ( Error :: UnexpectedVersionFormat ) => true ,
227
+ _ => false ,
228
+ } ) ;
229
+
217
230
}
218
231
219
232
#[ test]
@@ -225,7 +238,7 @@ commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e
225
238
commit-date: 2015-05-13
226
239
build-date: 2015-05-14
227
240
host: x86_64-unknown-linux-gnu
228
- release: 1.0.0" ) ;
241
+ release: 1.0.0" ) . unwrap ( ) ;
229
242
230
243
assert_eq ! ( version. semver, Version :: parse( "1.0.0" ) . unwrap( ) ) ;
231
244
assert_eq ! ( version. commit_hash, Some ( "a59de37e99060162a2674e3ff45409ac73595c0e" . into( ) ) ) ;
@@ -245,7 +258,7 @@ binary: rustc
245
258
commit-hash: unknown
246
259
commit-date: unknown
247
260
host: x86_64-unknown-linux-gnu
248
- release: 1.3.0" ) ;
261
+ release: 1.3.0" ) . unwrap ( ) ;
249
262
250
263
assert_eq ! ( version. semver, Version :: parse( "1.3.0" ) . unwrap( ) ) ;
251
264
assert_eq ! ( version. commit_hash, None ) ;
@@ -263,7 +276,7 @@ binary: rustc
263
276
commit-hash: 65d5c083377645a115c4ac23a620d3581b9562b6
264
277
commit-date: 2015-09-29
265
278
host: x86_64-unknown-linux-gnu
266
- release: 1.5.0-nightly" ) ;
279
+ release: 1.5.0-nightly" ) . unwrap ( ) ;
267
280
268
281
assert_eq ! ( version. semver, Version :: parse( "1.5.0-nightly" ) . unwrap( ) ) ;
269
282
assert_eq ! ( version. commit_hash, Some ( "65d5c083377645a115c4ac23a620d3581b9562b6" . into( ) ) ) ;
@@ -281,7 +294,7 @@ binary: rustc
281
294
commit-hash: 9a92aaf19a64603b02b4130fe52958cc12488900
282
295
commit-date: 2015-09-15
283
296
host: x86_64-unknown-linux-gnu
284
- release: 1.3.0" ) ;
297
+ release: 1.3.0" ) . unwrap ( ) ;
285
298
286
299
assert_eq ! ( version. semver, Version :: parse( "1.3.0" ) . unwrap( ) ) ;
287
300
assert_eq ! ( version. commit_hash, Some ( "9a92aaf19a64603b02b4130fe52958cc12488900" . into( ) ) ) ;
0 commit comments