//! submodule usecase: list submodules from a tree. use gix::hash::ObjectId; use gix::objs::tree::EntryRef; use crate::GitRepository; use crate::submodule::impls::SubmoduleOps; use crate::submodule::types::{LinkUrl, Submodule, SubmoduleList}; fn entries<'a>(tree: &'a gix::Tree) -> Result>, crate::Error> { let decoded = tree .decode() .map_err(|e| crate::Error::Find(e.to_string()))?; Ok(decoded.entries.to_owned()) } impl SubmoduleOps for GitRepository { fn submodule_list(&self, tree_id: &ObjectId) -> Result { let tip = self.tip_id()?; if let Some(hit) = self.cache_get_rev::("submodule", "list", &tree_id.to_string(), tip) { return Ok(hit); } let repo = self.repo()?; let tree = repo .find_tree(*tree_id) .map_err(|e| crate::Error::Find(e.to_string()))?; let entries = entries(&tree)?; let mut submodules = Vec::new(); for entry in &entries { if entry.mode.is_commit() { let path = entry.filename.to_string(); let commit_sha = entry.oid.to_owned(); submodules.push(Submodule { path, url: String::new(), branch: None, commit_sha, }); } } let v = SubmoduleList { submodules }; self.cache_put_rev("submodule", "list", &tree_id.to_string(), tip, &v); Ok(v) } fn submodule_link_url(&self, path: &str, tree_id: &ObjectId) -> Result { let tip = self.tip_id()?; let key = format!("{tree_id}.{path}"); if let Some(hit) = self.cache_get_rev::("submodule", "link", &key, tip) { return Ok(hit); } let repo = self.repo()?; let tree = repo .find_tree(*tree_id) .map_err(|e| crate::Error::Find(e.to_string()))?; let entries = entries(&tree)?; let entry = entries .iter() .find(|e| e.filename == path) .ok_or_else(|| crate::Error::NotFound { name: path.to_string(), })?; let v = LinkUrl { path: path.into(), full_url: String::new(), commit_sha: entry.oid.to_owned(), }; self.cache_put_rev("submodule", "link", &key, tip, &v); Ok(v) } fn submodule_resolve(&self, path: &str, tree_id: &ObjectId) -> Result { let tip = self.tip_id()?; let key = format!("{tree_id}.{path}"); if let Some(hit) = self.cache_get_rev::("submodule", "resolve", &key, tip) { return Ok(hit); } let repo = self.repo()?; let tree = repo .find_tree(*tree_id) .map_err(|e| crate::Error::Find(e.to_string()))?; let entries = entries(&tree)?; let entry = entries .iter() .find(|e| e.filename == path) .ok_or_else(|| crate::Error::NotFound { name: path.to_string(), })?; let v = entry.oid.to_owned(); self.cache_put_rev("submodule", "resolve", &key, tip, &v); Ok(v) } }