atomcode_core/setup/
seeds.rs1use anyhow::{Context, Result};
6use std::path::{Path, PathBuf};
7
8const SEEDS_TARZST: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/setup-seeds.tar.zst"));
9
10pub fn ensure_seeds_extracted(cache_root: &Path) -> Result<PathBuf> {
16 use sha2::{Digest, Sha256};
18 let mut h = Sha256::new();
19 h.update(SEEDS_TARZST);
20 let content_hash = format!("{:x}", h.finalize());
21 let short_hash = &content_hash[..12]; let cache_dir = cache_root
24 .join("seeds-cache")
25 .join(format!("{}-{}", env!("CARGO_PKG_VERSION"), short_hash));
26 let sentinel = cache_dir.join(".extracted");
27 if sentinel.exists() {
28 return Ok(cache_dir);
29 }
30 std::fs::create_dir_all(&cache_dir)
31 .with_context(|| format!("create_dir_all({})", cache_dir.display()))?;
32
33 let decoder = zstd::Decoder::new(SEEDS_TARZST)
34 .context("zstd decoder for embedded seeds")?;
35 let mut archive = tar::Archive::new(decoder);
36 archive
37 .unpack(&cache_dir)
38 .with_context(|| format!("unpack to {}", cache_dir.display()))?;
39
40 #[cfg(target_os = "macos")]
41 remove_quarantine_recursive(&cache_dir);
42
43 std::fs::write(&sentinel, b"").context("write sentinel")?;
44 Ok(cache_dir)
45}
46
47#[cfg(target_os = "macos")]
50fn remove_quarantine_recursive(dir: &std::path::Path) {
51 use std::process::Command;
52 let _ = Command::new("xattr")
53 .args(["-rd", "com.apple.quarantine"])
54 .arg(dir)
55 .output();
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn first_call_extracts_and_creates_sentinel() {
64 let dir = tempfile::tempdir().unwrap();
65 let extracted = ensure_seeds_extracted(dir.path()).unwrap();
66 assert!(extracted.join(".extracted").exists());
67 assert!(
69 extracted.join("skills").join("README.md").exists()
70 || extracted.join("README.md").exists()
71 || extracted.read_dir().unwrap().count() > 0
72 );
73 }
74
75 #[test]
76 fn second_call_is_idempotent() {
77 let dir = tempfile::tempdir().unwrap();
78 let first = ensure_seeds_extracted(dir.path()).unwrap();
79 let second = ensure_seeds_extracted(dir.path()).unwrap();
80 assert_eq!(first, second);
81 }
82
83}