use std::path::{Path, PathBuf};
#[derive(Clone, Debug)]
pub struct FsMetadata {
pub is_dir: bool,
pub is_symlink: bool,
}
#[derive(Clone, Debug)]
pub struct FsEntry {
pub name: String,
pub path: PathBuf,
pub is_dir: bool,
pub is_symlink: bool,
pub size: Option<u64>,
pub modified: Option<std::time::SystemTime>,
}
pub trait FileSystem {
fn read_dir(&self, dir: &Path) -> std::io::Result<Vec<FsEntry>>;
fn canonicalize(&self, path: &Path) -> std::io::Result<PathBuf>;
fn metadata(&self, path: &Path) -> std::io::Result<FsMetadata>;
fn create_dir(&self, path: &Path) -> std::io::Result<()>;
fn rename(&self, from: &Path, to: &Path) -> std::io::Result<()>;
fn remove_file(&self, path: &Path) -> std::io::Result<()>;
fn remove_dir(&self, path: &Path) -> std::io::Result<()>;
fn remove_dir_all(&self, path: &Path) -> std::io::Result<()>;
fn copy_file(&self, from: &Path, to: &Path) -> std::io::Result<u64>;
}
#[derive(Clone, Copy, Debug, Default)]
pub struct StdFileSystem;
impl FileSystem for StdFileSystem {
fn read_dir(&self, dir: &Path) -> std::io::Result<Vec<FsEntry>> {
let mut out = Vec::new();
let rd = std::fs::read_dir(dir)?;
for e in rd {
let e = match e {
Ok(v) => v,
Err(_) => continue,
};
let ft = match e.file_type() {
Ok(v) => v,
Err(_) => continue,
};
let name = e.file_name().to_string_lossy().to_string();
let path = e.path();
let meta = e.metadata().ok();
let modified = meta.as_ref().and_then(|m| m.modified().ok());
let is_dir = ft.is_dir();
let is_symlink = ft.is_symlink();
let size = if is_dir {
None
} else {
meta.as_ref().filter(|m| m.is_file()).map(|m| m.len())
};
out.push(FsEntry {
name,
path,
is_dir,
is_symlink,
size,
modified,
});
}
Ok(out)
}
fn canonicalize(&self, path: &Path) -> std::io::Result<PathBuf> {
std::fs::canonicalize(path)
}
fn metadata(&self, path: &Path) -> std::io::Result<FsMetadata> {
let md = std::fs::metadata(path)?;
let link_md = std::fs::symlink_metadata(path)?;
Ok(FsMetadata {
is_dir: md.is_dir(),
is_symlink: link_md.file_type().is_symlink(),
})
}
fn create_dir(&self, path: &Path) -> std::io::Result<()> {
std::fs::create_dir(path)
}
fn rename(&self, from: &Path, to: &Path) -> std::io::Result<()> {
std::fs::rename(from, to)
}
fn remove_file(&self, path: &Path) -> std::io::Result<()> {
std::fs::remove_file(path)
}
fn remove_dir(&self, path: &Path) -> std::io::Result<()> {
std::fs::remove_dir(path)
}
fn remove_dir_all(&self, path: &Path) -> std::io::Result<()> {
std::fs::remove_dir_all(path)
}
fn copy_file(&self, from: &Path, to: &Path) -> std::io::Result<u64> {
std::fs::copy(from, to)
}
}