mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-08-14 14:26:56 +00:00
run exercises with CWD set to their directory
This commit is contained in:
parent
0f0d3b78ca
commit
343e21b3bd
@ -6,18 +6,14 @@
|
||||
// Let's simulate this using asynchronous programming. Each person is
|
||||
// represented as an asynchronous task, which can be executed concurrently.
|
||||
|
||||
const SCORES_CLASS_A: &str = "exercises/24_async/scores_class_a.txt";
|
||||
const SCORES_CLASS_B: &str = "exercises/24_async/scores_class_b.txt";
|
||||
const SCORES_CLASS_C: &str = "exercises/24_async/scores_class_c.txt";
|
||||
|
||||
// Async tasks need to be executed by a "runtime", which is not provided by
|
||||
// Rust's standard library. Here, we use the mainstream runtime `tokio`.
|
||||
// The macro `tokio::main` wraps the entire main function in a runtime.
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mean_score_a = tokio::spawn(calculate_mean_score(SCORES_CLASS_A));
|
||||
let mean_score_b = tokio::spawn(calculate_mean_score(SCORES_CLASS_B));
|
||||
let mean_score_c = tokio::spawn(calculate_mean_score(SCORES_CLASS_C));
|
||||
let mean_score_a = tokio::spawn(calculate_mean_score("scores_class_a.txt"));
|
||||
let mean_score_b = tokio::spawn(calculate_mean_score("scores_class_b.txt"));
|
||||
let mean_score_c = tokio::spawn(calculate_mean_score("scores_class_c.txt"));
|
||||
|
||||
// TODO: Await the spawned tasks to check their results.
|
||||
assert_eq!(mean_score_a, 84); // alice
|
||||
|
||||
@ -6,18 +6,14 @@
|
||||
// Let's simulate this using asynchronous programming. Each person is
|
||||
// represented as an asynchronous task, which can be executed concurrently.
|
||||
|
||||
const SCORES_CLASS_A: &str = "exercises/24_async/scores_class_a.txt";
|
||||
const SCORES_CLASS_B: &str = "exercises/24_async/scores_class_b.txt";
|
||||
const SCORES_CLASS_C: &str = "exercises/24_async/scores_class_c.txt";
|
||||
|
||||
// Async tasks need to be executed by a "runtime", which is not provided by
|
||||
// Rust's standard library. Here, we use the mainstream runtime `tokio`.
|
||||
// The macro `tokio::main` wraps the entire main function in a runtime.
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mean_score_a = tokio::spawn(calculate_mean_score(SCORES_CLASS_A));
|
||||
let mean_score_b = tokio::spawn(calculate_mean_score(SCORES_CLASS_B));
|
||||
let mean_score_c = tokio::spawn(calculate_mean_score(SCORES_CLASS_C));
|
||||
let mean_score_a = tokio::spawn(calculate_mean_score("scores_class_a.txt"));
|
||||
let mean_score_b = tokio::spawn(calculate_mean_score("scores_class_b.txt"));
|
||||
let mean_score_c = tokio::spawn(calculate_mean_score("scores_class_c.txt"));
|
||||
|
||||
assert_eq!(mean_score_a.await.unwrap(), 84); // alice
|
||||
assert_eq!(mean_score_b.await.unwrap(), 89); // bob
|
||||
|
||||
23
src/cmd.rs
23
src/cmd.rs
@ -13,7 +13,12 @@ const TIMEOUT_SECS: u64 = 30;
|
||||
|
||||
/// Run a command with a description for a possible error and append the merged stdout and stderr.
|
||||
/// The boolean in the returned `Result` is true if the command's exit status is success.
|
||||
fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec<u8>>) -> Result<bool> {
|
||||
fn run_cmd(
|
||||
mut cmd: Command,
|
||||
description: &str,
|
||||
cwd: Option<&str>,
|
||||
output: Option<&mut Vec<u8>>,
|
||||
) -> Result<bool> {
|
||||
let spawn = |mut cmd: Command| {
|
||||
// The closure drops `cmd` which prevents a pipe deadlock.
|
||||
cmd.stdin(Stdio::null())
|
||||
@ -25,6 +30,9 @@ fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec<u8>>) ->
|
||||
.wait_timeout(Duration::from_secs(TIMEOUT_SECS))
|
||||
.with_context(|| format!("Failed to wait on `{description}` to exit"))
|
||||
};
|
||||
if let Some(cwd) = cwd {
|
||||
cmd.current_dir(cwd);
|
||||
}
|
||||
|
||||
let mut handle = if let Some(output) = output {
|
||||
let (mut reader, writer) =
|
||||
@ -133,7 +141,12 @@ impl CmdRunner {
|
||||
}
|
||||
|
||||
/// The boolean in the returned `Result` is true if the command's exit status is success.
|
||||
pub fn run_debug_bin(&self, bin_name: &str, output: Option<&mut Vec<u8>>) -> Result<bool> {
|
||||
pub fn run_debug_bin(
|
||||
&self,
|
||||
bin_name: &str,
|
||||
cwd: &str,
|
||||
output: Option<&mut Vec<u8>>,
|
||||
) -> Result<bool> {
|
||||
// 7 = "/debug/".len()
|
||||
let mut bin_path =
|
||||
PathBuf::with_capacity(self.target_dir.as_os_str().len() + 7 + bin_name.len());
|
||||
@ -141,7 +154,7 @@ impl CmdRunner {
|
||||
bin_path.push("debug");
|
||||
bin_path.push(bin_name);
|
||||
|
||||
run_cmd(Command::new(&bin_path), bin_name, output)
|
||||
run_cmd(Command::new(&bin_path), bin_name, Some(cwd), output)
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +174,7 @@ impl CargoSubcommand<'_> {
|
||||
|
||||
/// The boolean in the returned `Result` is true if the command's exit status is success.
|
||||
pub fn run(self, description: &str) -> Result<bool> {
|
||||
run_cmd(self.cmd, description, self.output)
|
||||
run_cmd(self.cmd, description, None, self.output)
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +192,7 @@ mod tests {
|
||||
cmd.arg("Hello");
|
||||
|
||||
let mut output = Vec::with_capacity(8);
|
||||
run_cmd(cmd, "echo …", Some(&mut output)).unwrap();
|
||||
run_cmd(cmd, "echo …", None, Some(&mut output)).unwrap();
|
||||
|
||||
assert_eq!(output, b"Hello\n\n");
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ pub fn solution_link_line(
|
||||
// Compilation must be done before calling this method.
|
||||
fn run_bin(
|
||||
bin_name: &str,
|
||||
cwd: &str,
|
||||
mut output: Option<&mut Vec<u8>>,
|
||||
cmd_runner: &CmdRunner,
|
||||
) -> Result<bool> {
|
||||
@ -46,7 +47,7 @@ fn run_bin(
|
||||
output.push(b'\n');
|
||||
}
|
||||
|
||||
let success = cmd_runner.run_debug_bin(bin_name, output.as_deref_mut())?;
|
||||
let success = cmd_runner.run_debug_bin(bin_name, cwd, output.as_deref_mut())?;
|
||||
|
||||
if let Some(output) = output
|
||||
&& !success
|
||||
@ -123,6 +124,14 @@ pub trait RunnableExercise {
|
||||
output.clear();
|
||||
}
|
||||
|
||||
let cwd_buf;
|
||||
let cwd = if let Some(dir) = self.dir() {
|
||||
cwd_buf = format!("exercises/{dir}");
|
||||
cwd_buf.as_str()
|
||||
} else {
|
||||
"exercises"
|
||||
};
|
||||
|
||||
if self.test() {
|
||||
let output_is_some = output.is_some();
|
||||
let mut test_cmd = cmd_runner.cargo("test", bin_name, output.as_deref_mut());
|
||||
@ -131,7 +140,7 @@ pub trait RunnableExercise {
|
||||
}
|
||||
let test_success = test_cmd.run("cargo test …")?;
|
||||
if !test_success {
|
||||
run_bin(bin_name, output, cmd_runner)?;
|
||||
run_bin(bin_name, cwd, output, cmd_runner)?;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
@ -151,7 +160,7 @@ pub trait RunnableExercise {
|
||||
}
|
||||
|
||||
let clippy_success = clippy_cmd.run("cargo clippy …")?;
|
||||
let run_success = run_bin(bin_name, output, cmd_runner)?;
|
||||
let run_success = run_bin(bin_name, cwd, output, cmd_runner)?;
|
||||
|
||||
Ok(clippy_success && run_success)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user