use std::path::PathBuf;
pub(crate) const SCHEMA_BACKLOG: &str = "doctrine.backlog";
pub(crate) const SCHEMA_KNOWLEDGE: &str = "doctrine.knowledge";
pub(crate) const SCHEMA_ADR: &str = "doctrine.adr";
pub(crate) const SCHEMA_RFC: &str = "doctrine.rfc";
pub(crate) const SCHEMA_MEMORY: &str = "doctrine.memory";
pub(crate) const SCHEMA_PLAN: &str = "doctrine.plan";
pub(crate) const SCHEMA_PLAN_OVERVIEW: &str = "doctrine.plan.overview";
pub(crate) fn repo_root() -> PathBuf {
if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") {
return PathBuf::from(dir);
}
let mut cur = std::env::current_dir().expect("resolve current dir");
loop {
if cur.join("Cargo.toml").is_file() {
return cur;
}
if !cur.pop() {
panic!("repo_root: no runtime CARGO_MANIFEST_DIR and no Cargo.toml ancestor of CWD");
}
}
}
pub(crate) fn doctrine_bin() -> PathBuf {
let mut p = std::env::current_exe().expect("resolve current_exe for doctrine_bin");
p.pop(); p.pop(); p.push(format!("doctrine{}", std::env::consts::EXE_SUFFIX));
p
}
pub(crate) const WORKER_MARKER_REL: &str = ".doctrine/state/dispatch/worker";
pub(crate) fn worker_marker_at(root: &std::path::Path, env_present: bool) -> bool {
env_present || root.join(WORKER_MARKER_REL).exists()
}
#[allow(dead_code)]
pub(crate) fn under_worker_marker() -> bool {
worker_marker_at(&repo_root(), std::env::var_os("DOCTRINE_WORKER").is_some())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn worker_marker_at_reads_env_and_marker_legs() {
let root = tempfile::tempdir_in(std::env::temp_dir()).expect("tempdir");
assert!(
!worker_marker_at(root.path(), false),
"no env, no marker ⇒ not under worker"
);
assert!(
worker_marker_at(root.path(), true),
"env leg ⇒ under worker"
);
let marker = root.path().join(WORKER_MARKER_REL);
std::fs::create_dir_all(marker.parent().expect("marker parent")).expect("mkdir marker dir");
std::fs::write(&marker, b"").expect("write marker");
assert!(
worker_marker_at(root.path(), false),
"marker file at root ⇒ under worker"
);
}
#[test]
fn doctrine_bin_returns_existing_executable() {
let path = doctrine_bin();
let name = path.file_name().expect("doctrine_bin path has a file name");
let name_str = name
.to_str()
.expect("doctrine_bin file name is valid UTF-8");
assert!(
name_str.starts_with("doctrine"),
"doctrine_bin file name starts with 'doctrine': {name_str}"
);
assert!(
path.exists(),
"doctrine_bin path exists: {}",
path.display()
);
let meta = path.metadata().expect("doctrine_bin metadata readable");
assert!(meta.is_file(), "doctrine_bin is a file: {}", path.display());
assert!(
meta.len() > 0,
"doctrine_bin non-zero size: {}",
path.display()
);
}
}