//! lfs usecase: LFS batch handling (storage layer is delegated to lib/storage). use std::collections::HashMap; use crate::GitRepository; use crate::lfs::impls::LfsOps; use crate::lfs::types::{ LfsBatchRequest, LfsBatchResponse, LfsLock, LfsLockList, LfsObject, LfsUploadResult, }; use crate::validate; impl LfsOps for GitRepository { fn lfs_handle_batch(&self, req: &LfsBatchRequest) -> Result { let _ = self.repo()?; let transfer = req .transfers .first() .cloned() .unwrap_or_else(|| "basic".to_string()); let action_key = match req.operation { crate::lfs::types::LfsOperation::Upload => "upload", crate::lfs::types::LfsOperation::Download => "download", crate::lfs::types::LfsOperation::Verify => "verify", }; let objects = req .objects .iter() .map(|o| { validate::validate_oid(&o.oid, 64)?; let mut actions = HashMap::new(); actions.insert( action_key.into(), crate::lfs::types::LfsAction { href: format!("/api/lfs/{}/{}", action_key, o.oid), header: None, expires_at: None, }, ); Ok(crate::lfs::types::LfsBatchObject { oid: o.oid.clone(), size: o.size, actions: Some(actions), error: None, }) }) .collect::, crate::Error>>()?; Ok(LfsBatchResponse { transfer, objects }) } fn lfs_upload(&self, obj: &LfsObject) -> Result { validate::validate_oid(&obj.oid, 64)?; let repo = self.repo()?; let present = repo .try_find_object( gix::hash::ObjectId::from_hex(obj.oid.as_bytes()) .map_err(|e| crate::Error::InvalidRevSpec(e.to_string()))?, ) .map_err(|e| crate::Error::Find(e.to_string()))? .is_some(); Ok(LfsUploadResult { present, oid: obj.oid.clone(), }) } fn lfs_download(&self, obj: &LfsObject) -> Result { validate::validate_oid(&obj.oid, 64)?; let _ = self.repo()?; Ok(format!("/api/lfs/download/{}", obj.oid)) } fn lfs_verify(&self, obj: &LfsObject) -> Result<(), crate::Error> { validate::validate_oid(&obj.oid, 64)?; let repo = self.repo()?; let id = gix::hash::ObjectId::from_hex(obj.oid.as_bytes()) .map_err(|e| crate::Error::InvalidRevSpec(e.to_string()))?; if repo .try_find_object(id) .map_err(|e| crate::Error::Find(e.to_string()))? .is_none() { return Err(crate::Error::NotExist(obj.oid.clone())); } Ok(()) } fn lfs_lock(&self, path: &str, owner: &str) -> Result { let _ = self.repo()?; Ok(LfsLock { path: path.into(), owner: Some(owner.into()), oid: None, }) } fn lfs_unlock(&self, path: &str, owner: &str) -> Result { let _ = self.repo()?; Ok(LfsLock { path: path.into(), owner: Some(owner.into()), oid: None, }) } fn lfs_list_locks( &self, _cursor: Option<&str>, _limit: u64, ) -> Result { let _ = self.repo()?; Ok(LfsLockList { locks: Vec::new(), next_cursor: None, }) } fn lfs_cleanup_unreferenced(&self) -> Result { let _ = self.repo()?; Ok(0) } }