use crate::config::Config;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::{Mutex, OnceLock};
pub fn is_external(cfg: &Config, governs: &str) -> bool {
if crate::workspace::remotes::split(cfg, governs).is_some() {
return true;
}
let g = governs.trim_start_matches("./").trim_end_matches('/');
let under = |p: &str| {
let p = p.trim_start_matches("./").trim_end_matches('/');
!p.is_empty() && crate::paths::is_under(g, p)
};
inner_projects(cfg).iter().any(|p| under(p))
}
pub fn submodule_at(cfg: &Config, rel: &str) -> Option<(String, String)> {
cfg.raw.remotes.iter().filter(|(_, r)| r.auto).find_map(|(name, r)| {
let p = r.path.trim_end_matches('/');
let inner = if rel == p { "" } else { rel.strip_prefix(p)?.strip_prefix('/')? };
Some((name.clone(), inner.to_string()))
})
}
fn own_project(owners: &crate::workspace::Owners, path: &str) -> bool {
owners.by_path(path).is_none()
}
fn inner_projects(cfg: &Config) -> Vec<String> {
static C: OnceLock<Mutex<HashMap<PathBuf, Vec<String>>>> = OnceLock::new();
let mut c = C.get_or_init(Default::default).lock().unwrap_or_else(|e| e.into_inner());
c.entry(cfg.spec_home.clone())
.or_insert_with(|| {
let owners = crate::workspace::Owners::discover(cfg);
let mut v: Vec<String> =
super::submodules(&cfg.spec_home).into_iter().filter(|p| own_project(&owners, p)).collect();
v.extend(cfg.raw.owners.nested_dirs().map(String::from));
for r in cfg.raw.remotes.values().filter(|r| !r.auto) {
for p in std::iter::once(&r.path).chain(&r.paths) {
if !p.starts_with("..") && !p.starts_with('/') && !p.starts_with('~') {
v.push(p.clone());
}
}
}
v
})
.clone()
}