Skip to main content

stakpak_ak/
error.rs

1use std::fmt::{Display, Formatter};
2use std::path::PathBuf;
3
4#[derive(Debug)]
5pub enum Error {
6    Io(std::io::Error),
7    AlreadyExists(PathBuf),
8    NotFound(PathBuf),
9    NotADirectory(PathBuf),
10    UnsafePath(PathBuf),
11    Parse(String),
12}
13
14impl Display for Error {
15    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
16        match self {
17            Self::Io(error) => write!(
18                f,
19                "io error: {error}. check filesystem permissions, parent directories, and AK_STORE"
20            ),
21            Self::AlreadyExists(path) => write!(
22                f,
23                "path already exists: {}. choose a new path or overwrite intentionally",
24                path.display()
25            ),
26            Self::NotFound(path) => write!(
27                f,
28                "path not found: {}. check that the path is relative to the store root",
29                path.display()
30            ),
31            Self::NotADirectory(path) => {
32                write!(f, "path is not a directory: {}", path.display())
33            }
34            Self::UnsafePath(path) => write!(
35                f,
36                "unsafe path blocked: {}. ak paths must stay inside the store and cannot pass through symlinks",
37                path.display()
38            ),
39            Self::Parse(message) => write!(f, "invalid input: {message}"),
40        }
41    }
42}
43
44impl std::error::Error for Error {}
45
46impl From<std::io::Error> for Error {
47    fn from(value: std::io::Error) -> Self {
48        Self::Io(value)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::Error;
55    use std::path::PathBuf;
56
57    #[test]
58    fn not_found_error_explains_path_interpretation() {
59        let error = Error::NotFound(PathBuf::from("/tmp/store/knowledge/missing.md"));
60        let rendered = error.to_string();
61
62        assert!(rendered.contains("path not found"));
63        assert!(rendered.contains("check that the path is relative to the store root"));
64    }
65
66    #[test]
67    fn already_exists_error_suggests_intentional_overwrite_or_new_path() {
68        let error = Error::AlreadyExists(PathBuf::from("/tmp/store/knowledge/existing.md"));
69        let rendered = error.to_string();
70
71        assert!(rendered.contains("path already exists"));
72        assert!(rendered.contains("choose a new path or overwrite intentionally"));
73    }
74}