summaryrefslogtreecommitdiff
path: root/src/templatespec.rs
blob: 7b8723bd33a1bab8bf1e10b5065b9860f69b901f (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
92
use crate::resource;
use crate::SubplotError;

use serde::Deserialize;

use std::path::{Path, PathBuf};

/// A template specification.
///
/// Contains the information codegen needs to use a template for
/// generating a test program. The names and types of fields match the
/// files in the `templates/.../template.yaml` files.
#[derive(Debug, Deserialize)]
pub struct TemplateSpec {
    template: PathBuf,
    #[serde(default)]
    helpers: Vec<PathBuf>,
    run: Option<String>,
}

impl TemplateSpec {
    // Create a new TemplateSpec from YAML text.
    fn from_yaml(yaml: &str) -> Result<TemplateSpec, SubplotError> {
        Ok(serde_yaml::from_str(yaml)?)
    }

    // Create a new TemplateSpec.
    fn new(
        basedir: &Path,
        template: &Path,
        helpers: Vec<PathBuf>,
        run: Option<&str>,
    ) -> TemplateSpec {
        TemplateSpec {
            template: basedir.to_path_buf().join(template),
            helpers,
            run: run.map(str::to_string),
        }
    }

    /// Read a template.yaml file and create the corresponding TemplateSpec.
    pub fn from_file(filename: &Path) -> Result<TemplateSpec, SubplotError> {
        let yaml = resource::read_as_string(filename, None)
            .map_err(|err| SubplotError::ReadFile(filename.to_path_buf(), err))?;
        let spec = TemplateSpec::from_yaml(&yaml)?;
        let dirname = match filename.parent() {
            Some(x) => x,
            None => {
                return Err(SubplotError::NoTemplateSpecDirectory(
                    filename.to_path_buf(),
                ))
            }
        };
        Ok(TemplateSpec::new(
            dirname,
            spec.template_filename(),
            spec.helpers().map(|p| p.to_path_buf()).collect(),
            spec.run(),
        ))
    }

    /// Return the name of the template file.
    pub fn template_filename(&self) -> &Path {
        &self.template
    }

    /// Return iterator for names of helper files.
    pub fn helpers(&self) -> impl Iterator<Item = &Path> {
        self.helpers.iter().map(|p| p.as_path())
    }

    /// Return command to run the generated test program, if specified.
    ///
    /// The name of the test program gets appended.
    pub fn run(&self) -> Option<&str> {
        self.run.as_deref()
    }
}

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

    #[test]
    fn new_from_yaml() {
        let yaml = "
template: template.py
";
        let spec = TemplateSpec::from_yaml(yaml).unwrap();
        assert_eq!(spec.template_filename().to_str().unwrap(), "template.py");
    }
}