Skip to content

Commit bdd76cd

Browse files
committed
Merge branch 'run-sols-in-parallel'
2 parents 825637f + 42a3503 commit bdd76cd

File tree

1 file changed

+49
-25
lines changed

1 file changed

+49
-25
lines changed

src/dev/check.rs

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ use std::{
44
fs::{self, read_dir, OpenOptions},
55
io::{self, Read, Write},
66
path::{Path, PathBuf},
7+
sync::{
8+
atomic::{self, AtomicBool},
9+
Mutex,
10+
},
11+
thread,
712
};
813

914
use crate::{
@@ -167,36 +172,52 @@ fn check_exercises(info_file: &InfoFile) -> Result<()> {
167172
}
168173

169174
fn check_solutions(require_solutions: bool, info_file: &InfoFile) -> Result<()> {
170-
let mut paths = hashbrown::HashSet::with_capacity(info_file.exercises.len());
171175
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"\nFailed 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+
});
183213
}
214+
});
184215

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.");
197218
}
198219

199-
check_unexpected_files("solutions", &paths)?;
220+
check_unexpected_files("solutions", &paths.into_inner().unwrap())?;
200221

201222
Ok(())
202223
}
@@ -224,3 +245,6 @@ pub fn check(require_solutions: bool) -> Result<()> {
224245

225246
Ok(())
226247
}
248+
249+
const SEPARATOR: &[u8] =
250+
b"\n========================================================================================\n";

0 commit comments

Comments
 (0)