fluidattacks-core 0.1.5

Fluid Attacks Core Library
Documentation
use anyhow::Result;
use ignore::gitignore::GitignoreBuilder;
use std::fs;
use std::path::Path;
use walkdir::WalkDir;

pub fn remove_symlinks(dir: &Path) -> Result<()> {
    for entry in WalkDir::new(dir) {
        let entry = entry?;
        let metadata = entry.path().symlink_metadata()?;
        if metadata.file_type().is_symlink() {
            fs::remove_file(entry.path())?;
        }
    }
    Ok(())
}

pub fn delete_gitignored_files(repo_path: &Path, patterns: &[String]) -> Result<()> {
    let mut builder = GitignoreBuilder::new(repo_path);
    for pattern in patterns {
        builder.add_line(None, pattern)?;
    }
    let gitignore = builder.build()?;

    for entry in WalkDir::new(repo_path) {
        let entry = entry?;
        let path = entry.path();

        let rel = match path.strip_prefix(repo_path) {
            Ok(r) => r,
            Err(_) => continue,
        };

        let rel_str = rel.to_string_lossy();

        if rel_str == ".git" || rel_str.starts_with(".git/") || rel_str.starts_with(".git\\") {
            continue;
        }

        if rel_str.is_empty() {
            continue;
        }

        if !entry.file_type().is_dir() && gitignore.matched(rel, false).is_ignore() {
            let _ = fs::remove_file(path);
        }
    }

    remove_empty_dirs(repo_path)?;
    Ok(())
}

pub fn copy_dir_all(src: &Path, dst: &Path) -> Result<()> {
    fs::create_dir_all(dst)?;
    for entry in fs::read_dir(src)? {
        let entry = entry?;
        let ty = entry.file_type()?;
        let dst_path = dst.join(entry.file_name());
        if ty.is_dir() {
            copy_dir_all(&entry.path(), &dst_path)?;
        } else {
            fs::copy(entry.path(), &dst_path)?;
        }
    }
    Ok(())
}

fn remove_empty_dirs(root: &Path) -> Result<()> {
    let mut dirs: Vec<_> = Vec::new();

    for entry in WalkDir::new(root) {
        let entry = entry?;
        let path = entry.path();

        let rel = match path.strip_prefix(root) {
            Ok(r) => r,
            Err(_) => continue,
        };

        let rel_str = rel.to_string_lossy();

        if rel_str == ".git" || rel_str.starts_with(".git/") || rel_str.starts_with(".git\\") {
            continue;
        }

        if entry.file_type().is_dir() && path != root {
            dirs.push(path.to_path_buf());
        }
    }

    dirs.sort();
    dirs.reverse();

    for dir in dirs {
        if let Ok(entries) = fs::read_dir(&dir) {
            if entries.count() == 0 {
                let _ = fs::remove_dir(&dir);
            }
        }
    }

    Ok(())
}