Fix ownership issues with runners

Signed-off-by: Luke Boswell <lukewilliamboswell@gmail.com>
This commit is contained in:
Sam Mohr 2024-08-14 15:12:42 -07:00
parent bc29782420
commit 89d63f23b7
No known key found for this signature in database
GPG key ID: EA41D161A3C1BC99
2 changed files with 48 additions and 34 deletions

View file

@ -14,8 +14,14 @@ fn exec_bench_w_input<T: Measurement>(
expected_ending: &str, expected_ending: &str,
bench_group_opt: Option<&mut BenchmarkGroup<T>>, bench_group_opt: Option<&mut BenchmarkGroup<T>>,
) { ) {
let run = Run::new_roc().add_args(["build", BUILD_HOST_FLAG, OPTIMIZE_FLAG, file.to_str().unwrap()]); let runner = Run::new_roc().add_args([
let compile_out = run.run(); "build",
BUILD_HOST_FLAG,
OPTIMIZE_FLAG,
file.to_str().unwrap(),
]);
let compile_out = runner.run();
if !compile_out.stderr.is_empty() && compile_out.stderr != "🔨 Rebuilding platform...\n" { if !compile_out.stderr.is_empty() && compile_out.stderr != "🔨 Rebuilding platform...\n" {
panic!("stderr was not empty:\n\t{}", compile_out.stderr); panic!("stderr was not empty:\n\t{}", compile_out.stderr);
@ -43,17 +49,19 @@ fn check_cmd_output(
.unwrap() .unwrap()
.to_string(); .to_string();
let run = Run::new(&cmd_str).with_stdin_vals([stdin_str]); let runner = Run::new(&cmd_str).with_stdin_vals([stdin_str]);
let out = if cmd_str.contains("cfold") { let out = if cmd_str.contains("cfold") {
let child = thread::Builder::new() thread::scope(|s| {
.stack_size(CFOLD_STACK_SIZE) let child = thread::Builder::new()
.spawn(move || run.run()) .stack_size(CFOLD_STACK_SIZE)
.unwrap(); .spawn_scoped(s, move || runner.run())
.unwrap();
child.join().unwrap() child.join().unwrap()
})
} else { } else {
run.run() runner.run()
}; };
if !&out.stdout.ends_with(expected_ending) { if !&out.stdout.ends_with(expected_ending) {
@ -64,7 +72,7 @@ fn check_cmd_output(
fn bench_cmd<T: Measurement>( fn bench_cmd<T: Measurement>(
file: &Path, file: &Path,
stdin_str: &str, stdin_str: &'static str,
executable_filename: &str, executable_filename: &str,
bench_group_opt: Option<&mut BenchmarkGroup<T>>, bench_group_opt: Option<&mut BenchmarkGroup<T>>,
) { ) {
@ -92,13 +100,18 @@ fn bench_cmd<T: Measurement>(
} }
} }
if let Some(bench_group) = bench_group_opt { if let Some(bench_group) = bench_group_opt {
bench_group.bench_function(&format!("Benchmarking {executable_filename:?}"), |b| { bench_group.bench_function(&format!("Benchmarking {executable_filename:?}"), |b| {
b.iter(|| Run::new(black_box(&cmd_str)).with_stdin_vals([stdin_str]).run()) b.iter(|| {
Run::new(black_box(&cmd_str))
.with_stdin_vals([stdin_str])
.run()
})
}); });
} else { } else {
Run::new(file.with_file_name(executable_filename).to_str().unwrap()).with_stdin_vals([stdin_str]).run(); Run::new(file.with_file_name(executable_filename).to_str().unwrap())
.with_stdin_vals([stdin_str])
.run();
} }
} }

View file

@ -10,7 +10,6 @@ use serde::Deserialize;
use serde_xml_rs::from_str; use serde_xml_rs::from_str;
use std::env; use std::env;
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::io::Read;
use std::io::Write; use std::io::Write;
use std::ops::Deref; use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
@ -34,16 +33,16 @@ lazy_static::lazy_static! {
static GLUE_LOCK: Mutex<()> = Mutex::new(()); static GLUE_LOCK: Mutex<()> = Mutex::new(());
#[derive(Debug)] #[derive(Debug)]
pub struct Out<'run> { pub struct Out {
pub cmd_str: OsString, // command with all its arguments, for easy debugging pub cmd_str: OsString, // command with all its arguments, for easy debugging
pub stdout: String, pub stdout: String,
pub stderr: String, pub stderr: String,
pub status: ExitStatus, pub status: ExitStatus,
pub run: &'run Run<'run>, pub run: Run,
pub valgrind_xml: Option<NamedTempFile>, pub valgrind_xml: Option<NamedTempFile>,
} }
impl std::fmt::Display for Out<'_> { impl std::fmt::Display for Out {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(
f, f,
@ -56,7 +55,7 @@ impl std::fmt::Display for Out<'_> {
} }
} }
impl Out<'_> { impl Out {
pub fn assert_clean_success(&self) { pub fn assert_clean_success(&self) {
self.assert_success_with_no_unexpected_errors(COMMON_STDERR.as_slice()); self.assert_success_with_no_unexpected_errors(COMMON_STDERR.as_slice());
} }
@ -91,13 +90,13 @@ impl Out<'_> {
/// Unlike `std::process::Command`, this builder is clonable and provides convenience methods for /// Unlike `std::process::Command`, this builder is clonable and provides convenience methods for
/// constructing Commands for the configured run and instrumenting the configured command with valgrind. /// constructing Commands for the configured run and instrumenting the configured command with valgrind.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Run<'a> { pub struct Run {
args: Vec<OsString>, args: Vec<OsString>,
env: Vec<(String, String)>, env: Vec<(String, String)>,
stdin_vals: Vec<&'a str>, stdin_vals: Vec<&'static str>,
} }
impl<'run> Run<'run> { impl<'run> Run {
pub fn new<S>(exe: S) -> Self pub fn new<S>(exe: S) -> Self
where where
S: AsRef<OsStr>, S: AsRef<OsStr>,
@ -159,7 +158,7 @@ impl<'run> Run<'run> {
(cmd, named_tempfile) (cmd, named_tempfile)
} }
pub fn arg<S>(&mut self, arg: S) -> &mut Self pub fn arg<S>(mut self, arg: S) -> Self
where where
S: Into<OsString>, S: Into<OsString>,
{ {
@ -167,13 +166,13 @@ impl<'run> Run<'run> {
self self
} }
pub fn add_args<I, S>(&mut self, args: I) -> &mut Self pub fn add_args<I, S>(mut self, args: I) -> Self
where where
I: IntoIterator<Item = S>, I: IntoIterator<Item = S>,
S: AsRef<OsStr>, S: AsRef<OsStr>,
{ {
for arg in args { for arg in args {
self.arg(&arg); self = self.arg(&arg);
} }
self self
} }
@ -186,16 +185,17 @@ impl<'run> Run<'run> {
self.env.iter().map(|(k, v)| (k.as_str(), v.as_str())) self.env.iter().map(|(k, v)| (k.as_str(), v.as_str()))
} }
pub fn with_stdin_vals<I>(&mut self, stdin_vals: I) -> &mut Self pub fn with_stdin_vals<I>(mut self, stdin_vals: I) -> Self
where where
I: IntoIterator<Item = &'run str>, I: IntoIterator<Item = &'static str>,
{ {
self.stdin_vals.extend(stdin_vals.into_iter()); self.stdin_vals.extend(stdin_vals.into_iter());
self self
} }
pub fn with_env<'a, I>(&mut self, env: I) -> &mut Self pub fn with_env<'a, I>(&mut self, env: I) -> &mut Self
where I: IntoIterator<Item = (&'a str, &'a str)> where
I: IntoIterator<Item = (&'a str, &'a str)>,
{ {
for (k, v) in env { for (k, v) in env {
self.env.push((k.into(), v.into())); self.env.push((k.into(), v.into()));
@ -203,7 +203,7 @@ impl<'run> Run<'run> {
self self
} }
fn do_run(&self, mut cmd: Command, stdin_vals: &[&str]) -> Out { fn run_with_command(self, mut cmd: Command) -> Out {
let cmd_str = pretty_command_string(&cmd); let cmd_str = pretty_command_string(&cmd);
let mut roc_cmd_child = cmd let mut roc_cmd_child = cmd
.stdin(Stdio::piped()) .stdin(Stdio::piped())
@ -215,7 +215,7 @@ impl<'run> Run<'run> {
}); });
let stdin = roc_cmd_child.stdin.as_mut().expect("Failed to open stdin"); let stdin = roc_cmd_child.stdin.as_mut().expect("Failed to open stdin");
for stdin_str in stdin_vals.iter() { for stdin_str in self.stdin_vals.iter() {
stdin stdin
.write_all(stdin_str.as_bytes()) .write_all(stdin_str.as_bytes())
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@ -236,18 +236,19 @@ impl<'run> Run<'run> {
} }
} }
pub fn run(&mut self) -> Out { pub fn run(self) -> Out {
self.do_run(self.command(), &self.stdin_vals) let command = self.command();
self.run_with_command(command)
} }
pub fn run_glue(&mut self) -> Out { pub fn run_glue(self) -> Out {
let _guard = GLUE_LOCK.lock().unwrap(); let _guard = GLUE_LOCK.lock().unwrap();
self.run() self.run()
} }
pub fn run_with_valgrind(&mut self) -> Out { pub fn run_with_valgrind(self) -> Out {
let (valgrind_cmd, valgrind_xml) = self.valgrind_command(); let (valgrind_cmd, valgrind_xml) = self.valgrind_command();
let mut out = self.do_run(valgrind_cmd, &self.stdin_vals); let mut out = self.run_with_command(valgrind_cmd);
out.valgrind_xml = Some(valgrind_xml); out.valgrind_xml = Some(valgrind_xml);
out out
} }