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