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
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use tinytemplate::TinyTemplate;

use crate::config::{Context, Dependencies};

fn build_template() -> String {
    fs::read_to_string(
        PathBuf::from("src")
            .join("templates")
            .join("elixir")
            .join("mix.exs.tmpl"),
    )
    .unwrap()
}

fn source_template() -> String {
    fs::read_to_string(
        PathBuf::from("src")
            .join("templates")
            .join("elixir")
            .join("parser.ex.tmpl"),
    )
    .unwrap()
}

fn generate_templates(deps: Dependencies) -> Vec<(&'static str, String)> {
    let build = build_template();
    let source = source_template();

    let mut template = TinyTemplate::new();
    template.add_template("mix.exs", &build).unwrap();
    template.add_template("parser.ex", &source).unwrap();

    let build_template = template
        .render("mix.exs", &Context { deps: deps.clone() })
        .unwrap();

    let source_template = template
        .render("parser.ex", &Context { deps })
        .unwrap();

    let mut templates = Vec::new();

    templates.push(("mix.exs", build_template));
    templates.push(("lib/parser.ex", source_template));

    templates
}

pub fn write_project(path: String, deps: Dependencies) -> Result<(), String> {
    println!("Generating mix project...");

    let folder_path = PathBuf::from(path);

    let templates = generate_templates(deps.clone());

    let (build_path, build_template) = templates.get(0).unwrap();
    let (source_path, source_template) = templates.get(1).unwrap();

    fs::create_dir_all(folder_path.clone())
        .map_err(|err| format!("Failed to create dir: {}", err))
        .and_then(|_| {
            env::set_current_dir(folder_path.clone())
                .map_err(|err| format!("Failed to set cwd: {}", err))
        })
        .and_then(|_| {
            fs::write(build_path, build_template)
                .map_err(|err| format!("Failed to write `mix.exs`: {}", err))
        })
        .and_then(|_| {
            fs::create_dir(PathBuf::from("lib"))
                .map_err(|err| format!("Failed to create `lib` dir: {}", err))
        })
        .and_then(|_| {
            fs::write(source_path, source_template)
                .map_err(|err| format!("Failed to write `lib/parser.ex`: {}", err))
        })
}

pub fn run(shell: bool) -> Result<(), String> {
    let stdout = os_pipe::dup_stdout().unwrap();
    let mut mix = match Command::new("mix")
        .args(&["do", "deps.get,", "deps.compile"])
        .stdout(stdout)
        .spawn()
    {
        Err(error) => panic!("Failed to spawn `mix` process: {}", error),
        Ok(process) => process,
    };

    let _ = mix.wait();

    if shell {
        let stdout = os_pipe::dup_stdout().unwrap();
        let mut iex_command = match Command::new("iex")
            .args(&["-S", "mix"])
            .stdout(stdout)
            .stdin(os_pipe::dup_stdin().unwrap())
            .spawn()
        {
            Err(error) => panic!("Failed to run `iex` shell: {}", error),
            Ok(process) => process,
        };

        let _ = iex_command.wait();
    }

    Ok(())
}