Skip to main content

aperture_cli/
fs.rs

1use std::io;
2use std::path::{Path, PathBuf};
3
4pub trait FileSystem {
5    /// Reads the entire contents of a file into a string.
6    ///
7    /// # Errors
8    ///
9    /// Returns an error if the file does not exist, cannot be read, or contains invalid UTF-8.
10    fn read_to_string(&self, path: &Path) -> io::Result<String>;
11
12    /// Writes a slice of bytes to a file, creating the file if it does not exist.
13    ///
14    /// # Errors
15    ///
16    /// Returns an error if the file cannot be written to or created.
17    fn write_all(&self, path: &Path, contents: &[u8]) -> io::Result<()>;
18
19    /// Creates a directory and all of its parent components if they are missing.
20    ///
21    /// # Errors
22    ///
23    /// Returns an error if the directory cannot be created.
24    fn create_dir_all(&self, path: &Path) -> io::Result<()>;
25
26    /// Removes a file from the filesystem.
27    ///
28    /// # Errors
29    ///
30    /// Returns an error if the file does not exist or cannot be removed.
31    fn remove_file(&self, path: &Path) -> io::Result<()>;
32
33    /// Removes a directory and all of its contents.
34    ///
35    /// # Errors
36    ///
37    /// Returns an error if the directory does not exist or cannot be removed.
38    fn remove_dir_all(&self, path: &Path) -> io::Result<()>;
39
40    /// Returns `true` if the path points to an existing entity.
41    fn exists(&self, path: &Path) -> bool;
42
43    /// Returns `true` if the path exists and is pointing at a directory.
44    fn is_dir(&self, path: &Path) -> bool;
45
46    /// Returns `true` if the path exists and is pointing at a regular file.
47    fn is_file(&self, path: &Path) -> bool;
48
49    /// Returns the canonical, absolute form of the path with all intermediate components normalized.
50    ///
51    /// # Errors
52    ///
53    /// Returns an error if the path does not exist or cannot be canonicalized.
54    fn canonicalize(&self, path: &Path) -> io::Result<PathBuf>;
55
56    /// Returns a vector of all entries in a directory.
57    ///
58    /// # Errors
59    ///
60    /// Returns an error if the directory does not exist or cannot be read.
61    fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
62
63    /// Writes data to a file atomically using a temp-file + rename strategy.
64    ///
65    /// The default implementation delegates to [`crate::atomic::atomic_write_sync`].
66    /// Test doubles may override this to use a simpler (non-atomic) write.
67    ///
68    /// # Errors
69    ///
70    /// Returns an error if the write or rename fails.
71    fn atomic_write(&self, path: &Path, contents: &[u8]) -> io::Result<()> {
72        crate::atomic::atomic_write_sync(path, contents)
73    }
74}
75
76pub struct OsFileSystem;
77
78impl FileSystem for OsFileSystem {
79    fn read_to_string(&self, path: &Path) -> io::Result<String> {
80        std::fs::read_to_string(path)
81    }
82
83    fn write_all(&self, path: &Path, contents: &[u8]) -> io::Result<()> {
84        std::fs::write(path, contents)
85    }
86
87    fn create_dir_all(&self, path: &Path) -> io::Result<()> {
88        std::fs::create_dir_all(path)
89    }
90
91    fn remove_file(&self, path: &Path) -> io::Result<()> {
92        std::fs::remove_file(path)
93    }
94
95    fn remove_dir_all(&self, path: &Path) -> io::Result<()> {
96        std::fs::remove_dir_all(path)
97    }
98
99    fn exists(&self, path: &Path) -> bool {
100        path.exists()
101    }
102
103    fn is_dir(&self, path: &Path) -> bool {
104        path.is_dir()
105    }
106
107    fn is_file(&self, path: &Path) -> bool {
108        path.is_file()
109    }
110
111    fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
112        path.canonicalize()
113    }
114
115    fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
116        Ok(std::fs::read_dir(path)?
117            .filter_map(std::result::Result::ok)
118            .map(|entry| entry.path())
119            .collect())
120    }
121}