-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Expand file tree
/
Copy pathbuild.rs
More file actions
69 lines (62 loc) · 3.11 KB
/
Copy pathbuild.rs
File metadata and controls
69 lines (62 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Build script for the `openhuman` core crate.
//!
//! Its sole job today is to generate the module list for the aggregated
//! `raw_coverage_all` integration test target. The `tests/raw_coverage/`
//! directory holds ~76 auto-generated `*_raw_coverage_e2e.rs` coverage suites
//! that were previously ~76 separate `tests/*.rs` integration targets. Each
//! separate target statically relinks the entire (very large) `openhuman`
//! rlib, so building the test suite paid ~76 full-crate link steps. Folding
//! them into a single target ([`tests/raw_coverage_all.rs`]) reduces that to
//! one link.
//!
//! We glob the directory at build time (rather than hand-maintaining a `mod`
//! list) so that any newly added `tests/raw_coverage/*.rs` file is picked up
//! automatically and cannot be silently skipped.
use std::env;
use std::fs;
use std::path::Path;
fn main() {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
let tests_dir = Path::new(&manifest_dir).join("tests");
let raw_dir = tests_dir.join("raw_coverage");
// Re-run whenever a file is added to / removed from the directory.
println!("cargo:rerun-if-changed={}", raw_dir.display());
let mut entries: Vec<(String, String)> = Vec::new();
let read_dir = match fs::read_dir(&raw_dir) {
Ok(rd) => Some(rd),
// Source-only builds (e.g. the Docker image copies `src/` but not
// `tests/`) never compile the integration targets, so there is nothing
// to aggregate — emit an empty module list rather than breaking the
// build. But if `tests/` IS present and only `raw_coverage/` is missing,
// that's an accidental deletion: fail loudly so the suite can't be
// silently dropped.
Err(_) if !tests_dir.exists() => None,
Err(e) => panic!("failed to read {}: {e}", raw_dir.display()),
};
for entry in read_dir.into_iter().flatten().flatten() {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("rs") {
continue;
}
let stem = match path.file_stem().and_then(|s| s.to_str()) {
Some(s) => s.to_string(),
None => continue,
};
// Re-run if any individual test file's contents change.
println!("cargo:rerun-if-changed={}", path.display());
// Rust `#[path]` accepts forward slashes on every platform; the
// absolute path keeps resolution independent of where the generated
// file is `include!`d from.
let abs = path.display().to_string().replace('\\', "/");
entries.push((stem, abs));
}
// Deterministic order keeps the generated file stable across builds.
entries.sort();
let mut generated = String::from("// @generated by build.rs — do not edit.\n");
for (stem, abs) in &entries {
generated.push_str(&format!("#[path = \"{abs}\"]\nmod {stem};\n"));
}
let out_dir = env::var("OUT_DIR").expect("OUT_DIR must be set");
let out_path = Path::new(&out_dir).join("raw_coverage_mods.rs");
fs::write(&out_path, generated).expect("failed to write raw_coverage_mods.rs");
}