use sley_core::{ObjectId, Result};
use sley_odb::repository_objects_dir;
use sley_worktree::worktree_root_for_git_dir;
use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
pub fn for_each_ref_loose_object_disk_size(git_dir: &Path, oid: &ObjectId) -> Result<Option<u64>> {
let hex = oid.to_hex();
if hex.len() < 2 {
return Ok(None);
}
let (fanout, file) = hex.split_at(2);
let path = repository_objects_dir(git_dir).join(fanout).join(file);
match fs::metadata(path) {
Ok(metadata) => Ok(Some(metadata.len())),
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err.into()),
}
}
pub fn for_each_ref_worktree_path(
git_dir: &Path,
main_worktree_root: Option<&Path>,
head_ref: Option<&str>,
refname: &str,
) -> Result<Option<String>> {
let main_worktree_root = main_worktree_root
.map(PathBuf::from)
.or_else(|| worktree_root_for_git_dir(git_dir).ok().flatten());
if head_ref == Some(refname)
&& let Some(worktree_root) = main_worktree_root
{
return Ok(Some(
fs::canonicalize(worktree_root)?
.to_string_lossy()
.into_owned(),
));
}
let worktrees_dir = git_dir.join("worktrees");
let Ok(entries) = fs::read_dir(worktrees_dir) else {
return Ok(None);
};
for entry in entries {
let entry = entry?;
let admin_dir = entry.path();
let Ok(head) = fs::read_to_string(admin_dir.join("HEAD")) else {
continue;
};
if head.trim().strip_prefix("ref: ") != Some(refname) {
continue;
}
let Ok(gitdir) = fs::read_to_string(admin_dir.join("gitdir")) else {
continue;
};
let gitdir = gitdir.trim();
if gitdir.is_empty() {
continue;
}
let gitdir_path = PathBuf::from(gitdir);
let gitdir_path = if gitdir_path.is_absolute() {
gitdir_path
} else {
admin_dir.join(gitdir_path)
};
if let Some(worktree_root) = gitdir_path.parent() {
return Ok(Some(
fs::canonicalize(worktree_root)?
.to_string_lossy()
.into_owned(),
));
}
}
Ok(None)
}
pub fn for_each_ref_worktree_paths(
git_dir: &Path,
main_worktree_root: Option<&Path>,
head_ref: Option<&str>,
) -> Result<HashMap<String, String>> {
let mut paths = HashMap::new();
let main_worktree_root = main_worktree_root
.map(PathBuf::from)
.or_else(|| worktree_root_for_git_dir(git_dir).ok().flatten());
if let Some(head_ref) = head_ref
&& let Some(worktree_root) = main_worktree_root
{
let canonical = fs::canonicalize(worktree_root)?;
paths.insert(
head_ref.to_string(),
canonical.to_string_lossy().into_owned(),
);
}
let worktrees_dir = git_dir.join("worktrees");
let Ok(entries) = fs::read_dir(worktrees_dir) else {
return Ok(paths);
};
for entry in entries {
let entry = entry?;
let admin_dir = entry.path();
let Ok(head) = fs::read_to_string(admin_dir.join("HEAD")) else {
continue;
};
let Some(refname) = head.trim().strip_prefix("ref: ") else {
continue;
};
if paths.contains_key(refname) {
continue;
}
let Ok(gitdir) = fs::read_to_string(admin_dir.join("gitdir")) else {
continue;
};
let gitdir = gitdir.trim();
if gitdir.is_empty() {
continue;
}
let gitdir_path = PathBuf::from(gitdir);
let gitdir_path = if gitdir_path.is_absolute() {
gitdir_path
} else {
admin_dir.join(gitdir_path)
};
if let Some(worktree_root) = gitdir_path.parent() {
let canonical = fs::canonicalize(worktree_root)?;
paths.insert(
refname.to_string(),
canonical.to_string_lossy().into_owned(),
);
}
}
Ok(paths)
}