use crate::adapter::rust::manifest::CargoToml;
use crate::core::reflink::reflink_or_copy_dir_recursive;
use std::fs;
use std::path::Path;
use super::build_script_directives::{compute_execution_key, BuildScriptDirectives};
pub fn remap_out_dir(directives: &mut BuildScriptDirectives, from: &str, to: &str) {
for s in &mut directives.link_searches {
if s == from {
*s = to.to_string();
}
}
for val in directives.envs.values_mut() {
if val.contains(from) {
*val = val.replace(from, to);
}
}
}
pub fn try_restore_build_script_cas(
cas_artifacts_dir: Option<&Path>,
build_key: &str,
pkg_dir: &Path,
pkg_toml: &CargoToml,
profile_name: &str,
clean_crate: &str,
out_dir: &Path,
) -> Option<BuildScriptDirectives> {
let artifacts_dir = cas_artifacts_dir?;
let cas_root = artifacts_dir.parent().unwrap_or(artifacts_dir);
let script_cas_dir = cas_root.join("build_scripts").join(build_key);
if !script_cas_dir.is_dir() {
return None;
}
let entries = fs::read_dir(&script_cas_dir).ok()?;
for entry in entries.flatten() {
let entry_dir = entry.path();
let file_name = entry_dir.file_name().and_then(|n| n.to_str()).unwrap_or("");
if file_name.starts_with('.') || !entry_dir.is_dir() {
continue;
}
let meta_file = entry_dir.join("meta.toml");
let mut cached_out_dir = entry_dir
.join(profile_name)
.join("build")
.join(clean_crate)
.join("out");
if !cached_out_dir.is_dir() {
cached_out_dir = entry_dir.join("out");
}
if !meta_file.is_file() {
continue;
}
if let Ok(content) = fs::read_to_string(&meta_file) {
if let Ok(mut directives) = toml::from_str::<BuildScriptDirectives>(&content) {
if directives.is_fresh(pkg_dir) {
let mut restore_ok = true;
if cached_out_dir.is_dir()
&& reflink_or_copy_dir_recursive(&cached_out_dir, out_dir).is_err()
{
restore_ok = false;
let _ = fs::remove_dir_all(out_dir);
let _ = fs::create_dir_all(out_dir);
}
if restore_ok {
let _ = fs::write(entry_dir.join(".last_used"), b"");
directives.out_dir = Some(out_dir.to_path_buf());
directives.links = pkg_toml.package.as_ref().and_then(|p| p.links.clone());
let cached_out_str = cached_out_dir.to_string_lossy();
let out_str = out_dir.to_string_lossy();
remap_out_dir(&mut directives, &cached_out_str, &out_str);
return Some(directives);
}
}
}
}
}
None
}
pub fn save_build_script_cas(
cas_artifacts_dir: Option<&Path>,
build_key: &str,
directives: &mut BuildScriptDirectives,
profile_name: &str,
clean_crate: &str,
out_dir: &Path,
) {
let artifacts_dir = match cas_artifacts_dir {
Some(d) => d,
None => return,
};
let cas_root = artifacts_dir.parent().unwrap_or(artifacts_dir);
let script_cas_dir = cas_root.join("build_scripts").join(build_key);
let exec_key = compute_execution_key(
build_key,
&directives.rerun_if_changed_hashes,
&directives.envs,
);
let entry_dir = script_cas_dir.join(&exec_key);
let cas_out = entry_dir
.join(profile_name)
.join("build")
.join(clean_crate)
.join("out");
let out_str = out_dir.to_string_lossy();
let cas_out_str = cas_out.to_string_lossy();
if !entry_dir.exists() {
let _ = fs::create_dir_all(&script_cas_dir);
let pid = std::process::id();
let tmp_entry_dir = script_cas_dir.join(format!(".tmp.{}.{}", exec_key, pid));
let _ = fs::remove_dir_all(&tmp_entry_dir);
if fs::create_dir_all(&tmp_entry_dir).is_ok() {
let mut ok = true;
if out_dir.is_dir() {
let tmp_out = tmp_entry_dir
.join(profile_name)
.join("build")
.join(clean_crate)
.join("out");
if let Some(p) = tmp_out.parent() {
let _ = fs::create_dir_all(p);
}
if reflink_or_copy_dir_recursive(out_dir, &tmp_out).is_err() {
ok = false;
}
}
if ok {
let _ = fs::write(tmp_entry_dir.join(".last_used"), b"");
let mut cas_d = directives.clone();
cas_d.out_dir = Some(cas_out.clone());
remap_out_dir(&mut cas_d, &out_str, &cas_out_str);
if let Ok(toml_str) = toml::to_string(&cas_d) {
if fs::write(tmp_entry_dir.join("meta.toml"), toml_str).is_ok() {
if fs::rename(&tmp_entry_dir, &entry_dir).is_err() {
let _ = fs::remove_dir_all(&tmp_entry_dir);
}
} else {
let _ = fs::remove_dir_all(&tmp_entry_dir);
}
} else {
let _ = fs::remove_dir_all(&tmp_entry_dir);
}
} else {
let _ = fs::remove_dir_all(&tmp_entry_dir);
}
}
}
if cas_out.is_dir() {
directives.out_dir = Some(cas_out.clone());
remap_out_dir(directives, &out_str, &cas_out_str);
}
}