pub mod extract;
pub mod generate;
mod structs;
use std::{
error::Error,
fs,
path::{Path, PathBuf},
process::Command,
};
pub fn extract(rel_stencils_dir: &str) -> Result<(), Box<dyn Error>> {
let out_dir = std::env::var("OUT_DIR")?;
let out_path = Path::new(&out_dir).canonicalize()?;
let target_dir = find_target_dir(&out_path)?.join("patchouly");
let current_dir = std::env::current_dir()?;
let stencils_dir = current_dir
.as_path()
.parent()
.ok_or("expected to be in a workspace")?
.join(rel_stencils_dir)
.canonicalize()?;
assert!(
stencils_dir.exists(),
"stencils dir {} does not exist",
stencils_dir.display()
);
let status = Command::new("cargo")
.current_dir(&stencils_dir)
.args([
"rustc",
"--release",
"--lib",
"--target-dir",
target_dir.to_str().unwrap(),
"--",
"-C",
"relocation-model=static",
])
.status()?;
if !status.success() {
return Err("failed to compile stencils crate".into());
}
println!("cargo:rerun-if-changed={}/src", stencils_dir.display());
let rlib = target_dir.join("release").join(dir_to_libname(&stencils_dir)?);
let extraction = extract::extract(&rlib)?;
generate::generate(extraction, &out_path)?;
Ok(())
}
fn dir_to_libname(rel: &Path) -> Result<String, Box<dyn Error>> {
let manifest = fs::read_to_string(rel.join("Cargo.toml"))?;
let name = manifest
.lines()
.map(str::trim)
.find_map(|line| {
line.strip_prefix("name = ")
.map(|value| value.trim_matches('"'))
})
.ok_or("package name not found in stencils Cargo.toml")?;
Ok(format!("lib{}.rlib", name.replace("-", "_")))
}
fn find_target_dir(out_dir: &Path) -> Result<PathBuf, Box<dyn Error>> {
let profile = std::env::var("PROFILE")?;
for parent in out_dir.ancestors() {
if parent.ends_with(&profile) {
return Ok(parent.parent().ok_or("failed to find target dir")?.to_path_buf());
}
}
Err("failed to find target dir".into())
}