use std::collections::HashMap; use gitbaby::commit::types::TreeEntryMode; use serde::{Deserialize, Serialize}; use crate::service::GitService; use crate::service::cache::{self, IMMUTABLE_TTL}; use crate::share::errors::{GitError, map_baby}; #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct SubmoduleDto { pub path: String, pub url: String, pub branch: Option, pub commit_sha: Option, } impl GitService { pub async fn submodule_list( &self, space_name: String, repo_name: String, revision: String, ) -> Result, GitError> { let ctx = self.context(space_name, repo_name).await?; let baby = self.baby(&ctx); let rev_oid = baby.rev_parse(&revision).await.map_err(map_baby)?; let key = format!("repo.{}.submodules.{}", ctx.model.id, rev_oid); cache::cached_fetch(&ctx.cache, &key, IMMUTABLE_TTL, || async { let entries = baby .get_tree_entries(&revision, std::path::Path::new("")) .await .map_err(map_baby)?; let mut meta: HashMap = HashMap::new(); if let Ok(submodules) = baby.list_submodules(&revision).await { for s in submodules { meta.insert(s.path.clone(), (s.url.clone(), s.branch.clone())); } } let mut out = Vec::new(); for e in entries { if e.mode == TreeEntryMode::Submodule { let (url, branch) = meta.get(&e.name).cloned().unwrap_or_default(); out.push(SubmoduleDto { path: e.name.clone(), url, branch: Some(branch).filter(|b| !b.is_empty()), commit_sha: Some(e.oid.to_string()), }); } } Ok(out) }) .await } pub async fn submodule_resolve( &self, space_name: String, repo_name: String, revision: String, path: String, ) -> Result { let ctx = self.context(space_name, repo_name).await?; let baby = self.baby(&ctx); let rev_oid = baby.rev_parse(&revision).await.map_err(map_baby)?; let key = format!( "repo.{}.submodule_resolve.{}.{}", ctx.model.id, rev_oid, path ); cache::cached_fetch(&ctx.cache, &key, IMMUTABLE_TTL, || async { let entries = baby .get_tree_entries(&revision, std::path::Path::new("")) .await .map_err(map_baby)?; entries .into_iter() .find(|e| e.name == path && e.mode == TreeEntryMode::Submodule) .map(|e| e.oid.to_string()) .ok_or(GitError::NotFound) }) .await } }