#[cfg(feature = "protox")]
use prost::Message as _;
#[cfg(feature = "protox")]
fn compile(files: &[&str], includes: &[&str], out_dir: &str, out_name: &str) {
let descriptor = protox::compile(files, includes)
.unwrap_or_else(|e| panic!("failed to compile {files:?}: {e}"));
let bytes = descriptor.encode_to_vec();
std::fs::write(format!("{out_dir}/{out_name}"), bytes)
.unwrap_or_else(|e| panic!("failed to write {out_name}: {e}"));
}
#[cfg(not(feature = "protox"))]
fn copy_prebuilt(out_dir: &str, manifest_dir: &str) {
if let Ok(descriptor_pb) = std::env::var("DESCRIPTOR_PB") {
let knife_pb = std::env::var("KNIFE_PB")
.unwrap_or_else(|_| panic!("DESCRIPTOR_PB is set but KNIFE_PB is not"));
let enum_collision_pb = std::env::var("ENUM_COLLISION_PB")
.unwrap_or_else(|_| panic!("DESCRIPTOR_PB is set but ENUM_COLLISION_PB is not"));
for (name, src) in &[
("descriptor.pb", descriptor_pb),
("knife.pb", knife_pb),
("enum_collision.pb", enum_collision_pb),
] {
let dst = std::path::Path::new(out_dir).join(name);
std::fs::copy(src, &dst)
.unwrap_or_else(|e| panic!("failed to copy {name} from '{src}': {e}"));
}
return;
}
let prebuilt = std::path::Path::new(manifest_dir).join("fixtures/prebuilt");
for name in &["descriptor.pb", "knife.pb", "enum_collision.pb"] {
let src = prebuilt.join(name);
let dst = std::path::Path::new(out_dir).join(name);
std::fs::copy(&src, &dst).unwrap_or_else(|e| panic!("failed to copy {name}: {e}"));
}
}
#[cfg(feature = "wkt-db")]
fn build_wkt_graph(out_dir: &str, manifest_dir: &str) {
use std::path::Path;
#[cfg(not(feature = "prebuilt-wkt"))]
use std::process::Command;
let wkt_rkyv_dst = format!("{out_dir}/wkt.rkyv");
let wkt_index_dst = format!("{out_dir}/wkt_index.rkyv");
#[cfg(feature = "prebuilt-wkt")]
{
let prebuilt = Path::new(manifest_dir).join("wkt/prebuilt");
for (name, dst) in &[
("wkt.rkyv", &wkt_rkyv_dst),
("wkt_index.rkyv", &wkt_index_dst),
] {
let src = prebuilt.join(name);
std::fs::copy(&src, dst)
.unwrap_or_else(|e| panic!("failed to copy {name} from wkt/prebuilt/: {e}"));
}
}
#[cfg(not(feature = "prebuilt-wkt"))]
{
if let Ok(prebuilt) = std::env::var("WKT_RKYV") {
std::fs::copy(&prebuilt, &wkt_rkyv_dst)
.unwrap_or_else(|e| panic!("failed to copy WKT_RKYV '{prebuilt}': {e}"));
let prebuilt_index = std::env::var("WKT_INDEX")
.unwrap_or_else(|_| panic!("WKT_RKYV is set but WKT_INDEX is not"));
std::fs::copy(&prebuilt_index, &wkt_index_dst)
.unwrap_or_else(|e| panic!("failed to copy WKT_INDEX '{prebuilt_index}': {e}"));
return;
}
let sources_path = Path::new(manifest_dir).join("wkt/SOURCES");
let sources_text =
std::fs::read_to_string(&sources_path).expect("failed to read wkt/SOURCES");
let proto_files: Vec<&str> = sources_text
.lines()
.map(str::trim)
.filter(|l| !l.is_empty())
.collect();
let wkt_desc_path = format!("{out_dir}/wkt.desc");
#[cfg(feature = "protox")]
{
use prost::Message as _;
let descriptor = protox::compile(&proto_files, &[""])
.unwrap_or_else(|e| panic!("failed to compile WKT protos: {e}"));
let bytes = descriptor.encode_to_vec();
std::fs::write(&wkt_desc_path, bytes)
.unwrap_or_else(|e| panic!("failed to write wkt.desc: {e}"));
}
#[cfg(not(feature = "protox"))]
{
let mut cmd = Command::new("protoc");
cmd.arg(format!("--descriptor_set_out={wkt_desc_path}"));
cmd.arg("--include_imports");
for f in &proto_files {
cmd.arg(f);
}
let status = cmd
.status()
.unwrap_or_else(|e| panic!("failed to run protoc: {e}"));
assert!(status.success(), "protoc failed with status {status}");
}
let schemas_desc = format!("{out_dir}/schemas.desc");
let reproto_bin = std::env::var("REPROTO_BIN").unwrap_or_else(|_| "reproto".to_string());
let status = Command::new(&reproto_bin)
.arg(format!("--build-schema-db={schemas_desc}"))
.arg(format!("-O{out_dir}/reproto-out"))
.arg(format!("-I{out_dir}"))
.arg("wkt.desc")
.status()
.unwrap_or_else(|e| panic!("failed to run reproto '{reproto_bin}': {e}"));
assert!(
status.success(),
"reproto --build-schema-db failed with status {status}"
);
std::fs::copy(format!("{out_dir}/schemas/hopcroft.rkyv"), &wkt_rkyv_dst)
.unwrap_or_else(|e| panic!("failed to copy hopcroft.rkyv: {e}"));
std::fs::copy(format!("{out_dir}/schemas/index.rkyv"), &wkt_index_dst)
.unwrap_or_else(|e| panic!("failed to copy index.rkyv: {e}"));
}
}
fn main() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
#[cfg(feature = "protox")]
{
let schemas_dir = format!("{manifest_dir}/fixtures/schemas");
let wkt_sources_path = std::path::Path::new(&manifest_dir).join("wkt/SOURCES");
let wkt_sources_text =
std::fs::read_to_string(&wkt_sources_path).expect("failed to read wkt/SOURCES");
let wkt_proto_files: Vec<&str> = wkt_sources_text
.lines()
.map(str::trim)
.filter(|l| !l.is_empty())
.collect();
compile(&wkt_proto_files, &[""], &out_dir, "descriptor.pb");
compile(&["knife.proto"], &[&schemas_dir], &out_dir, "knife.pb");
compile(
&["enum_collision.proto"],
&[&schemas_dir],
&out_dir,
"enum_collision.pb",
);
}
#[cfg(not(feature = "protox"))]
copy_prebuilt(&out_dir, &manifest_dir);
#[cfg(feature = "wkt-db")]
build_wkt_graph(&out_dir, &manifest_dir);
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=wkt/SOURCES");
println!("cargo:rerun-if-changed=fixtures/schemas/knife.proto");
println!("cargo:rerun-if-changed=fixtures/schemas/enum_collision.proto");
}