use std::{
env, fs,
path::{Path, PathBuf},
};
use miette::IntoDiagnostic;
use prost::Message;
fn main() -> miette::Result<()> {
println!("cargo::rerun-if-changed=../../proto");
println!("cargo::rerun-if-env-changed=BUILD_PROTO");
if env::var("BUILD_PROTO").unwrap_or("0".to_string()) == "0" {
return Ok(());
}
let crate_root: PathBuf =
env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR should be set").into();
let dst_dir = crate_root.join("src").join("generated");
fs::remove_dir_all(&dst_dir).into_diagnostic()?;
fs::create_dir(&dst_dir).into_diagnostic()?;
let cwd: PathBuf = env::current_dir().into_diagnostic()?;
let cwd = cwd
.parent()
.and_then(|p| p.parent())
.ok_or_else(|| miette::miette!("Failed to navigate two directories up"))?;
let proto_dir: PathBuf = cwd.join("proto");
let out = env::var("OUT_DIR").into_diagnostic()?;
let file_descriptor_path = PathBuf::from(out).join("file_descriptor_set.bin");
let protos = &[
proto_dir.join("block_producer.proto"),
proto_dir.join("store.proto"),
proto_dir.join("rpc.proto"),
];
let includes = &[proto_dir];
let file_descriptors = protox::compile(protos, includes)?;
fs::write(&file_descriptor_path, file_descriptors.encode_to_vec()).into_diagnostic()?;
let mut prost_config = prost_build::Config::new();
prost_config.skip_debug(["AccountId", "Digest"]);
tonic_build::configure()
.file_descriptor_set_path(&file_descriptor_path)
.skip_protoc_run()
.out_dir(&dst_dir)
.compile_with_config(prost_config, protos, includes)
.into_diagnostic()?;
generate_mod_rs(&dst_dir).into_diagnostic()?;
Ok(())
}
fn generate_mod_rs(directory: impl AsRef<Path>) -> std::io::Result<()> {
let mod_filepath = directory.as_ref().join("mod.rs");
let mut submodules = Vec::new();
for entry in fs::read_dir(directory)? {
let entry = entry?;
let path = entry.path();
if path.is_file() {
let file_stem = path
.file_stem()
.and_then(|f| f.to_str())
.expect("Could not get file name")
.to_owned();
submodules.push(file_stem);
}
}
submodules.sort();
let contents = submodules.iter().map(|f| format!("pub mod {f};\n"));
let contents = std::iter::once("// Generated by build.rs\n\n".to_owned())
.chain(contents)
.collect::<String>();
fs::write(mod_filepath, contents)
}