Skip to main content

varve_core/
discover.rs

1//! Pin discovery — walk up from the working directory (DD-006).
2//!
3//! The `rust-toolchain.toml` reflex: the nearest `varve.toml` on the path from
4//! the working directory to the filesystem root names the project's layer.
5//! Discovery never consults the environment, never falls through to a global
6//! default — a project without a pin has no layer, which at resolution time is
7//! an error, not a fallback.
8
9use std::path::{Path, PathBuf};
10
11/// The pin file name discovered by the walk.
12pub const PIN_FILE: &str = "varve.toml";
13
14/// Walk up from `start`, returning the nearest `varve.toml`.
15pub fn find_pin(start: &Path) -> Option<PathBuf> {
16    let mut dir = Some(start);
17    while let Some(d) = dir {
18        let candidate = d.join(PIN_FILE);
19        if candidate.is_file() {
20            return Some(candidate);
21        }
22        dir = d.parent();
23    }
24    None
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30    use std::fs;
31
32    // rivet: verifies REQ-PIN-001
33    #[test]
34    fn finds_pin_in_the_starting_directory() {
35        let tmp = tempfile::tempdir().unwrap();
36        let pin = tmp.path().join("varve.toml");
37        fs::write(&pin, "").unwrap();
38        assert_eq!(find_pin(tmp.path()), Some(pin));
39    }
40
41    // rivet: verifies REQ-PIN-001
42    #[test]
43    fn walks_up_to_an_ancestor_pin() {
44        let tmp = tempfile::tempdir().unwrap();
45        let pin = tmp.path().join("varve.toml");
46        fs::write(&pin, "").unwrap();
47        let deep = tmp.path().join("a/b/c");
48        fs::create_dir_all(&deep).unwrap();
49        assert_eq!(find_pin(&deep), Some(pin));
50    }
51
52    // rivet: verifies REQ-PIN-001
53    #[test]
54    fn nearest_pin_wins() {
55        let tmp = tempfile::tempdir().unwrap();
56        fs::write(tmp.path().join("varve.toml"), "").unwrap();
57        let sub = tmp.path().join("sub");
58        fs::create_dir_all(&sub).unwrap();
59        let near = sub.join("varve.toml");
60        fs::write(&near, "").unwrap();
61        assert_eq!(find_pin(&sub), Some(near));
62    }
63
64    // rivet: verifies REQ-PIN-001
65    #[test]
66    fn no_pin_means_none_not_a_default() {
67        let tmp = tempfile::tempdir().unwrap();
68        let deep = tmp.path().join("x/y");
69        fs::create_dir_all(&deep).unwrap();
70        assert_eq!(find_pin(&deep), None);
71    }
72}