use crate::utils::paths::{artifacts_dir, test_output_dir, test_target_dir};
use std::fs;
use std::io;
#[cfg(unix)]
use std::os::unix::fs as unix_fs; #[cfg(windows)]
use std::os::windows::fs as windows_fs; use std::path::{Path, PathBuf};
use walkdir::WalkDir;
fn with_path_context<P: AsRef<Path>>(err: io::Error, path: P) -> io::Error {
io::Error::new(
err.kind(),
format!(
"Error processing path '{}': {}",
path.as_ref().display(),
err
),
)
}
#[cfg(unix)]
fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
{
let o = original.as_ref();
let l = link.as_ref();
println!("Symlinking {} → {}", o.display(), l.display());
}
unix_fs::symlink(original, link)
}
#[cfg(windows)]
fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
{
let o = original.as_ref();
let l = link.as_ref();
println!("Symlinking {} → {}", o.display(), l.display());
}
if original.as_ref().is_dir() {
windows_fs::symlink_dir(original, link)
} else {
windows_fs::symlink_file(original, link)
}
}
pub fn prepare_target_dirs(
master_target_dir: &Path,
test_names: &[String],
output_dir: &Path,
) -> io::Result<Vec<PathBuf>> {
let mut test_target_dirs = Vec::new();
fs::create_dir_all(artifacts_dir(output_dir))?;
for test_name in test_names {
println!("Preparing target directory for test: {}", test_name);
let test_output_dir = test_output_dir(output_dir, test_name);
fs::create_dir_all(&test_output_dir).map_err(|e| with_path_context(e, &test_output_dir))?;
let test_target_dir = test_target_dir(output_dir, test_name);
fs::create_dir_all(&test_target_dir).map_err(|e| with_path_context(e, &test_target_dir))?;
let debug_dir = test_target_dir.join("debug");
fs::create_dir_all(&debug_dir)?;
let cargo_lock_file = debug_dir.join(".cargo-lock");
if !cargo_lock_file.exists() {
fs::write(&cargo_lock_file, "").map_err(|e| with_path_context(e, &cargo_lock_file))?;
}
let write_dirs = vec![
"debug/.fingerprint",
"debug/deps",
"debug/build",
"debug/incremental",
];
for dir_path in &write_dirs {
let dest_dir = test_target_dir.join(dir_path);
fs::create_dir_all(&dest_dir).map_err(|e| with_path_context(e, &dest_dir))?;
if *dir_path == "debug/deps" {
let source_dir = master_target_dir.join(dir_path);
if source_dir.exists() {
for entry in WalkDir::new(&source_dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
{
let rel_path = entry
.path()
.strip_prefix(&source_dir)
.expect("Failed to strip prefix");
let dest_file = dest_dir.join(rel_path);
if !dest_file.exists() {
fs::copy(entry.path(), &dest_file).map_err(|e| {
with_path_context(
e,
format!(
"Failed to copy from '{}' to '{}'",
entry.path().display(),
dest_file.display()
),
)
})?;
}
}
}
}
}
let symlink_dirs = vec!["debug/examples", "debug/build/src"];
for dir_path in &symlink_dirs {
let source_dir = master_target_dir.join(dir_path);
if !source_dir.exists() {
continue;
}
let dest_dir = test_target_dir.join(dir_path);
fs::create_dir_all(&dest_dir).map_err(|e| with_path_context(e, &dest_dir))?;
for entry in WalkDir::new(&source_dir)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
{
let rel_path = entry
.path()
.strip_prefix(&source_dir)
.expect("Failed to strip prefix");
let dest_file = dest_dir.join(rel_path);
if let Some(parent) = dest_file.parent() {
if !parent.exists() {
fs::create_dir_all(parent).map_err(|e| with_path_context(e, parent))?;
}
}
if !dest_file.exists() {
create_symlink(entry.path(), &dest_file).map_err(|e| {
with_path_context(
e,
format!(
"Failed to symlink from '{}' to '{}'",
entry.path().display(),
dest_file.display()
),
)
})?;
}
}
}
test_target_dirs.push(test_target_dir);
}
Ok(test_target_dirs)
}