1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use std::fs;
use std::io::{Result, Write};
use std::path::{Path, PathBuf};

use serde_json::{self, Value};

use super::{deep_merge::merge, sort_dependencied::sort};

pub fn render_template(src: &PathBuf, dest: &PathBuf) -> Result<()> {
    match fs::metadata(src) {
        Ok(stats) if stats.is_dir() => {
            if src.file_name() == Some("node_modules".as_ref()) {
                return Ok(());
            }

            fs::create_dir_all(dest)?;

            for entry in fs::read_dir(src)? {
                let entry = entry?;
                let src_path = entry.path();
                let dest_path = dest.join(entry.file_name());
                render_template(&src_path, &dest_path)?;
            }

            Ok(())
        }
        Ok(_) => {
            let file_name = Path::new(src).file_name().unwrap().to_str().unwrap();

            if file_name == "package.json" {
                if fs::metadata(&dest).is_ok() {
                    let existing_contents = fs::read_to_string(&dest).unwrap_or_default();
                    let existing: Value = serde_json::from_str(&existing_contents).unwrap();

                    let new_contents = fs::read_to_string(&src).unwrap_or_default();
                    let new_package: Value = serde_json::from_str(&new_contents).unwrap();

                    let mut package_json = merge(&existing, &new_package);
                    let pkg = sort(&mut package_json);
                    let pkg = serde_json::to_string_pretty(&pkg)?;
                    let mut file = fs::File::create(&dest)?;
                    file.write_all(pkg.as_bytes())?;
                    return Ok(());
                } else {
                    fs::copy(src, dest)?;
                }
            }

            if file_name.starts_with('_') {
                let parent_dir = dest.parent().unwrap();
                let new_filename = file_name.replacen('_', ".", 1);
                let dest_path = parent_dir.join(new_filename);

                if let ("_gitignore", Ok(_)) = (file_name, fs::metadata(&dest_path)) {
                    let existing = fs::read_to_string(&dest_path).unwrap_or_default();
                    let new_gitignore = fs::read_to_string(src).unwrap_or_default();
                    fs::write(&dest_path, existing + "\n" + &new_gitignore)?;
                    return Ok(());
                }

                if !fs::metadata(&dest).is_ok() {
                    fs::write(&dest, "\n")?;
                }
                fs::rename(&dest, &dest_path)?;
                fs::copy(src, &dest_path)?;

                return Ok(());
            }

            let dest_filename = Path::new(dest).file_name().unwrap().to_str().unwrap();
            if !fs::metadata(&dest).is_ok() && dest_filename != "package.json" {
                fs::write(&dest, "\n")?;
            }

            if dest_filename != "package.json" {
                fs::copy(src, dest)?;
            }

            Ok(())
        }
        Err(e) => Err(e),
    }
}