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
pub mod build;
pub mod channel;
pub mod env;
pub mod err;
pub mod git;

use build::*;
use env::*;
use err::*;
use git::*;

use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::Path;

const SHADOW_RS: &str = "shadow.rs";

#[derive(Debug)]
pub struct Shadow {
    f: File,
    map: HashMap<ShadowConst, RefCell<ConstVal>>,
}

impl Shadow {
    pub fn new(src_path: String, out_path: String) -> SdResult<()> {
        let src_path = Path::new(src_path.as_str());
        let out_path = Path::new(out_path.as_str()).join(SHADOW_RS);

        let mut map = Git::new(&src_path);
        for (k, v) in Project::new() {
            map.insert(k, v);
        }
        for (k, v) in SystemEnv::new() {
            map.insert(k, v);
        }

        let mut shadow = Shadow {
            f: File::create(out_path)?,
            map,
        };
        shadow.gen_const()?;
        println!("shadow build success");
        Ok(())
    }

    fn gen_const(&mut self) -> SdResult<()> {
        self.write_header()?;
        for (k, v) in self.map.clone() {
            self.write_const(k, v)?;
        }
        Ok(())
    }

    fn write_header(&self) -> SdResult<()> {
        let desc = r#"// Code generated by shadow-rs generator. DO NOT EDIT."#;
        writeln!(&self.f, "{}\n\n", desc)?;
        Ok(())
    }

    fn write_const(&mut self, shadow_const: ShadowConst, val: RefCell<ConstVal>) -> SdResult<()> {
        let val = val.into_inner();
        let desc = format!("// {}", val.desc);
        let define = format!(
            "pub const {} :{} = \"{}\";",
            shadow_const.to_ascii_uppercase(),
            val.t.to_string(),
            val.v
        );
        writeln!(&self.f, "{}", desc)?;
        writeln!(&self.f, "{}\n", define)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_build() -> SdResult<()> {
        Shadow::new("./".into(), "./".into())?;
        Ok(())
    }
}