@@ -4,6 +4,11 @@ use std::{
4
4
fs:: { self , read_dir, OpenOptions } ,
5
5
io:: { self , Read , Write } ,
6
6
path:: { Path , PathBuf } ,
7
+ sync:: {
8
+ atomic:: { self , AtomicBool } ,
9
+ Mutex ,
10
+ } ,
11
+ thread,
7
12
} ;
8
13
9
14
use crate :: {
@@ -167,36 +172,52 @@ fn check_exercises(info_file: &InfoFile) -> Result<()> {
167
172
}
168
173
169
174
fn check_solutions ( require_solutions : bool , info_file : & InfoFile ) -> Result < ( ) > {
170
- let mut paths = hashbrown:: HashSet :: with_capacity ( info_file. exercises . len ( ) ) ;
171
175
let target_dir = parse_target_dir ( ) ?;
172
- let mut output = Vec :: with_capacity ( OUTPUT_CAPACITY ) ;
173
-
174
- for exercise_info in & info_file. exercises {
175
- let path = exercise_info. sol_path ( ) ;
176
- if !Path :: new ( & path) . exists ( ) {
177
- if require_solutions {
178
- bail ! ( "Exercise {} is missing a solution" , exercise_info. name) ;
179
- }
180
-
181
- // No solution to check.
182
- continue ;
176
+ let paths = Mutex :: new ( hashbrown:: HashSet :: with_capacity ( info_file. exercises . len ( ) ) ) ;
177
+ let error_occured = AtomicBool :: new ( false ) ;
178
+
179
+ println ! ( "Running all solutions. This may take a while...\n " ) ;
180
+ thread:: scope ( |s| {
181
+ for exercise_info in & info_file. exercises {
182
+ s. spawn ( || {
183
+ let error = |e| {
184
+ let mut stderr = io:: stderr ( ) . lock ( ) ;
185
+ stderr. write_all ( e) . unwrap ( ) ;
186
+ stderr
187
+ . write_all ( b"\n Failed to run the solution of the exercise " )
188
+ . unwrap ( ) ;
189
+ stderr. write_all ( exercise_info. name . as_bytes ( ) ) . unwrap ( ) ;
190
+ stderr. write_all ( SEPARATOR ) . unwrap ( ) ;
191
+ error_occured. store ( true , atomic:: Ordering :: Relaxed ) ;
192
+ } ;
193
+
194
+ let path = exercise_info. sol_path ( ) ;
195
+ if !Path :: new ( & path) . exists ( ) {
196
+ if require_solutions {
197
+ error ( b"Solution missing" ) ;
198
+ }
199
+
200
+ // No solution to check.
201
+ return ;
202
+ }
203
+
204
+ let mut output = Vec :: with_capacity ( OUTPUT_CAPACITY ) ;
205
+ match exercise_info. run_solution ( & mut output, & target_dir) {
206
+ Ok ( true ) => {
207
+ paths. lock ( ) . unwrap ( ) . insert ( PathBuf :: from ( path) ) ;
208
+ }
209
+ Ok ( false ) => error ( & output) ,
210
+ Err ( e) => error ( e. to_string ( ) . as_bytes ( ) ) ,
211
+ }
212
+ } ) ;
183
213
}
214
+ } ) ;
184
215
185
- println ! ( "Running the solution of {}" , exercise_info. name) ;
186
- let success = exercise_info. run_solution ( & mut output, & target_dir) ?;
187
- if !success {
188
- io:: stderr ( ) . write_all ( & output) ?;
189
-
190
- bail ! (
191
- "Failed to run the solution of the exercise {}" ,
192
- exercise_info. name,
193
- ) ;
194
- }
195
-
196
- paths. insert ( PathBuf :: from ( path) ) ;
216
+ if error_occured. load ( atomic:: Ordering :: Relaxed ) {
217
+ bail ! ( "At least one solution failed. See the output above." ) ;
197
218
}
198
219
199
- check_unexpected_files ( "solutions" , & paths) ?;
220
+ check_unexpected_files ( "solutions" , & paths. into_inner ( ) . unwrap ( ) ) ?;
200
221
201
222
Ok ( ( ) )
202
223
}
@@ -224,3 +245,6 @@ pub fn check(require_solutions: bool) -> Result<()> {
224
245
225
246
Ok ( ( ) )
226
247
}
248
+
249
+ const SEPARATOR : & [ u8 ] =
250
+ b"\n ========================================================================================\n " ;
0 commit comments