use std::{ fs::FileType, path::{Path, PathBuf}, }; use anyhow::Result; use xshell::rm_rf; pub(crate) struct PreCacheCmd; impl PreCacheCmd { /// Cleans the `./target` dir after the build such that only /// dependencies are cached on CI. pub(crate) fn run(self) -> Result<()> { let slow_tests_cookie = Path::new("./target/.slow_tests_cookie"); if !slow_tests_cookie.exists() { panic!("slow tests were skipped on CI!") } rm_rf(slow_tests_cookie)?; for path in read_dir("./target/debug", FileType::is_file)? { // Can't delete yourself on windows :-( if !path.ends_with("xtask.exe") { rm_rf(&path)? } } rm_rf("./target/.rustc_info.json")?; let to_delete = read_dir("./crates", FileType::is_dir)? .into_iter() .map(|path| path.file_name().unwrap().to_string_lossy().replace('-', "_")) .collect::>(); for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() { for path in read_dir(dir, |_file_type| true)? { if path.ends_with("xtask.exe") { continue; } let file_name = path.file_name().unwrap().to_string_lossy(); let (stem, _) = match rsplit_once(&file_name, '-') { Some(it) => it, None => { rm_rf(path)?; continue; } }; let stem = stem.replace('-', "_"); if to_delete.contains(&stem) { rm_rf(path)?; } } } Ok(()) } } fn read_dir(path: impl AsRef, cond: impl Fn(&FileType) -> bool) -> Result> { read_dir_impl(path.as_ref(), &cond) } fn read_dir_impl(path: &Path, cond: &dyn Fn(&FileType) -> bool) -> Result> { let mut res = Vec::new(); for entry in path.read_dir()? { let entry = entry?; let file_type = entry.file_type()?; if cond(&file_type) { res.push(entry.path()) } } Ok(res) } fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> { let mut split = haystack.rsplitn(2, delim); let suffix = split.next()?; let prefix = split.next()?; Some((prefix, suffix)) }