Skip to main content

vfs_kit/
core.rs

1use anyhow;
2use std::path::{Path, PathBuf};
3
4/// FsBackend defines a common API for all virtual file systems (vfs) in the crate.
5/// Some functions here use `path` as a parameter or return value.
6/// In all cases, `path` will refer to the virtual file system. The exception
7/// is the `root()` function, which returns the path in the host file system.
8pub trait FsBackend {
9    /// Returns root path refer to the host file system.
10    fn root(&self) -> &Path;
11
12    /// Returns current working directory related to the vfs root.
13    fn cwd(&self) -> &Path;
14
15    /// Returns the path on the host system that matches the specified internal path.
16    /// * `inner_path` must exist in VFS
17    fn to_host<P: AsRef<Path>>(&self, inner_path: P) -> Result<PathBuf>;
18
19    /// Changes the current working directory.
20    /// `path` can be in relative or absolute form, but in both cases it must exist in vfs.
21    /// Error returns in case the `path` is not exist.
22    fn cd<P: AsRef<Path>>(&mut self, path: P) -> Result<()>;
23
24    /// Returns true, if `path` exists.
25    fn exists<P: AsRef<Path>>(&self, path: P) -> bool;
26
27    /// Checks if `path` is a directory.
28    fn is_dir<P: AsRef<Path>>(&self, path: P) -> Result<bool>;
29
30    /// Checks if `path` is a regular file.
31    fn is_file<P: AsRef<Path>>(&self, path: P) -> Result<bool>;
32
33    /// Returns an iterator over directory entries.
34    /// `path` is a directory, or CWD if None.
35    fn ls<P: AsRef<Path>>(&self, path: P) -> Result<impl Iterator<Item = &Path>>;
36
37    /// Returns a recursive iterator over the directory tree starting from a given path.
38    fn tree<P: AsRef<Path>>(&self, path: P) -> Result<impl Iterator<Item = &Path>>;
39
40    /// Creates directory and all it parents, if necessary.
41    fn mkdir<P: AsRef<Path>>(&mut self, path: P) -> Result<()>;
42
43    /// Creates new file in vfs.
44    fn mkfile<P: AsRef<Path>>(&mut self, file_path: P, content: Option<&[u8]>) -> Result<()>;
45
46    /// Reads the entire contents of a file into a byte vector.
47    fn read<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>>;
48
49    /// Writes bytes to an existing file, replacing its entire contents.
50    fn write<P: AsRef<Path>>(&mut self, path: P, content: &[u8]) -> Result<()>;
51
52    /// Appends bytes to the end of an existing file, preserving its old contents.
53    fn append<P: AsRef<Path>>(&mut self, path: P, content: &[u8]) -> Result<()>;
54
55    /// Removes a file or directory at the specified path.
56    fn rm<P: AsRef<Path>>(&mut self, path: P) -> Result<()>;
57
58    /// Removes all artifacts (dirs and files) in vfs, but preserve its root.
59    fn cleanup(&mut self) -> bool;
60}
61
62pub type Result<T> = std::result::Result<T, anyhow::Error>;
63
64pub mod utils {
65    use super::Result;
66    use std::path::{Component, Path, PathBuf};
67
68    /// Normalizes an arbitrary `path` by processing all occurrences
69    /// of '.' and '..' elements. Also, removes final `/`.
70    pub fn normalize<P: AsRef<Path>>(path: P) -> PathBuf {
71        let mut result = PathBuf::new();
72        for component in path.as_ref().components() {
73            match component {
74                Component::CurDir => {}
75                Component::ParentDir => {
76                    result.pop();
77                }
78                _ => {
79                    result.push(component);
80                }
81            }
82        }
83        // remove final /
84        if result != PathBuf::from("/") && result.ends_with("/") {
85            result.pop();
86        }
87        result
88    }
89
90    /// Checks that the path consists only of the root component `/`.
91    pub fn is_virtual_root<P: AsRef<Path>>(path: P) -> bool {
92        let components: Vec<_> = path.as_ref().components().collect();
93        components.len() == 1 && components[0] == Component::RootDir
94    }
95
96    /// Removes file or directory (recursively) on host.
97    pub fn rm_on_host<P: AsRef<Path>>(host_path: P) -> Result<()> {
98        let host_path = host_path.as_ref();
99        if host_path.is_dir() {
100            std::fs::remove_dir_all(host_path)?
101        } else {
102            std::fs::remove_file(host_path)?
103        }
104        Ok(())
105    }
106}