use std::io::Write;
use walkdir::WalkDir;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file_paths = get_proto_file_paths()?;
compile_protobuf(std::env::current_dir()?.display().to_string(), file_paths)?;
let build_path = std::env::var_os("OUT_DIR").unwrap();
let publish_under_package = "com.oliverhines.friendbook.grpc.services.";
let code = generate_module_code(build_path.to_str().unwrap(), publish_under_package);
let mut file =
std::fs::File::create(vec![build_path.to_str().unwrap(), "services.rs"].join("/"))?;
file.write_all(code?.as_bytes())?;
Ok(())
}
fn compile_protobuf(file_path_root: String, file_paths: Vec<String>) -> std::io::Result<()> {
let proto_path_arg: Vec<String> = vec![String::from("--proto_path="), file_path_root];
return tonic_build::configure()
.protoc_arg(proto_path_arg.join(""))
.build_server(true)
.compile(&file_paths, &[]);
}
fn get_proto_file_paths() -> std::io::Result<Vec<String>> {
let mut file_paths = Vec::new();
for entry in WalkDir::new("proto") {
let entry = entry?;
let file_name = entry.path().display().to_string();
if entry.file_type().is_file() && file_name.ends_with(".proto") {
file_paths.push(file_name);
println!("{}", entry.path().display().to_string())
}
}
return Ok(file_paths);
}
fn generate_module_code(build_path: &str, publish_under_package: &str) -> std::io::Result<String> {
let mut scope = codegen::Scope::new();
let top_level_mod = scope.new_module("services");
top_level_mod.vis("pub");
for entry in WalkDir::new(&build_path) {
let entry = entry?;
let file_name = entry.file_name().to_str().unwrap();
if entry.file_type().is_file()
&& str::starts_with(file_name, publish_under_package)
&& str::ends_with(file_name, ".rs")
{
let (_, remaining) = str::split_at(file_name, publish_under_package.len());
let (remaining, _) = str::split_at(remaining, remaining.len() - 3);
let package_name_parts: Vec<&str> = remaining.split(".").collect();
let mut current_mod = &mut *top_level_mod;
for i in 0..package_name_parts.len() {
current_mod = current_mod.get_or_new_module(package_name_parts[i]);
current_mod.vis("pub");
}
current_mod.new_struct(file_name);
}
}
let mut scope_to_change = scope.to_string().replace(
"struct ",
"include!(concat!(
env!(\"OUT_DIR\"),
\"/",
);
scope_to_change = scope_to_change.replace(";", "\"));");
return Ok(scope_to_change);
}