Skip to main content

odds/
paths.rs

1use std::{
2    fs::canonicalize,
3    path::{Path, PathBuf},
4};
5
6const STORAGE_PATH: &str = ".local/share/odds/";
7
8pub fn detect_explicit_path(input: &str) -> Option<PathBuf> {
9    let path = Path::new(input);
10    if path.exists() && path.is_dir() {
11        Some(path.to_path_buf())
12    } else {
13        None
14    }
15}
16/// Returns the roots from which the program is going to search for candidates;
17/// which are: the current working directory, home
18/// and potentially a git repository i.e. a folder containing .git.
19pub fn search_roots() -> Vec<PathBuf> {
20    let mut roots = Vec::new();
21
22    if let Ok(pwd) = std::env::current_dir() {
23        roots.push(pwd.clone());
24
25        if let Some(git_root) = find_git_root(&pwd) {
26            if git_root != pwd {
27                roots.push(git_root);
28            }
29        }
30    }
31
32    if let Ok(home) = std::env::var("HOME") {
33        roots.push(PathBuf::from(home));
34    }
35
36    roots.sort();
37    roots.dedup();
38
39    roots
40}
41
42pub fn normalize<P: AsRef<Path>>(path: P) -> PathBuf {
43    let p = path.as_ref();
44
45    canonicalize(p).unwrap_or_else(|_| p.to_path_buf())
46}
47
48/// Prefixes file name with the machines home plus storage path e.g.
49/// ~/.local/share/odds/<file>
50pub fn persistence_path(file: &str) -> PathBuf {
51    home_dir().join(STORAGE_PATH).join(file)
52}
53
54pub fn home_dir() -> PathBuf {
55    std::env::var("HOME")
56        .map(PathBuf::from)
57        .unwrap_or_else(|_| {
58            eprintln!("Warning: $HOME is not set, falling back to current directory.");
59            PathBuf::from(".")
60        })
61}
62
63fn find_git_root(start: &Path) -> Option<PathBuf> {
64    let mut current = Some(start);
65
66    while let Some(dir) = current {
67        if dir.join(".git").exists() {
68            return Some(dir.to_path_buf());
69        }
70        current = dir.parent();
71    }
72
73    None
74}