use chrono::{Datelike, Utc};
use crate::manifest;
use crate::package;
use crate::Error;
use crate::Result;
use crate::Template;
use log::debug;
use mustache::{self, MapBuilder};
use std::path::PathBuf;
use cargo_metadata::Package;
use super::RenderOutput;
#[derive(Debug, Clone)]
pub struct Builder<'a> {
copyright_year: Option<&'a str>,
copyright_holder: Option<&'a str>,
input: Option<&'a str>,
output: Option<&'a str>,
package: Option<&'a str>,
}
impl<'a> Builder<'a> {
pub fn new() -> Self {
Builder {
copyright_year: None,
copyright_holder: None,
input: None,
output: None,
package: None,
}
}
pub fn copyright_holder(&mut self, h: Option<&'a str>) -> &mut Self {
self.copyright_holder = h;
self
}
pub fn copyright_year(&mut self, y: Option<&'a str>) -> &mut Self {
self.copyright_year = y;
self
}
pub fn input(&mut self, i: Option<&'a str>) -> &mut Self {
self.input = i;
self
}
pub fn output(&mut self, o: Option<&'a str>) -> &mut Self {
self.output = o;
self
}
pub fn package(&mut self, o: Option<&'a str>) -> &mut Self {
self.package = o;
self
}
pub fn build(&self) -> Execution {
Execution {
copyright_holder: self.copyright_holder.map(String::from),
copyright_year: self.copyright_year.map(String::from),
input: self.input.map(PathBuf::from),
output: self.output.map(PathBuf::from),
package: self.package.map(PathBuf::from),
}
}
}
impl<'a> Default for Builder<'a> {
fn default() -> Self {
Builder::new()
}
}
#[derive(Debug)]
pub struct Execution {
copyright_holder: Option<String>,
copyright_year: Option<String>,
input: Option<PathBuf>,
output: Option<PathBuf>,
package: Option<PathBuf>,
}
impl Execution {
pub fn run(self, template: &Template) -> Result<()> {
let render = self.render(template)?;
render.write()?;
Ok(())
}
pub fn render(self, template: &Template) -> Result<RenderOutput> {
debug!("copyright_holder = {:?}", self.copyright_holder);
debug!("copyright_year = {:?}", self.copyright_year);
debug!("input = {:?}", self.input);
debug!("output = {:?}", self.output);
let manifest = manifest(self.input.as_ref())?;
let package = package(&manifest, self.package.as_ref().and_then(|p| p.to_str()))?;
let template = mustache::compile_str(template.to_str())?;
let data = MapBuilder::new()
.insert_str("copyright-year", self.copyright_year())
.insert_str("copyright-holder", self.copyright_holder(&package)?)
.build();
let rendered = template.render_data_to_string(&data).map_err(Error::from)?;
Ok(RenderOutput {
path: self.output,
rendered,
})
}
fn copyright_holder(&self, manifest: &Package) -> Result<String> {
if let Some(ref h) = self.copyright_holder {
Ok(h.to_owned())
} else {
super::authors(manifest)
}
}
fn copyright_year(&self) -> String {
self.copyright_year
.clone()
.map(String::from)
.unwrap_or_else(|| Utc::now().year().to_string())
}
}
impl Default for Execution {
fn default() -> Self {
Builder::new().build()
}
}
#[cfg(test)]
mod tests {
use super::*;
mod builder {
use super::*;
#[test]
fn copyright_holder_works() {
const EXPECTED: &str = "Example";
let mut actual = Builder::new();
actual.copyright_holder(Some(EXPECTED));
assert_eq!(actual.copyright_holder, Some(EXPECTED));
}
#[test]
fn copyright_year_works() {
const EXPECTED: &str = "1982";
let mut actual = Builder::new();
actual.copyright_year(Some(EXPECTED));
assert_eq!(actual.copyright_year, Some(EXPECTED));
}
#[test]
fn input_works() {
const EXPECTED: &str = "Example.wxs";
let mut actual = Builder::new();
actual.input(Some(EXPECTED));
assert_eq!(actual.input, Some(EXPECTED));
}
#[test]
fn output_works() {
const EXPECTED: &str = "C:\\Example\\output";
let mut actual = Builder::new();
actual.output(Some(EXPECTED));
assert_eq!(actual.output, Some(EXPECTED));
}
}
mod execution {
use super::*;
const MIN_MANIFEST: &str = r#"{
"name": "Example",
"version": "0.1.0",
"authors": ["First Last <first.last@example.com>"],
"id": "",
"dependencies": [],
"targets": [],
"features": {},
"manifest_path": ""
}"#;
#[test]
fn copyright_holder_works() {
let manifest = serde_json::from_str(MIN_MANIFEST).expect("Parsing TOML");
let actual = Execution::default().copyright_holder(&manifest).unwrap();
assert_eq!(actual, String::from("First Last"));
}
#[test]
fn copyright_holder_with_override_works() {
const EXPECTED: &str = "Dr. Example";
let manifest = serde_json::from_str(MIN_MANIFEST).expect("Parsing TOML");
let actual = Builder::new()
.copyright_holder(Some(EXPECTED))
.build()
.copyright_holder(&manifest)
.unwrap();
assert_eq!(actual, String::from(EXPECTED));
}
#[test]
fn copyright_year_works() {
let actual = Execution::default().copyright_year();
assert_eq!(actual, Utc::now().year().to_string());
}
#[test]
fn copyright_year_with_override_works() {
const EXPECTED: &str = "1982";
let actual = Builder::new()
.copyright_year(Some(EXPECTED))
.build()
.copyright_year();
assert_eq!(actual, String::from(EXPECTED));
}
}
}