use crate::GitRepository; use crate::pack::impls::PackOps; use crate::pack::types::{HotPackResult, IndexResult, IngestPackResult, PackStats, RepackResult}; fn count_loose_objects(repo: &gix::Repository) -> u64 { let mut count = 0u64; let dir = repo.path().join("objects"); let Ok(read) = std::fs::read_dir(dir) else { return 0; }; for shelf in read.flatten() { let Ok(entries) = std::fs::read_dir(shelf.path()) else { continue; }; for entry in entries.flatten() { if entry.path().is_file() { count += 1; } } } count } impl PackOps for GitRepository { fn pack_ingest_pack(&self, data: &[u8]) -> Result { let repo = self.repo()?; let path = repo.path().to_path_buf(); let out = duct::cmd("git", &["index-pack", "--stdin"]) .env("GIT_DIR", &path) .env("GIT_TERMINAL_PROMPT", "0") .stdin_bytes(data) .read() .map_err(|e| crate::Error::Other(format!("git index-pack failed: {e}")))?; let object_count = out.lines().count() as u64; tracing::info!( object_count, size = data.len(), "pack ingested via git index-pack" ); Ok(IngestPackResult { object_count, size: data.len() as i64, delta_count: 0, }) } fn pack_index(&self, pack_id: &str) -> Result { let repo = self.repo()?; let path = repo.path().to_path_buf(); let pack_dir = path.join("objects/pack"); let pack_file = pack_dir.join(format!("{pack_id}.pack")); if !pack_file.exists() { return Err(crate::Error::NotExist(format!("pack {pack_id}"))); } let pack_file = pack_file.to_string_lossy().to_string(); let out = crate::gitcli::run(&path, &["index-pack", &pack_file])?; let object_count = out.lines().count() as u64; tracing::info!(pack_id, object_count, "pack indexed"); Ok(IndexResult { pack_id: pack_id.into(), object_count, }) } fn pack_repack(&self) -> Result { let repo = self.repo()?; let path = repo.path().to_path_buf(); crate::gitcli::run(&path, &["repack", "-a", "-d", "-q"])?; tracing::info!("repack completed via git repack"); Ok(RepackResult { packs: vec![], pruned: 0, }) } fn pack_stats(&self) -> Result { let tip = self.tip_id()?; if let Some(hit) = self.cache_get_rev::("pack", "stats", "stats", tip) { return Ok(hit); } let repo = self.repo()?; let loose = count_loose_objects(&repo); let v = PackStats { objects: loose, size: 0, delta_count: 0, }; self.cache_put_rev("pack", "stats", "stats", tip, &v); Ok(v) } fn pack_cache_hot_pack(&self, pack_id: &str) -> Result { let repo = self.repo()?; let path = repo.path().to_path_buf(); crate::gitcli::run(&path, &["repack", "-a", "-d", "-q"])?; tracing::info!(pack_id, "hot pack cache performed via repack"); Ok(HotPackResult { cached: true, pack_id: pack_id.into(), }) } }