extern crate handlebars;
extern crate serde_json;
extern crate toml;
use serde_json::value::Map;
use std::env;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::result;
#[derive(Debug)]
pub enum Error {
Message(&'static str),
Io(::std::io::Error),
Fmt(::std::fmt::Error),
Render(handlebars::RenderError),
Template(handlebars::TemplateError),
TomlDe(toml::de::Error),
Env(env::VarError),
}
impl From<&'static str> for Error {
fn from(value: &'static str) -> Error {
Error::Message(value)
}
}
impl From<::std::io::Error> for Error {
fn from(value: ::std::io::Error) -> Error {
Error::Io(value)
}
}
impl From<::std::fmt::Error> for Error {
fn from(value: ::std::fmt::Error) -> Error {
Error::Fmt(value)
}
}
impl From<env::VarError> for Error {
fn from(value: env::VarError) -> Error {
Error::Env(value)
}
}
impl From<handlebars::RenderError> for Error {
fn from(value: handlebars::RenderError) -> Error {
Error::Render(value)
}
}
impl From<handlebars::TemplateError> for Error {
fn from(value: handlebars::TemplateError) -> Error {
Error::Template(value)
}
}
impl From<toml::de::Error> for Error {
fn from(value: toml::de::Error) -> Error {
Error::TomlDe(value)
}
}
type Result<T> = result::Result<T, Error>;
fn read_file(path: &str) -> String {
let mut f = File::open(path)
.map_err(|e| format!("cannot open: {}: {}", path, e))
.unwrap();
let mut content = String::new();
f.read_to_string(&mut content).unwrap();
content
}
fn process_colors() -> Result<()> {
let out_dir = env::var("OUT_DIR")?;
let out_path = Path::new(&out_dir);
let colors_content = read_file("themes.toml");
let template_content = read_file("src/static/doc._.css.hbs");
let value: toml::Value = colors_content.parse()?;
let schemes = value
.as_table()
.ok_or_else(|| Error::Message("not a table"))?;
let mut handlebar = handlebars::Handlebars::new();
handlebar.register_template_string("doc", template_content)?;
let mut entries = Vec::new();
let mut themes = String::new();
let default = schemes
.get("default")
.unwrap()
.as_table()
.ok_or_else(|| Error::Message("not a table"))?;
for (key, value) in schemes {
if key == "default" {
continue;
}
let mut colors_in = default.clone();
colors_in.extend(
value
.as_table()
.ok_or_else(|| Error::Message("not a table"))?
.clone(),
);
let mut colors = Map::new();
for (k, color) in colors_in {
let value = color
.as_str()
.ok_or_else(|| Error::Message("expected string"))?;
colors.insert(k.to_owned(), handlebars::to_json(&value));
}
let result = handlebar.render("doc", &colors)?;
let key_upper = key.to_uppercase();
let name = format!("doc.{}.css", key);
writeln!(
themes,
"const DOC_CSS_{}: &[u8] = include_bytes!(concat!(env!(\"OUT_DIR\"), \"/{}\"));",
key_upper, name
)?;
entries.push(format!("(\"{}\", DOC_CSS_{})", key, key_upper));
let mut f = File::create(out_path.join(name))?;
f.write_all(&result.into_bytes())?;
}
writeln!(themes, "")?;
writeln!(
themes,
"pub fn build_themes_vec() -> Vec<(&'static str, &'static [u8])> {{"
)?;
writeln!(themes, " vec![{}]", entries.join(", "))?;
writeln!(themes, "}}")?;
let mut themes_file = File::create(out_path.join("themes.rs"))?;
themes_file.write_all(&themes.into_bytes())?;
Ok(())
}
fn main() {
println!("cargo:rerun-if-changed=themes.toml");
println!("cargo:rerun-if-changed=src/static/doc._.css.hbs");
println!("cargo:rerun-if-changed=src/static/normalize.css");
process_colors().unwrap();
}