Skip to content

Commit e0c56fb

Browse files
committed
fix(cargo-codspeed): handle working-directory when using workspaces
1 parent be64f4f commit e0c56fb

File tree

11 files changed

+164
-61
lines changed

11 files changed

+164
-61
lines changed

crates/cargo-codspeed/src/build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
helpers::{clear_dir, get_codspeed_dir},
2+
helpers::{clear_dir, get_codspeed_target_dir},
33
prelude::*,
44
};
55

@@ -125,7 +125,7 @@ pub fn build_benches(
125125
.shell()
126126
.status_with_color("Built", benches_names_str, Color::Green)?;
127127

128-
let mut codspeed_target_dir = get_codspeed_dir(ws);
128+
let mut codspeed_target_dir = get_codspeed_target_dir(ws);
129129
create_dir_all(&codspeed_target_dir)?;
130130
if let Some(name) = package_name.as_ref() {
131131
codspeed_target_dir = codspeed_target_dir.join(name);

crates/cargo-codspeed/src/helpers.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,13 @@
11
use crate::prelude::*;
22
use std::path::{Path, PathBuf};
33

4-
pub fn get_codspeed_dir(ws: &Workspace) -> PathBuf {
4+
pub fn get_codspeed_target_dir(ws: &Workspace) -> PathBuf {
55
ws.target_dir()
66
.as_path_unlocked()
77
.to_path_buf()
88
.join("codspeed")
99
}
1010

11-
pub fn read_dir_recursive<P>(dir: P) -> Result<Vec<PathBuf>>
12-
where
13-
P: AsRef<Path>,
14-
{
15-
let mut out = vec![];
16-
for entry in std::fs::read_dir(dir)? {
17-
let entry = entry?;
18-
let path = entry.path();
19-
if path.is_dir() {
20-
out.extend(read_dir_recursive(&path)?);
21-
} else {
22-
out.push(path);
23-
}
24-
}
25-
Ok(out)
26-
}
27-
2811
pub fn clear_dir<P>(dir: P) -> Result<()>
2912
where
3013
P: AsRef<Path>,

crates/cargo-codspeed/src/run.rs

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,120 @@
1+
use std::{io, path::PathBuf};
2+
13
use anyhow::anyhow;
24
use termcolor::Color;
35

4-
use crate::{
5-
helpers::{get_codspeed_dir, read_dir_recursive},
6-
prelude::*,
7-
};
6+
use crate::{helpers::get_codspeed_target_dir, prelude::*};
7+
8+
struct BenchToRun {
9+
bench_path: PathBuf,
10+
bench_name: String,
11+
working_directory: PathBuf,
12+
package_name: String,
13+
}
814

915
pub fn run_benches(
1016
ws: &Workspace,
11-
benches: Option<Vec<String>>,
17+
selected_bench_names: Option<Vec<String>>,
1218
package: Option<String>,
1319
) -> Result<()> {
14-
let mut codspeed_dir = get_codspeed_dir(ws);
20+
let codspeed_target_dir = get_codspeed_target_dir(ws);
1521

16-
if let Some(package) = package {
17-
codspeed_dir.push(package.clone());
18-
if !codspeed_dir.exists() {
19-
return Err(anyhow!(
22+
let packages_to_run = if let Some(package) = package.as_ref() {
23+
let p = ws
24+
.members()
25+
.find(|m| m.manifest().name().to_string().as_str() == package);
26+
if let Some(p) = p {
27+
vec![p]
28+
} else {
29+
bail!("Package {} not found", package);
30+
}
31+
} else {
32+
ws.default_members().collect::<Vec<_>>()
33+
};
34+
let mut benches: Vec<BenchToRun> = vec![];
35+
for p in packages_to_run {
36+
let package_name = p.manifest().name().to_string();
37+
let is_root_package = p.root() == ws.root();
38+
let package_target_dir = if is_root_package {
39+
codspeed_target_dir.clone()
40+
} else {
41+
codspeed_target_dir.join(&package_name)
42+
};
43+
let working_directory = p.root().to_path_buf();
44+
if let io::Result::Ok(read_dir) = std::fs::read_dir(&package_target_dir) {
45+
for entry in read_dir {
46+
let entry = entry?;
47+
let bench_path = entry.path();
48+
let bench_name = bench_path
49+
.file_name()
50+
.unwrap()
51+
.to_str()
52+
.unwrap()
53+
.to_string();
54+
if !bench_path.is_dir() {
55+
benches.push(BenchToRun {
56+
package_name: package_name.clone(),
57+
bench_path,
58+
bench_name,
59+
working_directory: working_directory.clone(),
60+
});
61+
}
62+
}
63+
}
64+
}
65+
66+
if benches.is_empty() {
67+
if let Some(package) = package.as_ref() {
68+
bail!(
2069
"No benchmarks found. Run `cargo codspeed build -p {}` first.",
2170
package
22-
));
71+
);
72+
} else {
73+
bail!("No benchmarks found. Run `cargo codspeed build` first.");
2374
}
2475
}
25-
if !codspeed_dir.exists() {
26-
return Err(anyhow!(
27-
"No benchmarks found. Run `cargo codspeed build` first."
28-
));
29-
}
30-
31-
let found_benches = read_dir_recursive(codspeed_dir)?;
3276

33-
if found_benches.is_empty() {
34-
return Err(anyhow!(
35-
"No benchmark target found. Run `cargo codspeed build` first."
36-
));
37-
}
3877
let mut to_run = vec![];
39-
if let Some(benches) = benches {
78+
if let Some(selected_bench_names) = selected_bench_names {
4079
// Make sure all benchmarks are found
4180
let mut not_found = vec![];
42-
for bench in benches.iter() {
43-
let bench_path = found_benches
44-
.iter()
45-
.find(|b| b.file_name().unwrap().to_str().unwrap() == bench);
81+
for bench_name in selected_bench_names.iter() {
82+
let bench = benches.iter().find(|b| &b.bench_name == bench_name);
4683

47-
if let Some(bench_path) = bench_path {
48-
to_run.push(bench_path.clone());
84+
if let Some(bench) = bench {
85+
to_run.push(bench);
4986
} else {
50-
not_found.push(bench);
87+
not_found.push(bench_name);
5188
}
5289
}
5390

5491
if !not_found.is_empty() {
55-
return Err(anyhow!(
92+
bail!(
5693
"The following benchmarks to run were not found: {}",
5794
not_found.iter().join(", ")
58-
));
95+
);
5996
}
6097
} else {
61-
to_run = found_benches;
98+
to_run = benches.iter().collect();
6299
}
63100
ws.config().shell().status_with_color(
64101
"Collected",
65102
format!("{} benchmark suite(s) to run", to_run.len()),
66103
Color::White,
67104
)?;
68105
for bench in to_run.iter() {
69-
let bench_name = bench.file_name().unwrap().to_str().unwrap();
106+
let bench_name = &bench.bench_name;
70107
// workspace_root is needed since file! returns the path relatively to the workspace root
71108
// while CARGO_MANIFEST_DIR returns the path to the sub package
72109
let workspace_root = ws.root().to_string_lossy();
73-
ws.config()
74-
.shell()
75-
.status_with_color("Running", bench_name, Color::Yellow)?;
76-
std::process::Command::new(bench)
110+
ws.config().shell().status_with_color(
111+
"Running",
112+
format!("{} {}", &bench.package_name, bench_name),
113+
Color::Yellow,
114+
)?;
115+
std::process::Command::new(&bench.bench_path)
77116
.env("CODSPEED_CARGO_WORKSPACE_ROOT", workspace_root.as_ref())
117+
.current_dir(&bench.working_directory)
78118
.status()
79119
.map_err(|_| anyhow!("failed to execute the benchmark process"))
80120
.and_then(|status| {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Cargo.lock
2+
target/
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[workspace]
2+
members = ["the_crate"]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "the_crate"
3+
version = "0.0.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
bencher = "0.1.5"
9+
codspeed = { path = "../../../../codspeed" }
10+
codspeed-bencher-compat = { path = "../../../../bencher_compat" }
11+
12+
[[bench]]
13+
name = "bencher_example"
14+
harness = false
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use std::hint::black_box;
2+
3+
use codspeed_bencher_compat::{benchmark_group, benchmark_main, Bencher};
4+
5+
pub fn a(bench: &mut Bencher) {
6+
// Open ./input.txt file
7+
std::fs::read_to_string("./input.txt").expect("Failed to read file");
8+
bench.iter(|| (0..100).fold(0, |x, y| black_box(x + y)))
9+
}
10+
11+
benchmark_group!(benches, a);
12+
benchmark_main!(benches);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello world!
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use predicates::str::contains;
2+
3+
mod helpers;
4+
use helpers::*;
5+
6+
const DIR: &str = "tests/crates_working_directory.in";
7+
8+
#[test]
9+
fn test_crates_working_directory_build_and_run_explicit() {
10+
let dir = setup(DIR, Project::CratesWorkingDirectory);
11+
cargo_codspeed(&dir)
12+
.args(["build", "-p", "the_crate"])
13+
.assert()
14+
.success();
15+
cargo_codspeed(&dir)
16+
.args(["run", "-p", "the_crate"])
17+
.assert()
18+
.success()
19+
.stderr(contains("Finished running 1 benchmark suite(s)"));
20+
teardown(dir);
21+
}
22+
23+
#[test]
24+
fn test_crates_working_directory_build_and_run_implicit() {
25+
let dir = setup(DIR, Project::CratesWorkingDirectory);
26+
cargo_codspeed(&dir)
27+
.args(["build", "-p", "the_crate"])
28+
.assert()
29+
.success();
30+
cargo_codspeed(&dir)
31+
.arg("run")
32+
.assert()
33+
.success()
34+
.stderr(contains("Finished running 1 benchmark suite(s)"));
35+
teardown(dir);
36+
}

crates/cargo-codspeed/tests/helpers.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub enum Project {
2121
Features,
2222
Workspace,
2323
PackageInDeps,
24+
CratesWorkingDirectory,
2425
}
2526

2627
pub fn setup(dir: &str, project: Project) -> String {
@@ -63,6 +64,17 @@ pub fn setup(dir: &str, project: Project) -> String {
6364
workspace_root.join("crates").to_str().unwrap(),
6465
);
6566
}
67+
Project::CratesWorkingDirectory => {
68+
replace_in_file(
69+
tmp_dir
70+
.join("the_crate")
71+
.join("Cargo.toml")
72+
.to_str()
73+
.unwrap(),
74+
"../../../..",
75+
workspace_root.join("crates").to_str().unwrap(),
76+
);
77+
}
6678
}
6779
tmp_dir.to_str().unwrap().to_string()
6880
}

crates/cargo-codspeed/tests/simple.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn test_simple_build() {
3030
#[test]
3131
fn test_simple_build_and_run() {
3232
let dir = setup(DIR, Project::Simple);
33-
cargo_codspeed(&dir).arg("build").assert();
33+
cargo_codspeed(&dir).arg("build").assert().success();
3434
cargo_codspeed(&dir)
3535
.arg("run")
3636
.assert()
@@ -58,7 +58,8 @@ fn test_simple_build_and_run_single() {
5858
cargo_codspeed(&dir)
5959
.arg("build")
6060
.arg("another_bencher_example")
61-
.assert();
61+
.assert()
62+
.success();
6263
cargo_codspeed(&dir)
6364
.arg("run")
6465
.arg("another_bencher_example")

0 commit comments

Comments
 (0)