use crate::tui::model::{GitObject, GitObjectType};
pub fn build_git_file_tree(plumber: &crate::GitPlumber) -> Result<Vec<GitObject>, String> {
let git_path = plumber.get_repo_path().join(".git");
let mut git_contents = Vec::new();
if let Ok(objects_folder) = build_objects_folder(plumber) {
git_contents.push(objects_folder);
}
if let Ok(refs_folder) = build_refs_folder(plumber) {
git_contents.push(refs_folder);
}
match std::fs::read_dir(&git_path) {
Ok(entries) => {
let mut items: Vec<(String, std::path::PathBuf, bool)> = Vec::new();
for entry in entries.flatten() {
let entry_path = entry.path();
let name = entry.file_name().to_string_lossy().to_string();
let is_dir = entry_path.is_dir();
if name != "objects" && name != "refs" {
items.push((name, entry_path, is_dir));
}
}
items.sort_by(|a, b| {
match (a.2, b.2) {
(true, false) => std::cmp::Ordering::Less, (false, true) => std::cmp::Ordering::Greater, _ => a.0.cmp(&b.0), }
});
for (_, entry_path, is_dir) in items {
if is_dir {
git_contents.push(GitObject::new_filesystem_folder(entry_path, false));
} else {
git_contents.push(GitObject::new_filesystem_file(entry_path));
}
}
}
Err(e) => return Err(format!("Error reading .git directory: {}", e)),
}
Ok(git_contents)
}
fn build_objects_folder(plumber: &crate::GitPlumber) -> Result<GitObject, String> {
let objects_path = plumber.get_repo_path().join(".git/objects");
let mut objects_folder = GitObject::new_filesystem_folder(objects_path.clone(), true);
objects_folder.expanded = true;
let pack_path = objects_path.join("pack");
if pack_path.exists() {
let mut pack_folder = GitObject::new_filesystem_folder(pack_path, true);
pack_folder.expanded = true;
match plumber.list_pack_groups() {
Ok(pack_groups) => {
for (_, pack_group) in pack_groups {
if pack_group.is_valid() {
pack_folder.add_child(GitObject::new_pack_folder(pack_group));
}
}
}
Err(e) => return Err(format!("Error loading pack groups: {e}")),
}
if let GitObjectType::FileSystemFolder { is_loaded, .. } = &mut pack_folder.obj_type {
*is_loaded = true;
}
objects_folder.add_child(pack_folder);
}
let info_path = objects_path.join("info");
if info_path.exists() {
objects_folder.add_child(GitObject::new_filesystem_folder(info_path, false));
}
let mut loose_objects_folder = GitObject::new_category("Loose Objects");
loose_objects_folder.expanded = false;
match plumber.get_loose_object_stats() {
Ok(stats) => match plumber.list_parsed_loose_objects(stats.total_count) {
Ok(loose_objects) => {
for parsed_obj in loose_objects {
loose_objects_folder.add_child(GitObject::new_parsed_loose_object(parsed_obj));
}
}
Err(e) => return Err(format!("Error loading loose objects: {e}")),
},
Err(e) => return Err(format!("Error getting loose object stats: {e}")),
}
objects_folder.add_child(loose_objects_folder);
if let GitObjectType::FileSystemFolder { is_loaded, .. } = &mut objects_folder.obj_type {
*is_loaded = true;
}
Ok(objects_folder)
}
fn build_refs_folder(plumber: &crate::GitPlumber) -> Result<GitObject, String> {
let refs_path = plumber.get_repo_path().join(".git/refs");
let mut refs_folder = GitObject::new_filesystem_folder(refs_path, true);
refs_folder.expanded = true;
let heads_path = plumber.get_repo_path().join(".git/refs/heads");
if heads_path.exists() {
let mut heads_folder = GitObject::new_filesystem_folder(heads_path, true);
heads_folder.expanded = true;
match plumber.list_head_refs() {
Ok(head_refs) => {
for path in head_refs {
heads_folder.add_child(GitObject::new_ref(path));
}
}
Err(e) => return Err(format!("Error loading head refs: {e}")),
}
if let GitObjectType::FileSystemFolder { is_loaded, .. } = &mut heads_folder.obj_type {
*is_loaded = true;
}
refs_folder.add_child(heads_folder);
}
let remotes_path = plumber.get_repo_path().join(".git/refs/remotes");
if remotes_path.exists() {
let mut remotes_folder = GitObject::new_filesystem_folder(remotes_path, true);
remotes_folder.expanded = true;
match plumber.list_remote_refs() {
Ok(remote_refs) => {
for (remote_name, refs) in remote_refs {
let mut remote_category = GitObject::new_category(&remote_name);
for path in refs {
remote_category.add_child(GitObject::new_ref(path));
}
remotes_folder.add_child(remote_category);
}
}
Err(e) => return Err(format!("Error loading remote refs: {e}")),
}
if let GitObjectType::FileSystemFolder { is_loaded, .. } = &mut remotes_folder.obj_type {
*is_loaded = true;
}
refs_folder.add_child(remotes_folder);
}
let tags_path = plumber.get_repo_path().join(".git/refs/tags");
if tags_path.exists() {
let mut tags_folder = GitObject::new_filesystem_folder(tags_path, true);
tags_folder.expanded = true;
match plumber.list_tag_refs() {
Ok(tag_refs) => {
for path in tag_refs {
tags_folder.add_child(GitObject::new_ref(path));
}
}
Err(e) => return Err(format!("Error loading tag refs: {e}")),
}
if let GitObjectType::FileSystemFolder { is_loaded, .. } = &mut tags_folder.obj_type {
*is_loaded = true;
}
refs_folder.add_child(tags_folder);
}
match plumber.has_stash_ref() {
Ok(true) => {
let stash_path = plumber.get_repo_path().join(".git/refs/stash");
refs_folder.add_child(GitObject::new_ref(stash_path));
}
Ok(false) => {}
Err(e) => return Err(format!("Error checking stash ref: {e}")),
}
if let GitObjectType::FileSystemFolder { is_loaded, .. } = &mut refs_folder.obj_type {
*is_loaded = true;
}
Ok(refs_folder)
}