use std::path::Path; use crate::GitBaby; use crate::error::BabyError; use crate::share; use crate::submodule::helper; use crate::submodule::types::SubModule; async fn read_blob_at_revision( gitbaby: &GitBaby, commit: &str, blob_path: &str, ) -> Result>, BabyError> { share::validate_revision(commit)?; share::validate_local_no_escape(Path::new(blob_path))?; let dir = gitbaby .facade .git_repo_dir() .await .map_err(share::facade_error)?; let alternates = gitbaby .facade .git_alternate_object_directories() .await .map_err(share::facade_error)?; let env = share::build_env_safe(&alternates); let args = vec![ "cat-file".to_string(), "blob".to_string(), "--end-of-options".to_string(), format!("{}:{}", commit, blob_path), ]; let mut cmd = share::git_cmd("gitbaby::submodule", &dir, env, None, args); match cmd.run().await { Ok(output) => { if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); if stderr.contains("not a tree") || stderr.contains("does not exist") || stderr.contains("bad revision") || stderr.contains("could not read") { return Ok(None); } return Err(BabyError::SubModuleParse { line: 0, reason: format!("cat-file blob failed: {}", stderr.trim()), }); } Ok(Some(output.stdout)) } Err(crate::command::error::CmdError::NonZeroExit { stderr, .. }) => { if stderr.contains("not a tree") || stderr.contains("does not exist") || stderr.contains("bad revision") || stderr.contains("could not read") { Ok(None) } else { Err(BabyError::SubModuleParse { line: 0, reason: format!("cat-file blob failed: {}", stderr.trim()), }) } } Err(e) => Err(BabyError::from(e)), } } impl GitBaby { pub async fn list_submodules(&self, commit: &str) -> Result, BabyError> { share::validate_revision_non_empty(commit)?; match read_blob_at_revision(self, commit, ".gitmodules").await? { Some(bytes) => helper::parse_blob_to_submodules(&bytes), None => Ok(Vec::new()), } } pub async fn get_submodule( &self, commit: &str, name: &str, ) -> Result, BabyError> { share::validate_revision_non_empty(commit)?; if name.is_empty() { return Err(BabyError::Custom( "submodule name must not be empty".to_string(), )); } let subs = self.list_submodules(commit).await?; Ok(helper::lookup(&subs, name).cloned()) } } fn _unused(_p: &Path) {}