Skip to content

Commit 343e21b

Browse files
committed
run exercises with CWD set to their directory
1 parent 0f0d3b7 commit 343e21b

4 files changed

Lines changed: 36 additions & 22 deletions

File tree

exercises/24_async/async1.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,14 @@
66
// Let's simulate this using asynchronous programming. Each person is
77
// represented as an asynchronous task, which can be executed concurrently.
88

9-
const SCORES_CLASS_A: &str = "exercises/24_async/scores_class_a.txt";
10-
const SCORES_CLASS_B: &str = "exercises/24_async/scores_class_b.txt";
11-
const SCORES_CLASS_C: &str = "exercises/24_async/scores_class_c.txt";
12-
139
// Async tasks need to be executed by a "runtime", which is not provided by
1410
// Rust's standard library. Here, we use the mainstream runtime `tokio`.
1511
// The macro `tokio::main` wraps the entire main function in a runtime.
1612
#[tokio::main]
1713
async fn main() {
18-
let mean_score_a = tokio::spawn(calculate_mean_score(SCORES_CLASS_A));
19-
let mean_score_b = tokio::spawn(calculate_mean_score(SCORES_CLASS_B));
20-
let mean_score_c = tokio::spawn(calculate_mean_score(SCORES_CLASS_C));
14+
let mean_score_a = tokio::spawn(calculate_mean_score("scores_class_a.txt"));
15+
let mean_score_b = tokio::spawn(calculate_mean_score("scores_class_b.txt"));
16+
let mean_score_c = tokio::spawn(calculate_mean_score("scores_class_c.txt"));
2117

2218
// TODO: Await the spawned tasks to check their results.
2319
assert_eq!(mean_score_a, 84); // alice

solutions/24_async/async1.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,14 @@
66
// Let's simulate this using asynchronous programming. Each person is
77
// represented as an asynchronous task, which can be executed concurrently.
88

9-
const SCORES_CLASS_A: &str = "exercises/24_async/scores_class_a.txt";
10-
const SCORES_CLASS_B: &str = "exercises/24_async/scores_class_b.txt";
11-
const SCORES_CLASS_C: &str = "exercises/24_async/scores_class_c.txt";
12-
139
// Async tasks need to be executed by a "runtime", which is not provided by
1410
// Rust's standard library. Here, we use the mainstream runtime `tokio`.
1511
// The macro `tokio::main` wraps the entire main function in a runtime.
1612
#[tokio::main]
1713
async fn main() {
18-
let mean_score_a = tokio::spawn(calculate_mean_score(SCORES_CLASS_A));
19-
let mean_score_b = tokio::spawn(calculate_mean_score(SCORES_CLASS_B));
20-
let mean_score_c = tokio::spawn(calculate_mean_score(SCORES_CLASS_C));
14+
let mean_score_a = tokio::spawn(calculate_mean_score("scores_class_a.txt"));
15+
let mean_score_b = tokio::spawn(calculate_mean_score("scores_class_b.txt"));
16+
let mean_score_c = tokio::spawn(calculate_mean_score("scores_class_c.txt"));
2117

2218
assert_eq!(mean_score_a.await.unwrap(), 84); // alice
2319
assert_eq!(mean_score_b.await.unwrap(), 89); // bob

src/cmd.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ const TIMEOUT_SECS: u64 = 30;
1313

1414
/// Run a command with a description for a possible error and append the merged stdout and stderr.
1515
/// The boolean in the returned `Result` is true if the command's exit status is success.
16-
fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec<u8>>) -> Result<bool> {
16+
fn run_cmd(
17+
mut cmd: Command,
18+
description: &str,
19+
cwd: Option<&str>,
20+
output: Option<&mut Vec<u8>>,
21+
) -> Result<bool> {
1722
let spawn = |mut cmd: Command| {
1823
// The closure drops `cmd` which prevents a pipe deadlock.
1924
cmd.stdin(Stdio::null())
@@ -25,6 +30,9 @@ fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec<u8>>) ->
2530
.wait_timeout(Duration::from_secs(TIMEOUT_SECS))
2631
.with_context(|| format!("Failed to wait on `{description}` to exit"))
2732
};
33+
if let Some(cwd) = cwd {
34+
cmd.current_dir(cwd);
35+
}
2836

2937
let mut handle = if let Some(output) = output {
3038
let (mut reader, writer) =
@@ -133,15 +141,20 @@ impl CmdRunner {
133141
}
134142

135143
/// The boolean in the returned `Result` is true if the command's exit status is success.
136-
pub fn run_debug_bin(&self, bin_name: &str, output: Option<&mut Vec<u8>>) -> Result<bool> {
144+
pub fn run_debug_bin(
145+
&self,
146+
bin_name: &str,
147+
cwd: &str,
148+
output: Option<&mut Vec<u8>>,
149+
) -> Result<bool> {
137150
// 7 = "/debug/".len()
138151
let mut bin_path =
139152
PathBuf::with_capacity(self.target_dir.as_os_str().len() + 7 + bin_name.len());
140153
bin_path.push(&self.target_dir);
141154
bin_path.push("debug");
142155
bin_path.push(bin_name);
143156

144-
run_cmd(Command::new(&bin_path), bin_name, output)
157+
run_cmd(Command::new(&bin_path), bin_name, Some(cwd), output)
145158
}
146159
}
147160

@@ -161,7 +174,7 @@ impl CargoSubcommand<'_> {
161174

162175
/// The boolean in the returned `Result` is true if the command's exit status is success.
163176
pub fn run(self, description: &str) -> Result<bool> {
164-
run_cmd(self.cmd, description, self.output)
177+
run_cmd(self.cmd, description, None, self.output)
165178
}
166179
}
167180

@@ -179,7 +192,7 @@ mod tests {
179192
cmd.arg("Hello");
180193

181194
let mut output = Vec::with_capacity(8);
182-
run_cmd(cmd, "echo …", Some(&mut output)).unwrap();
195+
run_cmd(cmd, "echo …", None, Some(&mut output)).unwrap();
183196

184197
assert_eq!(output, b"Hello\n\n");
185198
}

src/exercise.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub fn solution_link_line(
3636
// Compilation must be done before calling this method.
3737
fn run_bin(
3838
bin_name: &str,
39+
cwd: &str,
3940
mut output: Option<&mut Vec<u8>>,
4041
cmd_runner: &CmdRunner,
4142
) -> Result<bool> {
@@ -46,7 +47,7 @@ fn run_bin(
4647
output.push(b'\n');
4748
}
4849

49-
let success = cmd_runner.run_debug_bin(bin_name, output.as_deref_mut())?;
50+
let success = cmd_runner.run_debug_bin(bin_name, cwd, output.as_deref_mut())?;
5051

5152
if let Some(output) = output
5253
&& !success
@@ -123,6 +124,14 @@ pub trait RunnableExercise {
123124
output.clear();
124125
}
125126

127+
let cwd_buf;
128+
let cwd = if let Some(dir) = self.dir() {
129+
cwd_buf = format!("exercises/{dir}");
130+
cwd_buf.as_str()
131+
} else {
132+
"exercises"
133+
};
134+
126135
if self.test() {
127136
let output_is_some = output.is_some();
128137
let mut test_cmd = cmd_runner.cargo("test", bin_name, output.as_deref_mut());
@@ -131,7 +140,7 @@ pub trait RunnableExercise {
131140
}
132141
let test_success = test_cmd.run("cargo test …")?;
133142
if !test_success {
134-
run_bin(bin_name, output, cmd_runner)?;
143+
run_bin(bin_name, cwd, output, cmd_runner)?;
135144
return Ok(false);
136145
}
137146

@@ -151,7 +160,7 @@ pub trait RunnableExercise {
151160
}
152161

153162
let clippy_success = clippy_cmd.run("cargo clippy …")?;
154-
let run_success = run_bin(bin_name, output, cmd_runner)?;
163+
let run_success = run_bin(bin_name, cwd, output, cmd_runner)?;
155164

156165
Ok(clippy_success && run_success)
157166
}

0 commit comments

Comments
 (0)