smaug_lib/util/
dir.rs

1use ignore::gitignore::{Gitignore, GitignoreBuilder};
2use log::*;
3use std::fs;
4use std::io;
5use std::path::Path;
6use walkdir::WalkDir;
7
8pub fn copy_directory<P: AsRef<Path>>(source: &P, destination: P) -> io::Result<()> {
9    let mut ignore_builder = GitignoreBuilder::new(source);
10    let ignore_file = source.as_ref().join(".smaugignore");
11
12    if ignore_file.is_file() {
13        ignore_builder.add(ignore_file);
14    }
15
16    let ignore = ignore_builder
17        .build()
18        .expect("Could not parse smaugignore file");
19
20    for entry in WalkDir::new(source) {
21        let entry = entry.expect("Could not find directory");
22        let entry = entry.path();
23        let relative = entry.strip_prefix(source.as_ref()).unwrap();
24        let new_path = destination.as_ref().join(relative);
25
26        if entry.is_file() && !is_ignored(entry, &ignore) {
27            trace!(
28                "Creating directory {}",
29                new_path.parent().and_then(|p| p.to_str()).unwrap()
30            );
31            fs::create_dir_all(new_path.parent().unwrap())?;
32            trace!(
33                "Copying file from {} to {}",
34                entry.to_str().unwrap(),
35                new_path.to_str().unwrap()
36            );
37            fs::copy(entry, new_path)?;
38        }
39    }
40
41    Ok(())
42}
43
44fn is_git_dir(path: &str) -> bool {
45    path.contains("/.git/") || path.contains("\\.git\\")
46}
47
48fn is_ignored(path: &Path, ignore: &Gitignore) -> bool {
49    if matches_ignore(path, ignore) {
50        trace!("Ignoring {:?}", path);
51        return true;
52    }
53
54    false
55}
56
57fn matches_ignore(path: &Path, ignore: &Gitignore) -> bool {
58    ignore
59        .matched_path_or_any_parents(path, path.is_dir())
60        .is_ignore()
61        || is_git_dir(path.to_string_lossy().as_ref())
62}