use crate::prelude::*;
pub const FILE: &str = ".wsb/stamp.json";
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StampConfig {
pub declared: Option<PathBuf>,
pub build_root: Option<PathBuf>,
pub local: Option<LocalRendering>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LocalRendering {
pub variable: String,
#[serde(default)]
pub prepare: Option<Vec<String>>,
#[serde(default)]
pub release: Option<Vec<String>>,
}
impl StampConfig {
pub fn load(scan_root: &Path) -> Result<Option<Self>> {
let path = scan_root.join(FILE);
let text = match std::fs::read_to_string(&path) {
Ok(text) => text,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(error) => return Err(error).with_context(|| format!("cannot read {}", path.display())),
};
serde_json::from_str(&text)
.map(Some)
.with_context(|| format!("{} is not a valid stamp configuration", path.display()))
}
pub fn declared_file(scan_root: &Path) -> Result<PathBuf> {
Self::named(scan_root, "declared", |config| config.declared.as_ref())
}
pub fn build_root(scan_root: &Path) -> Result<PathBuf> {
Self::named(scan_root, "build_root", |config| config.build_root.as_ref())
}
pub fn local(scan_root: &Path) -> Result<LocalRendering> {
let path = scan_root.join(FILE);
match Self::load(scan_root)? {
None => bail!(
"a local render needs the variable that selects it, declared as \"local\" in {}, \
and there is no such file",
path.display()
),
Some(config) => config.local.ok_or_else(|| {
anyhow!(
"a local render needs the variable that selects it, and {} declares no \"local\"",
path.display()
)
}),
}
}
fn named(
scan_root: &Path,
key: &str,
pick: impl Fn(&Self) -> Option<&PathBuf>,
) -> Result<PathBuf> {
let path = scan_root.join(FILE);
match Self::load(scan_root)? {
None => bail!(
"a template asks for what {} would name as \"{key}\", and there is no {}",
FILE,
path.display()
),
Some(config) => match pick(&config) {
Some(relative) => Ok(scan_root.join(relative)),
None => bail!(
"a template asks for what {} names as \"{key}\", and it names none",
path.display()
),
},
}
}
}
#[cfg(test)]
#[path = "stamp_config_tests.rs"]
mod tests;