use std::fs;
use std::path::Path;
use typify::{TypeSpace, TypeSpaceSettings};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=build.rs");
let schema_targets = [
(
"assets/SelectionList_2_0_0.schema.json",
"src/generated/ssvc/selection_list.rs",
),
(
"assets/DecisionPoint_2_0_0.schema.json",
"src/generated/ssvc/decision_point.rs",
),
];
for (file_path, target_folder) in schema_targets {
println!("cargo:rerun-if-changed={file_path}");
build_from_schema(file_path, target_folder)?;
}
Ok(())
}
fn build_from_schema(file_path: &str, target_path: &str) -> Result<(), Box<dyn std::error::Error>> {
let file = std::fs::File::open(file_path)?;
let schema = serde_json::from_reader(file)?;
let mut type_space = TypeSpace::new(
TypeSpaceSettings::default()
.with_struct_builder(true)
.with_derive("PartialEq".into())
.with_derive("Eq".into()),
);
type_space.add_root_schema(schema)?;
let mut syn_file = syn::parse2::<syn::File>(type_space.to_stream())?;
add_generated_code_header(&mut syn_file);
add_ignore_rustfmt(&mut syn_file);
add_ignore_clippy(&mut syn_file);
let content = prettyplease::unparse(&syn_file);
let out_file = Path::new(&target_path).to_path_buf();
if let Some(parent) = out_file.parent() {
fs::create_dir_all(parent)?;
}
fs::write(out_file, content)?;
Ok(())
}
fn add_generated_code_header(file: &mut syn::File) {
let doc_attr: syn::Attribute = syn::parse_quote! { #![doc = #GENERATED_CODE_HEADER] };
file.attrs.push(doc_attr);
}
static GENERATED_CODE_HEADER: &str = "
* This file is automatically generated by build.rs.
* Do not edit manually!
* Re-generate with: cargo build
";
fn add_ignore_rustfmt(file: &mut syn::File) {
let doc_attr = syn::parse_quote! { #![cfg_attr(any(), rustfmt::skip)] };
file.attrs.push(doc_attr);
}
fn add_ignore_clippy(file: &mut syn::File) {
let doc_attr = syn::parse_quote! { #![allow(clippy::all)] };
file.attrs.push(doc_attr);
}