Skip to content

Commit 50f6e52

Browse files
committed
Leak info_file and cmd_runner in dev check
1 parent 8854f0a commit 50f6e52

File tree

1 file changed

+125
-122
lines changed

1 file changed

+125
-122
lines changed

src/dev/check.rs

Lines changed: 125 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -165,65 +165,67 @@ fn check_unexpected_files(dir: &str, allowed_rust_files: &HashSet<PathBuf>) -> R
165165
Ok(())
166166
}
167167

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<()> {
169172
let mut stdout = io::stdout().lock();
170173
stdout.write_all(b"Running all exercises to check that they aren't already solved...\n")?;
171174

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;
204181
}
205182

206-
write!(stdout, "\rProgress: {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),
209206
}
210-
stdout.write_all(b"\n")?;
211207

212-
Ok(())
213-
})
208+
write!(stdout, "\rProgress: {handle_num}/{n_handles}")?;
209+
stdout.flush()?;
210+
handle_num += 1;
211+
}
212+
stdout.write_all(b"\n")?;
213+
214+
Ok(())
214215
}
215216

216-
fn check_exercises(info_file: &InfoFile, cmd_runner: &CmdRunner) -> Result<()> {
217+
fn check_exercises(info_file: &'static InfoFile, cmd_runner: &'static CmdRunner) -> Result<()> {
217218
match info_file.format_version.cmp(&CURRENT_FORMAT_VERSION) {
218219
Ordering::Less => bail!("`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\nPlease migrate to the latest format version"),
219220
Ordering::Greater => bail!("`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\nTry updating the Rustlings program"),
220221
Ordering::Equal => (),
221222
}
222223

224+
let handle = thread::spawn(move || check_exercises_unsolved(info_file, cmd_runner));
225+
223226
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)?;
225228

226-
check_exercises_unsolved(info_file, cmd_runner)?;
227229
handle.join().unwrap()
228230
}
229231

@@ -236,98 +238,96 @@ enum SolutionCheck {
236238

237239
fn check_solutions(
238240
require_solutions: bool,
239-
info_file: &InfoFile,
240-
cmd_runner: &CmdRunner,
241+
info_file: &'static InfoFile,
242+
cmd_runner: &'static CmdRunner,
241243
) -> Result<()> {
242244
let mut stdout = io::stdout().lock();
243245
stdout.write_all(b"Running all solutions...\n")?;
244246

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+
));
261259
}
262260

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+
}
287263

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)?;
290306
bail!(
291-
"Panic while trying to run the solution of the exericse {}",
307+
"Running the solution of the exercise {} failed with the error above",
292308
exercise_info.name,
293309
);
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),
311310
}
312-
313-
write!(stdout, "\rProgress: {handle_num}/{n_handles}")?;
314-
stdout.flush()?;
315-
handle_num += 1;
311+
SolutionCheck::Err(e) => return Err(e),
316312
}
317-
stdout.write_all(b"\n")?;
318313

319-
let handle = s.spawn(move || check_unexpected_files("solutions", &sol_paths));
314+
write!(stdout, "\rProgress: {handle_num}/{n_handles}")?;
315+
stdout.flush()?;
316+
handle_num += 1;
317+
}
318+
stdout.write_all(b"\n")?;
320319

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));
328321

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()
331331
}
332332

333333
pub fn check(require_solutions: bool) -> Result<()> {
@@ -340,9 +340,12 @@ pub fn check(require_solutions: bool) -> Result<()> {
340340
check_cargo_toml(&info_file.exercises, "Cargo.toml", b"")?;
341341
}
342342

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)?;
346349

347350
println!("Everything looks fine!");
348351

0 commit comments

Comments
 (0)