Skip to main content

harn_vm/
runtime_paths.rs

1use std::path::{Path, PathBuf};
2
3pub const HARN_STATE_DIR_ENV: &str = "HARN_STATE_DIR";
4pub const HARN_RUN_DIR_ENV: &str = "HARN_RUN_DIR";
5pub const HARN_WORKTREE_DIR_ENV: &str = "HARN_WORKTREE_DIR";
6
7fn resolve_root(base_dir: &Path, env_key: &str, default_relative: &str) -> PathBuf {
8    match std::env::var(env_key) {
9        Ok(value) if !value.trim().is_empty() => {
10            let candidate = PathBuf::from(value);
11            if candidate.is_absolute() {
12                candidate
13            } else {
14                base_dir.join(candidate)
15            }
16        }
17        _ => base_dir.join(default_relative),
18    }
19}
20
21pub fn state_root(base_dir: &Path) -> PathBuf {
22    resolve_root(base_dir, HARN_STATE_DIR_ENV, ".harn")
23}
24
25pub fn run_root(base_dir: &Path) -> PathBuf {
26    resolve_root(base_dir, HARN_RUN_DIR_ENV, ".harn-runs")
27}
28
29pub fn worktree_root(base_dir: &Path) -> PathBuf {
30    match std::env::var(HARN_WORKTREE_DIR_ENV) {
31        Ok(value) if !value.trim().is_empty() => {
32            let candidate = PathBuf::from(value);
33            if candidate.is_absolute() {
34                candidate
35            } else {
36                base_dir.join(candidate)
37            }
38        }
39        _ => state_root(base_dir).join("worktrees"),
40    }
41}
42
43pub fn store_path(base_dir: &Path) -> PathBuf {
44    state_root(base_dir).join("store.json")
45}
46
47pub fn checkpoint_dir(base_dir: &Path) -> PathBuf {
48    state_root(base_dir).join("checkpoints")
49}
50
51pub fn metadata_dir(base_dir: &Path) -> PathBuf {
52    state_root(base_dir).join("metadata")
53}
54
55pub fn event_log_dir(base_dir: &Path) -> PathBuf {
56    state_root(base_dir).join("events")
57}
58
59pub fn event_log_sqlite_path(base_dir: &Path) -> PathBuf {
60    state_root(base_dir).join("events.sqlite")
61}
62
63pub fn workflow_dir(base_dir: &Path) -> PathBuf {
64    state_root(base_dir).join("workflows")
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn defaults_resolve_under_base_dir() {
73        let base = Path::new("/tmp/harn-runtime-paths");
74        assert_eq!(state_root(base), base.join(".harn"));
75        assert_eq!(run_root(base), base.join(".harn-runs"));
76        assert_eq!(worktree_root(base), base.join(".harn").join("worktrees"));
77        assert_eq!(event_log_dir(base), base.join(".harn").join("events"));
78        assert_eq!(workflow_dir(base), base.join(".harn").join("workflows"));
79        assert_eq!(
80            event_log_sqlite_path(base),
81            base.join(".harn").join("events.sqlite")
82        );
83    }
84}