@@ -165,65 +165,67 @@ fn check_unexpected_files(dir: &str, allowed_rust_files: &HashSet<PathBuf>) -> R
165
165
Ok ( ( ) )
166
166
}
167
167
168
- fn check_exercises_unsolved ( info_file : & InfoFile , cmd_runner : & CmdRunner ) -> Result < ( ) > {
168
+ fn check_exercises_unsolved (
169
+ info_file : & ' static InfoFile ,
170
+ cmd_runner : & ' static CmdRunner ,
171
+ ) -> Result < ( ) > {
169
172
let mut stdout = io:: stdout ( ) . lock ( ) ;
170
173
stdout. write_all ( b"Running all exercises to check that they aren't already solved...\n " ) ?;
171
174
172
- thread:: scope ( |s| {
173
- let handles = info_file
174
- . exercises
175
- . iter ( )
176
- . filter_map ( |exercise_info| {
177
- if exercise_info. skip_check_unsolved {
178
- return None ;
179
- }
180
-
181
- Some ( (
182
- exercise_info. name . as_str ( ) ,
183
- s. spawn ( || exercise_info. run_exercise ( None , cmd_runner) ) ,
184
- ) )
185
- } )
186
- . collect :: < Vec < _ > > ( ) ;
187
-
188
- let n_handles = handles. len ( ) ;
189
- write ! ( stdout, "Progress: 0/{n_handles}" ) ?;
190
- stdout. flush ( ) ?;
191
- let mut handle_num = 1 ;
192
-
193
- for ( exercise_name, handle) in handles {
194
- let Ok ( result) = handle. join ( ) else {
195
- bail ! ( "Panic while trying to run the exericse {exercise_name}" ) ;
196
- } ;
197
-
198
- match result {
199
- Ok ( true ) => bail ! (
200
- "The exercise {exercise_name} is already solved.\n {SKIP_CHECK_UNSOLVED_HINT}" ,
201
- ) ,
202
- Ok ( false ) => ( ) ,
203
- Err ( e) => return Err ( e) ,
175
+ let handles = info_file
176
+ . exercises
177
+ . iter ( )
178
+ . filter_map ( |exercise_info| {
179
+ if exercise_info. skip_check_unsolved {
180
+ return None ;
204
181
}
205
182
206
- write ! ( stdout, "\r Progress: {handle_num}/{n_handles}" ) ?;
207
- stdout. flush ( ) ?;
208
- handle_num += 1 ;
183
+ Some ( (
184
+ exercise_info. name . as_str ( ) ,
185
+ thread:: spawn ( || exercise_info. run_exercise ( None , cmd_runner) ) ,
186
+ ) )
187
+ } )
188
+ . collect :: < Vec < _ > > ( ) ;
189
+
190
+ let n_handles = handles. len ( ) ;
191
+ write ! ( stdout, "Progress: 0/{n_handles}" ) ?;
192
+ stdout. flush ( ) ?;
193
+ let mut handle_num = 1 ;
194
+
195
+ for ( exercise_name, handle) in handles {
196
+ let Ok ( result) = handle. join ( ) else {
197
+ bail ! ( "Panic while trying to run the exericse {exercise_name}" ) ;
198
+ } ;
199
+
200
+ match result {
201
+ Ok ( true ) => {
202
+ bail ! ( "The exercise {exercise_name} is already solved.\n {SKIP_CHECK_UNSOLVED_HINT}" , )
203
+ }
204
+ Ok ( false ) => ( ) ,
205
+ Err ( e) => return Err ( e) ,
209
206
}
210
- stdout. write_all ( b"\n " ) ?;
211
207
212
- Ok ( ( ) )
213
- } )
208
+ write ! ( stdout, "\r Progress: {handle_num}/{n_handles}" ) ?;
209
+ stdout. flush ( ) ?;
210
+ handle_num += 1 ;
211
+ }
212
+ stdout. write_all ( b"\n " ) ?;
213
+
214
+ Ok ( ( ) )
214
215
}
215
216
216
- fn check_exercises ( info_file : & InfoFile , cmd_runner : & CmdRunner ) -> Result < ( ) > {
217
+ fn check_exercises ( info_file : & ' static InfoFile , cmd_runner : & ' static CmdRunner ) -> Result < ( ) > {
217
218
match info_file. format_version . cmp ( & CURRENT_FORMAT_VERSION ) {
218
219
Ordering :: Less => bail ! ( "`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\n Please migrate to the latest format version" ) ,
219
220
Ordering :: Greater => bail ! ( "`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\n Try updating the Rustlings program" ) ,
220
221
Ordering :: Equal => ( ) ,
221
222
}
222
223
224
+ let handle = thread:: spawn ( move || check_exercises_unsolved ( info_file, cmd_runner) ) ;
225
+
223
226
let info_file_paths = check_info_file_exercises ( info_file) ?;
224
- let handle = thread :: spawn ( move || check_unexpected_files ( "exercises" , & info_file_paths) ) ;
227
+ check_unexpected_files ( "exercises" , & info_file_paths) ? ;
225
228
226
- check_exercises_unsolved ( info_file, cmd_runner) ?;
227
229
handle. join ( ) . unwrap ( )
228
230
}
229
231
@@ -236,98 +238,96 @@ enum SolutionCheck {
236
238
237
239
fn check_solutions (
238
240
require_solutions : bool ,
239
- info_file : & InfoFile ,
240
- cmd_runner : & CmdRunner ,
241
+ info_file : & ' static InfoFile ,
242
+ cmd_runner : & ' static CmdRunner ,
241
243
) -> Result < ( ) > {
242
244
let mut stdout = io:: stdout ( ) . lock ( ) ;
243
245
stdout. write_all ( b"Running all solutions...\n " ) ?;
244
246
245
- thread:: scope ( |s| {
246
- let handles = info_file
247
- . exercises
248
- . iter ( )
249
- . map ( |exercise_info| {
250
- s. spawn ( || {
251
- let sol_path = exercise_info. sol_path ( ) ;
252
- if !Path :: new ( & sol_path) . exists ( ) {
253
- if require_solutions {
254
- return SolutionCheck :: Err ( anyhow ! (
255
- "The solution of the exercise {} is missing" ,
256
- exercise_info. name,
257
- ) ) ;
258
- }
259
-
260
- return SolutionCheck :: MissingOptional ;
247
+ let handles = info_file
248
+ . exercises
249
+ . iter ( )
250
+ . map ( |exercise_info| {
251
+ thread:: spawn ( move || {
252
+ let sol_path = exercise_info. sol_path ( ) ;
253
+ if !Path :: new ( & sol_path) . exists ( ) {
254
+ if require_solutions {
255
+ return SolutionCheck :: Err ( anyhow ! (
256
+ "The solution of the exercise {} is missing" ,
257
+ exercise_info. name,
258
+ ) ) ;
261
259
}
262
260
263
- let mut output = Vec :: with_capacity ( OUTPUT_CAPACITY ) ;
264
- match exercise_info. run_solution ( Some ( & mut output) , cmd_runner) {
265
- Ok ( true ) => SolutionCheck :: Success { sol_path } ,
266
- Ok ( false ) => SolutionCheck :: RunFailure { output } ,
267
- Err ( e) => SolutionCheck :: Err ( e) ,
268
- }
269
- } )
270
- } )
271
- . collect :: < Vec < _ > > ( ) ;
272
-
273
- let mut sol_paths = hash_set_with_capacity ( info_file. exercises . len ( ) ) ;
274
- let mut fmt_cmd = Command :: new ( "rustfmt" ) ;
275
- fmt_cmd
276
- . arg ( "--check" )
277
- . arg ( "--edition" )
278
- . arg ( "2021" )
279
- . arg ( "--color" )
280
- . arg ( "always" )
281
- . stdin ( Stdio :: null ( ) ) ;
282
-
283
- let n_handles = handles. len ( ) ;
284
- write ! ( stdout, "Progress: 0/{n_handles}" ) ?;
285
- stdout. flush ( ) ?;
286
- let mut handle_num = 1 ;
261
+ return SolutionCheck :: MissingOptional ;
262
+ }
287
263
288
- for ( exercise_info, handle) in info_file. exercises . iter ( ) . zip ( handles) {
289
- let Ok ( check_result) = handle. join ( ) else {
264
+ let mut output = Vec :: with_capacity ( OUTPUT_CAPACITY ) ;
265
+ match exercise_info. run_solution ( Some ( & mut output) , cmd_runner) {
266
+ Ok ( true ) => SolutionCheck :: Success { sol_path } ,
267
+ Ok ( false ) => SolutionCheck :: RunFailure { output } ,
268
+ Err ( e) => SolutionCheck :: Err ( e) ,
269
+ }
270
+ } )
271
+ } )
272
+ . collect :: < Vec < _ > > ( ) ;
273
+
274
+ let mut sol_paths = hash_set_with_capacity ( info_file. exercises . len ( ) ) ;
275
+ let mut fmt_cmd = Command :: new ( "rustfmt" ) ;
276
+ fmt_cmd
277
+ . arg ( "--check" )
278
+ . arg ( "--edition" )
279
+ . arg ( "2021" )
280
+ . arg ( "--color" )
281
+ . arg ( "always" )
282
+ . stdin ( Stdio :: null ( ) ) ;
283
+
284
+ let n_handles = handles. len ( ) ;
285
+ write ! ( stdout, "Progress: 0/{n_handles}" ) ?;
286
+ stdout. flush ( ) ?;
287
+ let mut handle_num = 1 ;
288
+
289
+ for ( exercise_info, handle) in info_file. exercises . iter ( ) . zip ( handles) {
290
+ let Ok ( check_result) = handle. join ( ) else {
291
+ bail ! (
292
+ "Panic while trying to run the solution of the exericse {}" ,
293
+ exercise_info. name,
294
+ ) ;
295
+ } ;
296
+
297
+ match check_result {
298
+ SolutionCheck :: Success { sol_path } => {
299
+ fmt_cmd. arg ( & sol_path) ;
300
+ sol_paths. insert ( PathBuf :: from ( sol_path) ) ;
301
+ }
302
+ SolutionCheck :: MissingOptional => ( ) ,
303
+ SolutionCheck :: RunFailure { output } => {
304
+ stdout. write_all ( b"\n \n " ) ?;
305
+ stdout. write_all ( & output) ?;
290
306
bail ! (
291
- "Panic while trying to run the solution of the exericse {}" ,
307
+ "Running the solution of the exercise {} failed with the error above " ,
292
308
exercise_info. name,
293
309
) ;
294
- } ;
295
-
296
- match check_result {
297
- SolutionCheck :: Success { sol_path } => {
298
- fmt_cmd. arg ( & sol_path) ;
299
- sol_paths. insert ( PathBuf :: from ( sol_path) ) ;
300
- }
301
- SolutionCheck :: MissingOptional => ( ) ,
302
- SolutionCheck :: RunFailure { output } => {
303
- stdout. write_all ( b"\n \n " ) ?;
304
- stdout. write_all ( & output) ?;
305
- bail ! (
306
- "Running the solution of the exercise {} failed with the error above" ,
307
- exercise_info. name,
308
- ) ;
309
- }
310
- SolutionCheck :: Err ( e) => return Err ( e) ,
311
310
}
312
-
313
- write ! ( stdout, "\r Progress: {handle_num}/{n_handles}" ) ?;
314
- stdout. flush ( ) ?;
315
- handle_num += 1 ;
311
+ SolutionCheck :: Err ( e) => return Err ( e) ,
316
312
}
317
- stdout. write_all ( b"\n " ) ?;
318
313
319
- let handle = s. spawn ( move || check_unexpected_files ( "solutions" , & sol_paths) ) ;
314
+ write ! ( stdout, "\r Progress: {handle_num}/{n_handles}" ) ?;
315
+ stdout. flush ( ) ?;
316
+ handle_num += 1 ;
317
+ }
318
+ stdout. write_all ( b"\n " ) ?;
320
319
321
- if !fmt_cmd
322
- . status ( )
323
- . context ( "Failed to run `rustfmt` on all solution files" ) ?
324
- . success ( )
325
- {
326
- bail ! ( "Some solutions aren't formatted. Run `rustfmt` on them" ) ;
327
- }
320
+ let handle = thread:: spawn ( move || check_unexpected_files ( "solutions" , & sol_paths) ) ;
328
321
329
- handle. join ( ) . unwrap ( )
330
- } )
322
+ if !fmt_cmd
323
+ . status ( )
324
+ . context ( "Failed to run `rustfmt` on all solution files" ) ?
325
+ . success ( )
326
+ {
327
+ bail ! ( "Some solutions aren't formatted. Run `rustfmt` on them" ) ;
328
+ }
329
+
330
+ handle. join ( ) . unwrap ( )
331
331
}
332
332
333
333
pub fn check ( require_solutions : bool ) -> Result < ( ) > {
@@ -340,9 +340,12 @@ pub fn check(require_solutions: bool) -> Result<()> {
340
340
check_cargo_toml ( & info_file. exercises , "Cargo.toml" , b"" ) ?;
341
341
}
342
342
343
- let cmd_runner = CmdRunner :: build ( ) ?;
344
- check_exercises ( & info_file, & cmd_runner) ?;
345
- check_solutions ( require_solutions, & info_file, & cmd_runner) ?;
343
+ // Leaking is fine since they are used until the end of the program.
344
+ let cmd_runner = Box :: leak ( Box :: new ( CmdRunner :: build ( ) ?) ) ;
345
+ let info_file = Box :: leak ( Box :: new ( info_file) ) ;
346
+
347
+ check_exercises ( info_file, cmd_runner) ?;
348
+ check_solutions ( require_solutions, info_file, cmd_runner) ?;
346
349
347
350
println ! ( "Everything looks fine!" ) ;
348
351
0 commit comments