entrust_core/
resolve.rs

1use anyhow::anyhow;
2use std::path;
3use std::path::{Path, PathBuf};
4use walkdir::WalkDir;
5
6pub struct Locations {
7    pub files: Vec<String>,
8    pub dirs: Vec<String>,
9}
10
11pub fn get_existing_locations(base: &Path) -> anyhow::Result<Locations> {
12    let walk_dir = WalkDir::new(base);
13    let mut locations = Locations {
14        files: Vec::with_capacity(16),
15        dirs: Vec::with_capacity(16),
16    };
17    for entry in walk_dir {
18        let entry = entry?;
19        let mut path = pathdiff::diff_paths(entry.path(), base)
20            .ok_or(anyhow!("Error resolving relative path"))?
21            .into_os_string()
22            .into_string()
23            .map_err(|_| anyhow!("Encountered invalid UTF-8"))?;
24        if path.starts_with('.') {
25            continue;
26        }
27        if cfg!(windows) {
28            path = path.replace(path::MAIN_SEPARATOR, "/")
29        }
30        if entry.path().is_dir() {
31            if !path.is_empty() {
32                let dir_path = format!("{path}/");
33                if !locations.dirs.contains(&dir_path) {
34                    locations.dirs.push(dir_path)
35                }
36            }
37        } else {
38            locations.files.push(path)
39        }
40    }
41    Ok(locations)
42}
43
44pub fn resolve_existing_location(
45    base: &Path,
46    key: &str,
47    can_be_dir: bool,
48) -> anyhow::Result<PathBuf> {
49    let concat = base.join(key);
50    if can_be_dir {
51        return if concat.exists() {
52            Ok(concat)
53        } else {
54            Err(anyhow!("Key {key} does not exist"))
55        };
56    }
57    if concat.is_file() {
58        return Ok(concat);
59    }
60    if concat.is_dir() {
61        let pass = concat.join("pass");
62        return if pass.is_file() {
63            Ok(pass)
64        } else {
65            Err(anyhow!("{key} is a directory"))
66        };
67    }
68    let existing = get_existing_locations(base)?;
69    let candidates: Vec<_> = existing
70        .files
71        .iter()
72        .filter(|&s| s.starts_with(key))
73        .collect();
74    if candidates.len() == 1 {
75        return Ok(base.join(candidates[0]));
76    }
77    Err(anyhow!("Key {key} does not exist"))
78}
79
80pub fn resolve_new_location(base: &Path, key: &str) -> anyhow::Result<PathBuf> {
81    let file = base.join(key);
82    if file.exists() {
83        Err(anyhow!("Key {key} already exists"))
84    } else {
85        Ok(file)
86    }
87}