subscribe-list/build.rs

80 lines
2.9 KiB
Rust

use regex::Regex;
use std::{collections::HashSet, env, error::Error, fs, path::Path, process::Command};
fn escape_template(v: &str) -> Result<String, String> {
let cant_escape = "\\{";
if v.contains(cant_escape) {
return Err(format!("can't escape {cant_escape}"));
}
Ok(v.replace("{", "\\{"))
}
fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed=migrations");
println!("cargo:rerun-if-changed=website");
let out_dir = env::var_os("OUT_DIR").unwrap();
let website_dir = Path::new(&out_dir).join("website");
let templates_dir = Path::new(&out_dir).join("templates");
fs::create_dir_all(&templates_dir)?;
let status = Command::new("mdbook")
.arg("build")
.arg("--dest-dir")
.arg(&website_dir)
.current_dir("website")
.status()
.map_err(|e| format!("Can't run mdbook: {e}"))?;
if !status.success() {
return Err(format!("mdbook exited with an error: {status:?}").into());
}
let sub_template_path = website_dir.join("subscription/index.html");
let sub_template = fs::read_to_string(&sub_template_path)
.map_err(|e| format!("Error reading {}: {e}", sub_template_path.display()))?;
let regex = Regex::new(r#"(?s)<div class="subscribe_list_template_section" id="(?<id>[^"]*)"/>(?<template>.*?)<div class="subscribe_list_template_section"/>"#).unwrap();
let matches = Vec::from_iter(regex.captures_iter(&sub_template));
let mut between_matches = vec![];
let mut last_end = 0;
for m in &matches {
let m = m.get(0).unwrap();
between_matches.push(&sub_template[last_end..m.start()]);
last_end = m.end();
}
between_matches.push(&sub_template[last_end..]);
let prefix = between_matches.remove(0);
let Some(suffix) = between_matches.pop() else {
return Err(format!(
"no subscribe_list_template_section `div`s found: {}",
sub_template_path.display()
)
.into());
};
let prefix = escape_template(prefix)?;
let suffix = escape_template(suffix)?;
for i in between_matches {
if i.trim_start() != "" {
return Err(format!(
r#"can't have non-whitespace text between
<div class="subscribe_list_template_section"/>
and next
<div class="subscribe_list_template_section" id="..">"#
)
.into());
}
}
let mut identifiers = HashSet::new();
for m in &matches {
let id = &m["id"];
if id.contains(|ch: char| !ch.is_ascii_alphanumeric() && ch != '_') {
return Err(format!("invalid identifier {id:?}").into());
}
if !identifiers.insert(id) {
return Err(format!("duplicate identifier {id:?}").into());
}
let template = &m["template"];
fs::write(
templates_dir.join(format!("{id}.txt")),
prefix.clone() + template + &suffix,
)?;
}
Ok(())
}