use std::{
fs::{self, DirEntry},
path::{Path, PathBuf},
};
use super::FsError;
pub(crate) fn read_to_string(path: impl AsRef<Path>) -> Result<String, FsError> {
let path = path.as_ref();
fs::read_to_string(path).map_err(|source| FsError::ReadToString {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<(), FsError> {
let path = path.as_ref();
fs::write(path, contents).map_err(|source| FsError::Write {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn write_atomic(
path: impl AsRef<Path>,
contents: impl AsRef<[u8]>,
) -> Result<(), FsError> {
use std::io::Write;
let path = path.as_ref();
let dir = path
.parent()
.filter(|dir| !dir.as_os_str().is_empty())
.unwrap_or(Path::new("."));
let mut file = tempfile::NamedTempFile::new_in(dir).map_err(|source| FsError::FileCreate {
path: path.to_path_buf(),
source,
})?;
file.write_all(contents.as_ref())
.and_then(|()| file.as_file().sync_all())
.map_err(|source| FsError::Write {
path: path.to_path_buf(),
source,
})?;
file.persist(path).map_err(|err| FsError::Write {
path: path.to_path_buf(),
source: err.error,
})?;
Ok(())
}
pub(crate) fn copy(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<u64, FsError> {
let from = from.as_ref();
let to = to.as_ref();
fs::copy(from, to).map_err(|source| FsError::Copy {
from: from.to_path_buf(),
to: to.to_path_buf(),
source,
})
}
pub(crate) fn hard_link(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<(), FsError> {
let from = from.as_ref();
let to = to.as_ref();
fs::hard_link(from, to).map_err(|source| FsError::HardLink {
from: from.to_path_buf(),
to: to.to_path_buf(),
source,
})
}
pub(crate) fn link_dir_all(src: &Path, dest: &Path) -> Result<(), FsError> {
create_dir_all(dest)?;
for entry in read_dir(src)? {
let entry = entry?;
let from = entry.path();
let to = dest.join(entry.file_name());
if from.is_dir() {
link_dir_all(&from, &to)?;
} else {
hard_link(&from, &to)?;
}
}
Ok(())
}
pub(crate) fn create_dir_all(path: impl AsRef<Path>) -> Result<(), FsError> {
let path = path.as_ref();
fs::create_dir_all(path).map_err(|source| FsError::CreateDirAll {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn remove_file(path: impl AsRef<Path>) -> Result<(), FsError> {
let path = path.as_ref();
fs::remove_file(path).map_err(|source| FsError::RemoveFile {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn remove_dir_all(path: impl AsRef<Path>) -> Result<(), FsError> {
let path = path.as_ref();
fs::remove_dir_all(path).map_err(|source| FsError::RemoveDirAll {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn read_dir(
path: impl AsRef<Path>,
) -> Result<impl Iterator<Item = Result<DirEntry, FsError>>, FsError> {
let path = path.as_ref();
fs::read_dir(path)
.map_err(|source| FsError::ReadDir {
path: path.to_path_buf(),
source,
})
.map(|entries| {
let path = path.to_path_buf();
entries.map(move |entry| {
entry.map_err(|source| FsError::ReadDir {
path: path.clone(),
source,
})
})
})
}
pub(crate) fn open(path: impl AsRef<Path>) -> Result<fs::File, FsError> {
let path = path.as_ref();
fs::File::open(path).map_err(|source| FsError::FileOpen {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn create(path: impl AsRef<Path>) -> Result<fs::File, FsError> {
let path = path.as_ref();
fs::File::create(path).map_err(|source| FsError::FileCreate {
path: path.to_path_buf(),
source,
})
}
pub(crate) fn absolute(path: impl AsRef<Path>) -> Result<PathBuf, FsError> {
let path = path.as_ref();
std::path::absolute(path).map_err(|source| FsError::GetAbsolutePath {
path: path.to_path_buf(),
source,
})
}