use std::fs;
fn run_candidate_target_dirs(
src: &str,
dir: &std::path::Path,
cargo_target_dir: Option<&str>,
out_dir: &std::path::Path,
) -> Vec<std::path::PathBuf> {
let src = src.replace("\r\n", "\n");
let start = src
.find("fn candidate_target_dirs()")
.expect("candidate_target_dirs present");
let body = &src[start..];
let end = body.find("\n}\n").expect("function end") + 3;
let program = format!(
"{}\nfn main() {{ for c in candidate_target_dirs() {{ println!(\"{{}}\", c.display()); }} }}\n",
&body[..end]
);
let main_rs = dir.join("main.rs");
fs::write(&main_rs, program).unwrap();
let exe = dir.join(if cfg!(windows) { "probe.exe" } else { "probe" });
let status =
std::process::Command::new(std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()))
.args(["--edition", "2021", "-o"])
.arg(&exe)
.arg(&main_rs)
.status()
.expect("rustc runs");
assert!(status.success(), "probe failed to compile");
let mut cmd = std::process::Command::new(&exe);
cmd.env_remove("CARGO_TARGET_DIR").env("OUT_DIR", out_dir);
if let Some(v) = cargo_target_dir {
cmd.env("CARGO_TARGET_DIR", v);
}
let out = cmd.output().expect("probe runs");
assert!(
out.status.success(),
"probe failed: {}",
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8(out.stdout)
.unwrap()
.lines()
.map(std::path::PathBuf::from)
.collect()
}
#[test]
fn build_scripts_skip_relative_cargo_target_dir() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let mut files = vec![root.join("src/templates/build.rs.tmpl")];
for name in [
"blog",
"bookmarks",
"bookmarks-distributed",
"cms",
"reddit-clone",
"saas",
"teams",
"todo-app",
"wiki",
] {
files.push(root.join("../examples").join(name).join("build.rs"));
}
files.push(root.join("src/starters/cms/build.rs"));
files.push(root.join("src/starters/saas/build.rs"));
let tmp = tempfile::tempdir().unwrap();
let ws = tmp.path().join("ws");
let out_dir = ws.join("target/debug/build/pkg-1/out");
let abs_target = tmp.path().join("abs").join("target");
let expected = [ws.join("target"), ws.clone()];
let mut seen = std::collections::HashSet::new();
for file in files {
let src =
fs::read_to_string(&file).unwrap_or_else(|e| panic!("reading {}: {e}", file.display()));
let src = src.replace("\r\n", "\n");
let start = src.find("fn candidate_target_dirs()").unwrap();
if !seen.insert(src[start..].split("\n}\n").next().unwrap().to_owned()) {
continue;
}
let name = file.display();
let rel = run_candidate_target_dirs(&src, tmp.path(), Some("target"), &out_dir);
assert_eq!(rel, expected, "{name}: relative value kept");
let none = run_candidate_target_dirs(&src, tmp.path(), None, &out_dir);
assert_eq!(none, expected, "{name}: unset differs");
let abs = run_candidate_target_dirs(&src, tmp.path(), abs_target.to_str(), &out_dir);
assert_eq!(abs[0], abs_target, "{name}: absolute lost");
assert_eq!(abs[1..], expected, "{name}: OUT_DIR fallback lost");
}
}