@@ -162,7 +162,46 @@ fn check_unexpected_files(
162
162
Ok ( ( ) )
163
163
}
164
164
165
- fn check_exercises ( info_file : & InfoFile ) -> Result < ( ) > {
165
+ fn check_exercises_unsolved ( info_file : & InfoFile , target_dir : & Path ) -> Result < ( ) > {
166
+ let error_occurred = AtomicBool :: new ( false ) ;
167
+
168
+ println ! (
169
+ "Running all exercises to check that they aren't already solved. This may take a while…\n " ,
170
+ ) ;
171
+ thread:: scope ( |s| {
172
+ for exercise_info in & info_file. exercises {
173
+ if exercise_info. skip_check_unsolved {
174
+ continue ;
175
+ }
176
+
177
+ s. spawn ( || {
178
+ let error = |e| {
179
+ let mut stderr = io:: stderr ( ) . lock ( ) ;
180
+ stderr. write_all ( e) . unwrap ( ) ;
181
+ stderr. write_all ( b"\n Problem with the exercise " ) . unwrap ( ) ;
182
+ stderr. write_all ( exercise_info. name . as_bytes ( ) ) . unwrap ( ) ;
183
+ stderr. write_all ( SEPARATOR ) . unwrap ( ) ;
184
+ error_occurred. store ( true , atomic:: Ordering :: Relaxed ) ;
185
+ } ;
186
+
187
+ let mut output = Vec :: with_capacity ( OUTPUT_CAPACITY ) ;
188
+ match exercise_info. run_exercise ( & mut output, target_dir) {
189
+ Ok ( true ) => error ( b"Already solved!" ) ,
190
+ Ok ( false ) => ( ) ,
191
+ Err ( e) => error ( e. to_string ( ) . as_bytes ( ) ) ,
192
+ }
193
+ } ) ;
194
+ }
195
+ } ) ;
196
+
197
+ if error_occurred. load ( atomic:: Ordering :: Relaxed ) {
198
+ bail ! ( CHECK_EXERCISES_UNSOLVED_ERR ) ;
199
+ }
200
+
201
+ Ok ( ( ) )
202
+ }
203
+
204
+ fn check_exercises ( info_file : & InfoFile , target_dir : & Path ) -> Result < ( ) > {
166
205
match info_file. format_version . cmp ( & CURRENT_FORMAT_VERSION ) {
167
206
Ordering :: Less => bail ! ( "`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\n Please migrate to the latest format version" ) ,
168
207
Ordering :: Greater => bail ! ( "`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\n Try updating the Rustlings program" ) ,
@@ -172,15 +211,14 @@ fn check_exercises(info_file: &InfoFile) -> Result<()> {
172
211
let info_file_paths = check_info_file_exercises ( info_file) ?;
173
212
check_unexpected_files ( "exercises" , & info_file_paths) ?;
174
213
175
- Ok ( ( ) )
214
+ check_exercises_unsolved ( info_file , target_dir )
176
215
}
177
216
178
- fn check_solutions ( require_solutions : bool , info_file : & InfoFile ) -> Result < ( ) > {
179
- let target_dir = parse_target_dir ( ) ?;
217
+ fn check_solutions ( require_solutions : bool , info_file : & InfoFile , target_dir : & Path ) -> Result < ( ) > {
180
218
let paths = Mutex :: new ( hashbrown:: HashSet :: with_capacity ( info_file. exercises . len ( ) ) ) ;
181
219
let error_occurred = AtomicBool :: new ( false ) ;
182
220
183
- println ! ( "Running all solutions. This may take a while... \n " ) ;
221
+ println ! ( "Running all solutions. This may take a while… \n " ) ;
184
222
thread:: scope ( |s| {
185
223
for exercise_info in & info_file. exercises {
186
224
s. spawn ( || {
@@ -206,7 +244,7 @@ fn check_solutions(require_solutions: bool, info_file: &InfoFile) -> Result<()>
206
244
}
207
245
208
246
let mut output = Vec :: with_capacity ( OUTPUT_CAPACITY ) ;
209
- match exercise_info. run_solution ( & mut output, & target_dir) {
247
+ match exercise_info. run_solution ( & mut output, target_dir) {
210
248
Ok ( true ) => {
211
249
paths. lock ( ) . unwrap ( ) . insert ( PathBuf :: from ( path) ) ;
212
250
}
@@ -242,8 +280,9 @@ pub fn check(require_solutions: bool) -> Result<()> {
242
280
check_cargo_toml ( & info_file. exercises , & current_cargo_toml, b"" ) ?;
243
281
}
244
282
245
- check_exercises ( & info_file) ?;
246
- check_solutions ( require_solutions, & info_file) ?;
283
+ let target_dir = parse_target_dir ( ) ?;
284
+ check_exercises ( & info_file, & target_dir) ?;
285
+ check_solutions ( require_solutions, & info_file, & target_dir) ?;
247
286
248
287
println ! ( "\n Everything looks fine!" ) ;
249
288
@@ -252,3 +291,6 @@ pub fn check(require_solutions: bool) -> Result<()> {
252
291
253
292
const SEPARATOR : & [ u8 ] =
254
293
b"\n ========================================================================================\n " ;
294
+
295
+ const CHECK_EXERCISES_UNSOLVED_ERR : & str = "At least one exercise is already solved or failed to run. See the output above.
296
+ If this is an intro exercise that is intended to be already solved, add `skip_check_unsolved = true` to the exercise's metadata in the `info.toml` file." ;
0 commit comments