@@ -32,18 +32,23 @@ struct Opt {
32
32
/// (which must be already built)
33
33
#[ structopt( short = "p" , long = "svd2rust-path" , parse( from_os_str) ) ]
34
34
bin_path : Option < PathBuf > ,
35
+
36
+ // TODO: Consider using the same strategy cargo uses for passing args to rustc via `--`
37
+ /// Run svd2rust with `--nightly`
38
+ #[ structopt( long = "nightly" ) ]
39
+ nightly : bool ,
35
40
36
41
/// Filter by chip name, case sensitive, may be combined with other filters
37
- #[ structopt( short = "c" , long = "chip" ) ]
38
- chip : Option < String > ,
42
+ #[ structopt( short = "c" , long = "chip" , raw ( validator = "validate_chips" ) ) ]
43
+ chip : Vec < String > ,
39
44
40
45
/// Filter by manufacturer, case sensitive, may be combined with other filters
41
- #[ structopt( short = "m" , long = "manufacturer" ) ]
46
+ #[ structopt( short = "m" , long = "manufacturer" , raw ( validator = "validate_manufacturer" ) ) ]
42
47
mfgr : Option < String > ,
43
48
44
49
/// Filter by architecture, case sensitive, may be combined with other filters
45
50
/// Options are: "CortexM", "RiscV", and "Msp430"
46
- #[ structopt( short = "a" , long = "architecture" ) ]
51
+ #[ structopt( short = "a" , long = "architecture" , raw ( validator = "validate_architecture" ) ) ]
47
52
arch : Option < String > ,
48
53
49
54
/// Include tests expected to fail (will cause a non-zero return code)
@@ -54,19 +59,50 @@ struct Opt {
54
59
#[ structopt( short = "f" , long = "format" ) ]
55
60
format : bool ,
56
61
62
+ /// Print all available test using the specified filters
63
+ #[ structopt( long = "list" ) ]
64
+ list : bool ,
65
+
57
66
/// Path to an `rustfmt` binary, relative or absolute.
58
67
/// Defaults to `$(rustup which rustfmt)`
59
68
#[ structopt( long = "rustfmt_bin_path" , parse( from_os_str) ) ]
60
69
rustfmt_bin_path : Option < PathBuf > ,
61
70
71
+ /// Specify what rustup toolchain to use when compiling chip(s)
72
+ #[ structopt( long = "toolchain" , env = "RUSTUP_TOOLCHAIN" ) ]
73
+ rustup_toolchain : Option < String > ,
74
+
62
75
/// Use verbose output
63
76
#[ structopt( long = "verbose" , short = "v" , parse( from_occurrences) ) ]
64
77
verbose : u8 ,
65
78
// TODO: Specify smaller subset of tests? Maybe with tags?
66
- // TODO: Early fail
67
79
// TODO: Compile svd2rust?
68
80
}
69
81
82
+ fn validate_chips ( s : String ) -> Result < ( ) , String > {
83
+ if tests:: TESTS . iter ( ) . any ( |t| t. chip == s) {
84
+ Ok ( ( ) )
85
+ } else {
86
+ Err ( format ! ( "Chip `{}` is not a valid value" , s) )
87
+ }
88
+ }
89
+
90
+ fn validate_architecture ( s : String ) -> Result < ( ) , String > {
91
+ if tests:: TESTS . iter ( ) . any ( |t| format ! ( "{:?}" , t. arch) == s) {
92
+ Ok ( ( ) )
93
+ } else {
94
+ Err ( format ! ( "Architecture `{}` is not a valid value" , s) )
95
+ }
96
+ }
97
+
98
+ fn validate_manufacturer ( s : String ) -> Result < ( ) , String > {
99
+ if tests:: TESTS . iter ( ) . any ( |t| format ! ( "{:?}" , t. mfgr) == s) {
100
+ Ok ( ( ) )
101
+ } else {
102
+ Err ( format ! ( "Manufacturer `{}` is not a valid value" , s) )
103
+ }
104
+ }
105
+
70
106
/// Validate any assumptions made by this program
71
107
fn validate_tests ( tests : & [ & tests:: TestCase ] ) {
72
108
use std:: collections:: HashSet ;
@@ -88,6 +124,18 @@ fn validate_tests(tests: &[&tests::TestCase]) {
88
124
}
89
125
}
90
126
127
+ fn read_file ( path : & PathBuf , buf : & mut String ) {
128
+ if buf. is_empty ( ) {
129
+ buf. push_str ( & format ! ( "{}\n " , path. display( ) ) ) ;
130
+ } else {
131
+ buf. push_str ( & format ! ( "\n {}\n " , path. display( ) ) ) ;
132
+ }
133
+ File :: open ( path)
134
+ . expect ( "Couldn't open file" )
135
+ . read_to_string ( buf)
136
+ . expect ( "Couldn't read file to string" ) ;
137
+ }
138
+
91
139
fn main ( ) {
92
140
let opt = Opt :: from_args ( ) ;
93
141
@@ -138,6 +186,12 @@ fn main() {
138
186
default_rustfmt. as_ref ( )
139
187
}
140
188
} ;
189
+
190
+ // Set RUSTUP_TOOLCHAIN if needed
191
+ if let Some ( toolchain) = & opt. rustup_toolchain {
192
+ :: std:: env:: set_var ( "RUSTUP_TOOLCHAIN" , toolchain) ;
193
+ }
194
+
141
195
// collect enabled tests
142
196
let tests = tests:: TESTS
143
197
. iter ( )
@@ -161,8 +215,8 @@ fn main() {
161
215
} )
162
216
// Specify chip - note: may match multiple
163
217
. filter ( |t| {
164
- if let Some ( ref chip ) = opt. chip {
165
- chip == t. chip
218
+ if ! opt. chip . is_empty ( ) {
219
+ opt . chip . iter ( ) . any ( |c| c == t. chip )
166
220
} else {
167
221
true
168
222
}
@@ -171,36 +225,55 @@ fn main() {
171
225
. filter ( |t| opt. bad_tests || t. should_pass )
172
226
. collect :: < Vec < _ > > ( ) ;
173
227
228
+ if opt. list {
229
+ // FIXME: Prettier output
230
+ eprintln ! ( "{:?}" , tests. iter( ) . map( |t| t. name( ) ) . collect:: <Vec <_>>( ) ) ;
231
+ exit ( 0 ) ;
232
+ }
233
+ if tests. is_empty ( ) {
234
+ eprintln ! ( "No tests run, you might want to use `--bad-tests` and/or `--long-test`" ) ;
235
+ }
236
+
174
237
let any_fails = AtomicBool :: new ( false ) ;
175
238
176
239
// TODO: It would be more efficient to reuse directories, so we don't
177
240
// have to rebuild all the deps crates
178
241
tests. par_iter ( ) . for_each ( |t| {
179
242
let start = Instant :: now ( ) ;
180
243
181
- match svd_test:: test ( t, & bin_path, rustfmt_bin_path) {
182
- Ok ( ( ) ) => {
183
- // TODO: If verbosity is > 1, print every logged stderr
184
- eprintln ! (
185
- "Passed: {} - {} seconds" ,
186
- t. name( ) ,
187
- start. elapsed( ) . as_secs( )
188
- ) ;
244
+ match svd_test:: test ( t, & bin_path, rustfmt_bin_path, opt. nightly , opt. verbose ) {
245
+ Ok ( s) => {
246
+ if let Some ( stderrs) = s {
247
+ let mut buf = String :: new ( ) ;
248
+ for stderr in stderrs {
249
+ read_file ( & stderr, & mut buf) ;
250
+ }
251
+ eprintln ! (
252
+ "Passed: {} - {} seconds\n {}" ,
253
+ t. name( ) ,
254
+ start. elapsed( ) . as_secs( ) ,
255
+ buf
256
+ ) ;
257
+ } else {
258
+ eprintln ! (
259
+ "Passed: {} - {} seconds" ,
260
+ t. name( ) ,
261
+ start. elapsed( ) . as_secs( )
262
+ ) ;
263
+ }
189
264
}
190
265
Err ( e) => {
191
266
any_fails. store ( true , Ordering :: Release ) ;
192
267
let additional_info = if opt. verbose > 0 {
193
268
match e. kind ( ) {
194
- & errors:: ErrorKind :: ProcessFailed ( ref command, _, Some ( ref stderr) )
195
- if command == "cargo check" =>
196
- {
197
- let mut buf = String :: new ( ) ;
198
- // Unwrap is safe
199
- File :: open ( stderr)
200
- . expect ( "Couldn't open file" )
201
- . read_to_string ( & mut buf)
202
- . expect ( "Couldn't read file to string" ) ;
203
- buf. insert_str ( 0 , & format ! ( "\n ---{:?}---\n " , stderr. as_os_str( ) ) ) ;
269
+ & errors:: ErrorKind :: ProcessFailed ( _, _, Some ( ref stderr) , ref previous_processes_stderr) => {
270
+ let mut buf = String :: new ( ) ;
271
+ if opt. verbose > 1 {
272
+ for stderr in previous_processes_stderr {
273
+ read_file ( & stderr, & mut buf) ;
274
+ }
275
+ }
276
+ read_file ( & stderr, & mut buf) ;
204
277
buf
205
278
}
206
279
_ => "" . into ( ) ,
0 commit comments