use crate::GitError; use crate::hook::sync::HookMetaDataSync; use db::database::AppTransaction; use models::repos::repo_lfs_object; use sea_orm::*; use std::collections::HashSet; impl HookMetaDataSync { pub async fn sync_lfs_objects(&self, txn: &AppTransaction) -> Result<(), GitError> { let repo_id = self.repo.id; let existing: Vec = repo_lfs_object::Entity::find() .filter(repo_lfs_object::Column::Repo.eq(repo_id)) .all(txn) .await .map_err(|e| GitError::IoError(format!("failed to query lfs objects: {}", e)))?; let mut existing_oids: HashSet = existing.into_iter().map(|o| o.oid).collect(); let local_oids = self.domain.lfs_object_list()?; let now = chrono::Utc::now(); let mut new_objects = Vec::new(); for oid in local_oids { let oid_str = oid.as_str().to_string(); if existing_oids.contains(&oid_str) { existing_oids.remove(&oid_str); continue; } let path = match self.domain.lfs_object_path(&oid) { Ok(p) => p, Err(e) => { slog::warn!( self.logger, "invalid LFS OID in local objects directory: {}", e ); continue; } }; let size = if let Ok(meta) = std::fs::metadata(&path) { meta.len() as i64 } else { continue; }; let storage_path = path.to_string_lossy().to_string(); new_objects.push(repo_lfs_object::ActiveModel { repo: Set(repo_id), oid: Set(oid_str), size: Set(size), storage_path: Set(storage_path), uploaded_by: Set(None), uploaded_at: Set(now), ..Default::default() }); } if !new_objects.is_empty() { // Insert in batches for chunk in new_objects.chunks(100) { repo_lfs_object::Entity::insert_many(chunk.to_vec()) .exec(txn) .await .map_err(|e| { GitError::IoError(format!("failed to insert lfs objects: {}", e)) })?; } } // Remove objects that no longer exist on disk if !existing_oids.is_empty() { repo_lfs_object::Entity::delete_many() .filter(repo_lfs_object::Column::Repo.eq(repo_id)) .filter(repo_lfs_object::Column::Oid.is_in(existing_oids)) .exec(txn) .await .map_err(|e| { GitError::IoError(format!("failed to delete stale lfs objects: {}", e)) })?; } Ok(()) } }