1pub mod extract;
2pub mod generate;
3mod structs;
4
5use std::{
6 error::Error,
7 fs,
8 path::{Path, PathBuf},
9 process::Command,
10};
11
12pub fn extract(rel_stencils_dir: &str) -> Result<(), Box<dyn Error>> {
35 let out_dir = std::env::var("OUT_DIR")?;
36 let out_path = Path::new(&out_dir).canonicalize()?;
37 let target_dir = find_target_dir(&out_path)?.join("patchouly");
39 let current_dir = std::env::current_dir()?;
40 let stencils_dir = current_dir
41 .as_path()
42 .parent()
43 .ok_or("expected to be in a workspace")?
44 .join(rel_stencils_dir)
45 .canonicalize()?;
46 assert!(
47 stencils_dir.exists(),
48 "stencils dir {} does not exist",
49 stencils_dir.display()
50 );
51
52 let status = Command::new("cargo")
54 .current_dir(&stencils_dir)
55 .args([
56 "rustc",
57 "--release",
58 "--lib",
59 "--target-dir",
60 target_dir.to_str().unwrap(),
61 "--",
62 "-C",
63 "relocation-model=static",
64 ])
65 .status()?;
66 if !status.success() {
67 return Err("failed to compile stencils crate".into());
68 }
69
70 println!("cargo:rerun-if-changed={}/src", stencils_dir.display());
71
72 let rlib = target_dir.join("release").join(dir_to_libname(&stencils_dir)?);
73 let extraction = extract::extract(&rlib)?;
74 generate::generate(extraction, &out_path)?;
75
76 Ok(())
77}
78
79fn dir_to_libname(rel: &Path) -> Result<String, Box<dyn Error>> {
80 let manifest = fs::read_to_string(rel.join("Cargo.toml"))?;
81 let name = manifest
82 .lines()
83 .map(str::trim)
84 .find_map(|line| {
85 line.strip_prefix("name = ")
86 .map(|value| value.trim_matches('"'))
87 })
88 .ok_or("package name not found in stencils Cargo.toml")?;
89 Ok(format!("lib{}.rlib", name.replace("-", "_")))
90}
91
92fn find_target_dir(out_dir: &Path) -> Result<PathBuf, Box<dyn Error>> {
93 let profile = std::env::var("PROFILE")?;
94 for parent in out_dir.ancestors() {
95 if parent.ends_with(&profile) {
96 return Ok(parent.parent().ok_or("failed to find target dir")?.to_path_buf());
97 }
98 }
99 Err("failed to find target dir".into())
100}