Skip to main content

concinnity_world/world/
find.rs

1/// The world source file's conventional name.
2pub const WORLD_JSONL: &str = "world.jsonl";
3/// Locate a world JSONL file.
4///
5/// If `name` is given, returns the state root's `worlds/<name>.jsonl` when it
6/// exists. If `name` is None, returns the most recently modified `.jsonl` in
7/// `worlds/`. Falls back to `world.jsonl` in the current directory and then
8/// walks up parent directories, which is also the whole search when no state
9/// root is installed.
10pub fn find_world_jsonl(name: Option<&str>) -> std::io::Result<String> {
11    let worlds_dir = crate::paths::worlds_dir();
12
13    if let Some(n) = name {
14        let path = worlds_dir
15            .as_deref()
16            .map(|d| d.join(format!("{}.jsonl", n)));
17        if let Some(path) = &path
18            && path.exists()
19        {
20            return Ok(path.to_string_lossy().into_owned());
21        }
22        return Err(named_world_not_found(n, path.as_deref()));
23    }
24
25    // No name given: pick the most recently modified world in `worlds/`.
26    if let Some(worlds_dir) = worlds_dir.filter(|d| d.is_dir()) {
27        let mut best: Option<(std::time::SystemTime, std::path::PathBuf)> = None;
28        if let Ok(entries) = std::fs::read_dir(&worlds_dir) {
29            for entry in entries.flatten() {
30                let path = entry.path();
31                if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
32                    continue;
33                }
34                if let Ok(meta) = std::fs::metadata(&path) {
35                    let mtime = meta.modified().unwrap_or(std::time::UNIX_EPOCH);
36                    if best.as_ref().map(|(t, _)| mtime > *t).unwrap_or(true) {
37                        best = Some((mtime, path));
38                    }
39                }
40            }
41        }
42        if let Some((_, path)) = best {
43            return Ok(path.to_string_lossy().into_owned());
44        }
45    }
46
47    // Fall back to world.jsonl in cwd or any parent directory.
48    let mut dir = std::env::current_dir()?;
49    loop {
50        let candidate = dir.join(WORLD_JSONL);
51        if candidate.exists() {
52            return Ok(candidate.to_string_lossy().into_owned());
53        }
54        match dir.parent() {
55            Some(parent) => dir = parent.to_path_buf(),
56            None => {
57                return Err(std::io::Error::new(
58                    std::io::ErrorKind::NotFound,
59                    format!(
60                        "no world found: run `cn fetch-world` or create `{}`",
61                        WORLD_JSONL,
62                    ),
63                ));
64            }
65        }
66    }
67}
68
69// The error for a named world that could not be located. Split out so both
70// misses -- a state root holding no such world, and no state root at all -- are
71// testable without touching the process-global anchor.
72fn named_world_not_found(name: &str, path: Option<&std::path::Path>) -> std::io::Error {
73    let message = match path {
74        Some(p) => format!("world '{}' not found at {}", name, p.display()),
75        None => format!("world '{}' not found: no project state directory", name),
76    };
77    std::io::Error::new(std::io::ErrorKind::NotFound, message)
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    // The named-miss branches are exercised through the pure error builder: the
85    // lookup itself reads the process-global path anchors and walks up from the
86    // cwd, both of which are shared with other tests in this binary (paths.rs
87    // owns the global mutation), so redirecting them would race those tests.
88    #[test]
89    fn a_missing_named_world_names_the_file_it_looked_for() {
90        let path = std::path::Path::new("/proj/worlds/cn_test_no_such_world.jsonl");
91        let err = named_world_not_found("cn_test_no_such_world", Some(path));
92        assert_eq!(err.kind(), std::io::ErrorKind::NotFound);
93        let msg = err.to_string();
94        assert!(msg.contains("cn_test_no_such_world"), "message was: {msg}");
95        assert!(msg.contains(".jsonl"), "message was: {msg}");
96    }
97
98    // With no state root there is no file to name, so the message says what is
99    // missing instead of pointing at a path nobody chose.
100    #[test]
101    fn a_named_world_without_a_state_root_says_so() {
102        let err = named_world_not_found("main", None);
103        assert_eq!(err.kind(), std::io::ErrorKind::NotFound);
104        let msg = err.to_string();
105        assert!(msg.contains("main"), "message was: {msg}");
106        assert!(
107            msg.contains("no project state directory"),
108            "message was: {msg}"
109        );
110    }
111
112    // The lookup still fails cleanly for a name nothing on this host provides.
113    #[test]
114    fn missing_named_world_is_a_not_found_error() {
115        let err = find_world_jsonl(Some("cn_test_no_such_world")).unwrap_err();
116        assert_eq!(err.kind(), std::io::ErrorKind::NotFound);
117        assert!(err.to_string().contains("cn_test_no_such_world"));
118    }
119}