summaryrefslogtreecommitdiffstats
path: root/src/conf.rs
blob: eec5d864b5dab48f02c75acfef73cdba56521b36 (plain) (blame)
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
use serde_derive::{Serialize, Deserialize};
use std::path::{ PathBuf, Path };
use toml::de;
use log::{ error, trace };
use std::io::prelude::*;

type Error = std::io::Error;
use std::io::ErrorKind;

use crate::backends::{ Backend, PythonBackend, ClangBackend };


#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Conf {
    #[serde(skip)]
    path: Option<PathBuf>,

    #[serde(default)]
    python: PythonBackend,

    #[serde(default)]
    clang: ClangBackend
}


impl Conf {
    pub fn get_template(&self, fname: &Path) -> &str {
        self.get_backend(fname)
            .and_then(|backend| backend.get_template())
            .unwrap_or("")
    }

    pub fn get_backend(&self, fname: &Path) -> Option<Box<&dyn Backend>> {
        let ext = fname.extension()
                       .and_then(|ext| ext.to_str())
                       .unwrap_or("");

        match ext {
            "py" => Some(Box::new(&self.python)),
            "cc" | "cpp" | "cxx" => Some(Box::new(&self.clang)),
            _ => None
        }
    }

    pub fn run(&self, fname: &Path) -> std::io::Result<()> {
        self.get_backend(fname)
            .and_then(|backend| Some(backend.run(fname)))
            .unwrap_or(Err(Error::new(ErrorKind::InvalidData, "Backend not found")))
    }

    pub fn make(&self, fname: &Path) -> std::io::Result<()> {
        trace!("Template: {:?}", self.get_template(&fname));

        std::fs::File::create(fname)?
            .write_all(self.get_template(fname).as_bytes())?;

        trace!("Written some bytes to {}", fname.to_string_lossy());
        Ok(())
    }

    #[allow(unused)]
    pub fn get_compiler_args(&self) -> String {
        "somedef".to_string()
    }
}



pub fn get_conf() -> Conf {
    match get_conf_maybe() {
        Ok(c) => c,
        Err(e) => {
            match e.kind() {
                ErrorKind::InvalidData => error!("parse: {}", e),
                _ => error!("{}", e)
            };
            Default::default()
        }
    }
}


pub fn get_conf_maybe() -> Result<Conf, Error> {
    let mut current = std::env::current_dir()?;
    let path = loop {
        let candidate = current.join(".evr");
        if candidate.exists() {
            break candidate;
        }

        if !current.pop() {
            error!("Not a evr subtree.");
            return Err(Error::new(ErrorKind::NotFound, "Not a evr subtree"));
        }
    };

    let raw_buf = std::fs::read_to_string(path.as_path())?;

    let buf_result: Result<Conf, de::Error> = de::from_str(&raw_buf);

    match buf_result {
        Ok(mut buf) => {
            buf.path = Some(path.clone());
            Ok(buf)
        },
        Err(err) => {
            Err(Error::new(ErrorKind::InvalidData, err))
        }
    }
}