use crate::prelude::*;
use std::path::PathBuf;
use wsb_prj::settings::RepoSettings;
pub fn find_repo_root(start_dir: &Path) -> Option<PathBuf> {
start_dir
.ancestors()
.find(|dir| RepoSettings::exists(dir))
.map(Path::to_path_buf)
}
pub fn require_repo_root(start_dir: &Path) -> Result<PathBuf> {
if let Some(root) = find_repo_root(start_dir) {
return Ok(root);
}
if let Some(old) = start_dir
.ancestors()
.find(|dir| dir.join(wsb_prj::settings::DIR).join("state.json").is_file())
{
anyhow::bail!(
"{} was set up by an older wsb, whose settings this one reads from a committed \
.wsb/repo.json. Run `wsb migrate` to bring it across",
old.display()
);
}
anyhow::bail!(
"{} is in no repository wsb manages (no .wsb/repo.json at or above it). \
Run `wsb init` in the repository",
start_dir.display()
)
}
pub fn find_super_root(start_dir: &Path) -> Option<PathBuf> {
let repo = gix::discover(start_dir).ok()?;
let workdir = repo.workdir()?.to_path_buf();
let mut current = workdir;
while let Some(parent) = current.parent() {
if parent == current {
break;
}
if parent.join(".git").exists() {
if let Ok(parent_repo) = gix::discover(parent) {
if let Some(parent_workdir) = parent_repo.workdir() {
let parent_workdir = parent_workdir.to_path_buf();
if current.starts_with(&parent_workdir) {
current = parent_workdir;
continue;
}
}
}
}
break;
}
Some(current)
}
pub fn find_worktree_root(start_dir: &Path) -> Option<PathBuf> {
find_super_root(start_dir).filter(|root| RepoSettings::exists(root))
}
pub fn require_worktree_root(start_dir: &Path) -> Result<PathBuf> {
find_worktree_root(start_dir).with_context(|| {
format!(
"{} is in no worktree wsb manages: its outermost repository has no .wsb/repo.json. \
Run `wsb init` there",
start_dir.display()
)
})
}