mod unix;
use std::{io, os::unix::fs::DirBuilderExt, path::Path};
#[cfg(unix)]
use unix as sys;
pub struct DirBuilder {
recursive: bool,
inner: sys::BuilderInner,
}
impl DirBuilder {
pub fn new() -> Self {
Self {
recursive: false,
inner: sys::BuilderInner::new(),
}
}
pub fn recursive(&mut self, recursive: bool) -> &mut Self {
self.recursive = recursive;
self
}
pub async fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
if self.recursive {
self.create_dir_all(path.as_ref()).await
} else {
self.inner.mkdir(path.as_ref()).await
}
}
async fn create_dir_all(&self, path: &Path) -> io::Result<()> {
if path == Path::new("") {
return Ok(());
}
let mut inexist_path = path;
let mut need_create = vec![];
while match self.inner.mkdir(inexist_path).await {
Ok(()) => false,
Err(ref e) if e.kind() == io::ErrorKind::NotFound => true,
Err(_) if is_dir(inexist_path).await => false,
Err(e) => return Err(e),
} {
match inexist_path.parent() {
Some(p) => {
need_create.push(inexist_path);
inexist_path = p;
}
None => {
return Err(io::Error::new(
io::ErrorKind::Other,
"failed to create whole tree",
))
}
}
}
for p in need_create.into_iter().rev() {
self.inner.mkdir(p).await?;
}
Ok(())
}
}
impl Default for DirBuilder {
fn default() -> Self {
Self::new()
}
}
impl DirBuilderExt for DirBuilder {
fn mode(&mut self, mode: u32) -> &mut Self {
self.inner.set_mode(mode);
self
}
}
async fn is_dir(path: &Path) -> bool {
std::fs::metadata(path).is_ok_and(|metadata| metadata.is_dir())
}