rustledger_loader/
discover.rs1use std::path::{Path, PathBuf};
11
12pub const COMMON_ROOT_NAMES: &[&str] = &[
14 "main.bean",
15 "main.beancount",
16 "ledger.bean",
17 "ledger.beancount",
18 "journal.bean",
19 "journal.beancount",
20 "index.bean",
21 "index.beancount",
22];
23
24#[must_use]
30pub fn discover_journal_file(dir: &Path) -> Option<PathBuf> {
31 for name in COMMON_ROOT_NAMES {
32 let candidate = dir.join(name);
33 if candidate.is_file() {
34 return Some(candidate);
35 }
36 }
37 None
38}
39
40#[must_use]
49pub fn discover_journal_upward(start: &Path) -> Option<PathBuf> {
50 let mut dir = Some(start);
51 while let Some(d) = dir {
52 if let Some(found) = discover_journal_file(d) {
53 return Some(found);
54 }
55 dir = d.parent();
56 }
57 None
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[test]
65 fn finds_a_root_beside_the_file_and_prefers_the_nearest() {
66 let dir = tempfile::tempdir().expect("tempdir");
67 let outer = dir.path();
68 let inner = outer.join("sub/deeper");
69 std::fs::create_dir_all(&inner).expect("mkdir");
70
71 std::fs::write(outer.join("main.beancount"), "").expect("write outer");
72 assert_eq!(
73 discover_journal_upward(&inner),
74 Some(outer.join("main.beancount")),
75 "walks up when nothing is nearer"
76 );
77
78 let nested = outer.join("sub").join("ledger.beancount");
79 std::fs::write(&nested, "").expect("write inner");
80 assert_eq!(
81 discover_journal_upward(&inner),
82 Some(nested),
83 "a nearer root wins over an outer one"
84 );
85 }
86
87 #[test]
88 fn name_priority_is_stable_and_directories_do_not_count() {
89 let dir = tempfile::tempdir().expect("tempdir");
90 std::fs::create_dir(dir.path().join("main.bean")).expect("mkdir");
92 assert_eq!(discover_journal_file(dir.path()), None);
93
94 std::fs::write(dir.path().join("journal.beancount"), "").expect("write");
95 std::fs::write(dir.path().join("main.beancount"), "").expect("write");
96 assert_eq!(
97 discover_journal_file(dir.path()),
98 Some(dir.path().join("main.beancount")),
99 "`main.beancount` outranks `journal.beancount`"
100 );
101 }
102
103 #[test]
104 fn returns_none_when_there_is_no_ledger_anywhere_above() {
105 let dir = tempfile::tempdir().expect("tempdir");
106 let deep = dir.path().join("a/b/c");
107 std::fs::create_dir_all(&deep).expect("mkdir");
108 assert_eq!(discover_journal_upward(&deep), None);
111 }
112}