use std::process::Command; use crate::bare::GitBare; use crate::error::{GitError, GitResult}; use crate::pb::{ ArchiveEntry, ListArchiveEntriesRequest, ListArchiveEntriesResponse, ObjectType, PageInfo, object_selector, }; impl GitBare { pub fn list_archive_entries( &self, request: ListArchiveEntriesRequest, ) -> GitResult { let revision = match request.treeish.and_then(|s| s.selector) { Some(object_selector::Selector::Oid(oid)) => oid.hex, Some(object_selector::Selector::Revision(name)) => name.revision, None => "HEAD".into(), }; let mut args = vec!["ls-tree".to_string(), "-r".into(), "-l".into(), revision]; if !request.pathspec.is_empty() { args.push("--".into()); args.extend(request.pathspec); } let output = Command::new("git") .arg("--git-dir") .arg(&self.bare_dir) .args(&args) .output()?; if !output.status.success() { return Err(GitError::CommandFailed { status_code: output.status.code(), stderr: String::from_utf8_lossy(&output.stderr).into_owned(), }); } let entries = String::from_utf8_lossy(&output.stdout) .lines() .filter_map(|line| { let (meta, path) = line.split_once('\t')?; let parts: Vec<&str> = meta.split_whitespace().collect(); let hex = parts.get(2)?.to_string(); Some(ArchiveEntry { path: path.to_string(), oid: Some(self.oid_to_pb(hex)), mode: u32::from_str_radix(parts.first().copied().unwrap_or("0"), 8) .unwrap_or(0), size: parts.get(3).and_then(|s| s.parse().ok()).unwrap_or(0), r#type: match parts.get(1).copied().unwrap_or_default() { "tree" => ObjectType::Tree as i32, "blob" => ObjectType::Blob as i32, "commit" => ObjectType::Commit as i32, "tag" => ObjectType::Tag as i32, _ => ObjectType::Unspecified as i32, }, }) }) .collect::>(); let total_count = entries.len() as u64; Ok(ListArchiveEntriesResponse { entries, page_info: Some(PageInfo { next_page_token: String::new(), has_next_page: false, total_count, }), }) } }