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}