steeldb/paths.rs
1//! Location-independent model resolution. An installed `steeldb` binary must find its bundled models
2//! whatever the working directory is — so we search, in priority order: an explicit env override, the
3//! per-user cache (`~/.steeldb/models`, `%LOCALAPPDATA%\steeldb\models`), next-to-the-executable
4//! (`<exe>/models`, and `<exe>/../../models` for the dev `target/<profile>/` layout), then `./models`.
5
6use std::path::PathBuf;
7
8/// Candidate `models/` roots, most-preferred first.
9pub fn model_roots() -> Vec<PathBuf> {
10 let mut roots = Vec::new();
11 if let Ok(r) = std::env::var("STEELDB_MODELS") {
12 roots.push(PathBuf::from(r));
13 }
14 if let Ok(home) = std::env::var("HOME") {
15 roots.push(PathBuf::from(home).join(".steeldb/models"));
16 }
17 if let Ok(la) = std::env::var("LOCALAPPDATA") {
18 roots.push(PathBuf::from(la).join("steeldb").join("models"));
19 }
20 if let Ok(exe) = std::env::current_exe() {
21 if let Some(dir) = exe.parent() {
22 roots.push(dir.join("models")); // installed: models next to the binary
23 roots.push(dir.join("..").join("..").join("models")); // dev: target/<profile>/ → repo/models
24 }
25 }
26 roots.push(PathBuf::from("models")); // CWD fallback (running from repo root)
27 roots
28}
29
30/// Resolve a model sub-directory. An explicit `env_var` wins (if it points at a dir containing
31/// `marker`); otherwise the first `<root>/<name>` that contains `marker`. `marker` is a file that must
32/// exist so we don't return an empty/partial dir.
33pub fn model_dir(name: &str, env_var: &str, marker: &str) -> Option<PathBuf> {
34 if let Ok(p) = std::env::var(env_var) {
35 let p = PathBuf::from(p);
36 if p.join(marker).exists() {
37 return Some(p);
38 }
39 }
40 model_roots().into_iter().map(|r| r.join(name)).find(|d| d.join(marker).exists())
41}