smaug-lib 0.5.0

The library for interacting with Smaug projects
Documentation
use ignore::gitignore::{Gitignore, GitignoreBuilder};
use log::*;
use std::fs;
use std::io;
use std::path::Path;
use walkdir::WalkDir;

pub fn copy_directory<P: AsRef<Path>>(source: &P, destination: P) -> io::Result<()> {
    let mut ignore_builder = GitignoreBuilder::new(source);
    let ignore_file = source.as_ref().join(".smaugignore");

    if ignore_file.is_file() {
        ignore_builder.add(ignore_file);
    }

    let ignore = ignore_builder
        .build()
        .expect("Could not parse smaugignore file");

    for entry in WalkDir::new(source) {
        let entry = entry.expect("Could not find directory");
        let entry = entry.path();
        let relative = entry.strip_prefix(source.as_ref()).unwrap();
        let new_path = destination.as_ref().join(relative);

        if entry.is_file() && !is_ignored(entry, &ignore) {
            trace!(
                "Creating directory {}",
                new_path.parent().and_then(|p| p.to_str()).unwrap()
            );
            fs::create_dir_all(new_path.parent().unwrap())?;
            trace!(
                "Copying file from {} to {}",
                entry.to_str().unwrap(),
                new_path.to_str().unwrap()
            );
            fs::copy(entry, new_path)?;
        }
    }

    Ok(())
}

fn is_git_dir(path: &str) -> bool {
    path.contains("/.git/") || path.contains("\\.git\\")
}

fn is_ignored(path: &Path, ignore: &Gitignore) -> bool {
    if matches_ignore(path, ignore) {
        trace!("Ignoring {:?}", path);
        return true;
    }

    false
}

fn matches_ignore(path: &Path, ignore: &Gitignore) -> bool {
    ignore
        .matched_path_or_any_parents(path, path.is_dir())
        .is_ignore()
        || is_git_dir(path.to_string_lossy().as_ref())
}