summaryrefslogtreecommitdiffstats
path: root/src/package/script.rs
blob: 968f3642e563fba85267263e92838e0e0894de8f (plain)
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
use anyhow::Error;
use anyhow::Result;
use handlebars::Handlebars;
use serde::Deserialize;
use serde::Serialize;

use crate::package::Package;
use crate::phase::Phase;
use crate::phase::PhaseName;

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(transparent)]
pub struct Script(String);

#[derive(Clone, Debug)]
pub struct Shebang(String);

impl From<String> for Shebang {
    fn from(s: String) -> Self {
        Shebang(s)
    }
}

impl AsRef<str> for Script {
    fn as_ref(&self) -> &str {
        self.0.as_ref()
    }
}

pub struct ScriptBuilder<'a> {
    shebang: &'a Shebang,
}

impl<'a> ScriptBuilder<'a> {
    pub fn new(shebang: &'a Shebang) -> Self {
        ScriptBuilder {
            shebang,
        }
    }

    pub fn build(self, package: &Package, phaseorder: &Vec<PhaseName>, strict_mode: bool) -> Result<Script> {
        let mut script = format!("{shebang}\n", shebang = self.shebang.0);

        for name in phaseorder {
            match package.phases().get(name) {
                Some(Phase::Text(text)) => {
                    script.push_str(&indoc::formatdoc!(r#"
                        ### phase {}
                        {}
                        ### / {} phase
                    "#,
                    name.as_str(),
                    text,
                    name.as_str(),
                    ));

                    script.push_str("\n");
                },

                // TODO: Support path embedding
                // (requires possibility to have stuff in Script type that gets copied to
                // container)
                Some(Phase::Path(pb)) => {
                    script.push_str(&format!(r#"
                        # Phase (from file {path}): {name}
                        # NOT SUPPORTED YET
                        exit 1
                    "#,
                    path = pb.display(),
                    name = name.as_str()));

                    script.push_str("\n");
                },

                None => {
                    script.push_str(&format!("# No script for phase: {name}", name = name.as_str()));
                    script.push_str("\n");
                },
            }
        }

        Self::interpolate_package(script, package, strict_mode).map(Script)
    }

    fn interpolate_package(script: String, package: &Package, strict_mode: bool) -> Result<String> {
        let mut hb = Handlebars::new();
        hb.register_template_string("script", script)?;
        hb.set_strict_mode(strict_mode);
        hb.render("script", package).map_err(Error::from)
    }
}