pulith-fs 0.1.0

Cross-platform atomic filesystem primitives
Documentation
use crate::{Error, Result};
use std::fs;
use std::path::Path;

pub fn copy_dir_all(src: impl AsRef<Path>, dest: impl AsRef<Path>) -> Result<()> {
    let src = src.as_ref();
    let dest = dest.as_ref();

    if !dest.exists() {
        fs::create_dir_all(dest).map_err(|e| Error::Write {
            path: dest.to_path_buf(),
            source: e,
        })?;
    }

    for entry in fs::read_dir(src).map_err(|e| Error::Read {
        path: src.to_path_buf(),
        source: e,
    })? {
        let entry = entry.map_err(|e| Error::Read {
            path: src.to_path_buf(),
            source: e,
        })?;
        let file_type = entry.file_type().map_err(|e| Error::Read {
            path: entry.path(),
            source: e,
        })?;

        let src_path = entry.path();
        let dest_path = dest.join(entry.file_name());

        if file_type.is_dir() {
            copy_dir_all(&src_path, &dest_path)?;
        } else if file_type.is_symlink() {
            let target = fs::read_link(&src_path).map_err(|e| Error::Read {
                path: src_path,
                source: e,
            })?;
            crate::primitives::symlink::atomic_symlink(target, &dest_path)?;
        } else {
            fs::copy(&src_path, &dest_path).map_err(|e| Error::Write {
                path: dest_path,
                source: e,
            })?;
        }
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;

    #[test]
    fn test_copy_dir_all() {
        let dir = tempdir().unwrap();
        let src = dir.path().join("src");
        let dest = dir.path().join("dest");
        std::fs::create_dir_all(src.join("subdir")).unwrap();
        std::fs::write(src.join("file.txt"), "data").unwrap();
        std::fs::write(src.join("subdir/nested.txt"), "nested").unwrap();

        copy_dir_all(&src, &dest).unwrap();
        assert!(dest.join("file.txt").exists());
        assert!(dest.join("subdir/nested.txt").exists());
    }
}