use std::path::{Path, PathBuf};
use stow_types::rustc::ParsedExternCrate;
use crate::cache_policy;
const LOCAL_BUILD_DIR: &str = "local-build";
pub async fn record_local_build(target: &str, crate_name: &str) -> stow_types::error::Result<()> {
let Some(dir) = local_build_dir(target) else {
return Ok(());
};
async_fs::create_dir_all(&dir)
.await
.map_err(|error| stow_types::stow_error!("create {}: {error}", dir.display()))?;
let marker = dir.join(marker_name(crate_name));
async_fs::write(&marker, [])
.await
.map_err(|error| stow_types::stow_error!("write {}: {error}", marker.display()))
}
pub fn locally_built_dependency(
target: &str,
extern_crates: &[ParsedExternCrate],
) -> Option<String> {
if extern_crates.is_empty() {
return None;
}
let dir = local_build_dir(target)?;
locally_built_dependency_in(&dir, extern_crates)
}
fn locally_built_dependency_in(dir: &Path, extern_crates: &[ParsedExternCrate]) -> Option<String> {
extern_crates
.iter()
.map(|dependency| dependency.crate_name.as_str())
.find(|crate_name| dir.join(marker_name(crate_name)).exists())
.map(ToOwned::to_owned)
}
fn local_build_dir(target: &str) -> Option<PathBuf> {
let policy_dir = cache_policy::policy_dir()?;
Some(marker_dir(&policy_dir, target))
}
fn marker_dir(policy_dir: &Path, target: &str) -> PathBuf {
policy_dir.join(LOCAL_BUILD_DIR).join(target)
}
fn marker_name(crate_name: &str) -> String {
crate_name.replace('-', "_")
}
#[cfg(test)]
mod tests {
use stow_types::rustc::ParsedExternCrate;
use super::{locally_built_dependency_in, marker_dir, marker_name};
fn build_with_local(crates: &[&str]) -> (tempfile::TempDir, std::path::PathBuf) {
let temp = tempfile::tempdir().expect("temp dir");
let dir = marker_dir(temp.path(), "aarch64-apple-darwin");
std::fs::create_dir_all(&dir).expect("create marker dir");
for name in crates {
std::fs::write(dir.join(marker_name(name)), []).expect("write marker");
}
(temp, dir)
}
fn externs(names: &[&str]) -> Vec<ParsedExternCrate> {
names
.iter()
.map(|name| ParsedExternCrate {
crate_name: (*name).to_owned(),
path: std::path::PathBuf::from(format!("deps/lib{name}-0123456789abcdef.rmeta")),
})
.collect()
}
#[test]
fn hyphens_and_underscores_name_the_same_marker() {
let (_temp, dir) = build_with_local(&["unicode-ident"]);
assert_eq!(
locally_built_dependency_in(&dir, &externs(&["unicode_ident"])),
Some("unicode_ident".to_owned())
);
}
#[test]
fn untouched_dependencies_leave_the_cache_usable() {
let (_temp, dir) = build_with_local(&["memchr"]);
assert_eq!(
locally_built_dependency_in(&dir, &externs(&["unicode_ident", "serde"])),
None
);
}
#[test]
fn one_local_dependency_rules_out_the_cache() {
let (_temp, dir) = build_with_local(&["unicode_ident"]);
assert_eq!(
locally_built_dependency_in(&dir, &externs(&["serde", "unicode_ident"])),
Some("unicode_ident".to_owned())
);
}
#[test]
fn a_leaf_invocation_is_always_usable() {
let (_temp, dir) = build_with_local(&["unicode_ident"]);
assert_eq!(locally_built_dependency_in(&dir, &externs(&[])), None);
}
}