use std::path::Path;
#[allow(dead_code)]
pub fn find_reliary_root(start: &str) -> Option<(String, String, String)> {
let p = Path::new(start);
let mut current: Option<&Path> = if p.is_file() || p.is_symlink() {
p.parent()
} else {
Some(p)
};
while let Some(dir) = current {
let reliary = dir.join(".reliary");
if reliary.is_dir() {
let root = dir.to_string_lossy().to_string();
let idx = reliary.join("index.sqlite").to_string_lossy().to_string();
let cache = reliary.join("cache.sqlite").to_string_lossy().to_string();
return Some((root, idx, cache));
}
current = dir.parent();
}
None
}
#[allow(dead_code)]
pub fn find_workdir(start: &str) -> String {
find_reliary_root(start).map(|(r, _, _)| r).unwrap_or_else(|| ".".to_string())
}
#[allow(dead_code)]
pub fn relativize(root: &str, file: &str) -> String {
file.strip_prefix(&format!("{}/", root))
.or_else(|| file.strip_prefix(root))
.unwrap_or(file)
.to_string()
}
pub fn open_or_create(path: &std::path::Path) -> Result<rusqlite::Connection, String> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).ok(); ensure_reliary_ignored(parent);
}
reliary_core::open(path)
}
pub fn ensure_reliary_ignored(dir: &Path) {
if dir.file_name().and_then(|n| n.to_str()) != Some(".reliary") {
return;
}
let gi = dir.join(".gitignore");
if gi.exists() {
return;
}
let _ = std::fs::write(&gi, "*\n"); }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn find_workdir_defaults_to_dot() {
assert_eq!(find_workdir("/nonexistent/path"), ".");
}
#[test]
fn relativize_strips_prefix() {
assert_eq!(relativize("/home/user/project", "/home/user/project/src/main.rs"), "src/main.rs");
}
#[test]
fn relativize_returns_full_when_no_match() {
assert_eq!(relativize("/home/a", "/home/b/file.rs"), "/home/b/file.rs");
}
#[test]
fn ensure_reliary_ignored_writes_star() {
let dir = std::env::temp_dir().join(format!("relign_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
let rr = dir.join(".reliary");
std::fs::create_dir_all(&rr).unwrap();
ensure_reliary_ignored(&rr);
let gi = rr.join(".gitignore");
assert!(gi.exists(), "self-ignore must be written");
assert_eq!(std::fs::read_to_string(&gi).unwrap().trim(), "*");
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn ensure_reliary_ignored_does_not_clobber_user_file() {
let dir = std::env::temp_dir().join(format!("relign2_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
let rr = dir.join(".reliary");
std::fs::create_dir_all(&rr).unwrap();
std::fs::write(rr.join(".gitignore"), "*\n!config.json\n").unwrap();
ensure_reliary_ignored(&rr);
let got = std::fs::read_to_string(rr.join(".gitignore")).unwrap();
assert!(got.contains("!config.json"), "user .gitignore must be preserved, got: {got:?}");
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn ensure_reliary_ignored_ignores_other_dirs() {
let dir = std::env::temp_dir().join(format!("relign3_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
ensure_reliary_ignored(&dir);
assert!(!dir.join(".gitignore").exists(), "must not write into a non-.reliary dir");
let _ = std::fs::remove_dir_all(&dir);
}
}