use std::fs::OpenOptions; use std::io::{Read, Seek, Write}; use std::path::PathBuf; use std::{fs, io}; use walkdir::WalkDir; const DST_FOLDER: &str = "src/generated"; const COMPILE_FILES: &[&str] = &[ "ydb_auth_v1.proto", "ydb_coordination_v1.proto", "ydb_discovery_v1.proto", "ydb_scheme_v1.proto", "ydb_table_v1.proto", "ydb_topic_v1.proto", ]; const INCLUDE_DIRS: &[&str] = &["ydb-api-protos"]; fn main() -> Result<(), Box> { if std::env::var("CARGO_FEATURE_REGENERATE_SOURCES").unwrap_or_else(|_| "0".into()) != "1" { println!("skip regenerate sources"); return Ok(()); }; println!("cargo:rerun-if-changed=ydb-api-protos"); clean_dst_dir(DST_FOLDER)?; let descriptor_file = PathBuf::from(DST_FOLDER).join("../descriptors.bin"); let mut cfg = prost_build::Config::default(); cfg.compile_well_known_types() .type_attribute(".Ydb", "#[derive(serde::Serialize, serde::Deserialize)]") // .extern_path(".google.protobuf", "::pbjson_types") .file_descriptor_set_path(&descriptor_file); tonic_build::configure() .build_server(false) .build_client(true) .out_dir(DST_FOLDER) .include_file("mod.rs") .compile_well_known_types(true) // the serialize attributes is workaround // in future need to find/write good serialization for the types .type_attribute( "google.protobuf.Timestamp", "#[derive(serde::Serialize, serde::Deserialize)]", ) .type_attribute( "google.protobuf.Empty", "#[derive(serde::Serialize, serde::Deserialize)]", ) .type_attribute( "google.protobuf.Duration", "#[derive(serde::Serialize, serde::Deserialize)]", ) .type_attribute( "google.protobuf.Any", "#[derive(serde::Serialize, serde::Deserialize)]", ) .compile_with_config(cfg, COMPILE_FILES, INCLUDE_DIRS)?; // let descriptor_bytes = std::fs::read(descriptor_file).unwrap(); // pbjson_build::Builder::new() // .out_dir(DST_FOLDER) // .register_descriptors(&descriptor_bytes) // .unwrap() // .build(&[".google", ".ydb"]) // .unwrap(); // fix_generated_files("src/generated")?; Ok(()) } fn clean_dst_dir(dst: &str) -> Result<(), Box> { for file in fs::read_dir(dst)? { let fname = file?.file_name().to_str().unwrap().to_owned(); let fpath = format!("{}/{}", dst, fname); if fname == "lib.rs" || fname == "mod.rs" { println!("truncate file: {}", &fpath); fs::File::create(&fpath)?; continue; } println!("remove file: {}", &fpath); fs::remove_file(fpath)?; } Ok(()) } fn fix_generated_files(dir: &str) -> io::Result<()> { for item in WalkDir::new(dir) { let item = item?; let item_path = item.path().to_str().unwrap_or(""); if !item.metadata()?.is_file() { println!("skip not file: '{}'", item_path); continue; } fix_generated_file(item.path())?; } Ok(()) } fn fix_generated_file(fpath: &std::path::Path) -> io::Result<()> { if fpath.as_os_str().to_str().unwrap_or("").ends_with(".rs") { println!("rewrite file: '{}'", fpath.to_str().unwrap_or("")); } else { println!( "skip rewrite file: '{}'", fpath.to_str().unwrap_or(""), ); return Ok(()); } let mut f = OpenOptions::new().read(true).write(true).open(fpath)?; let mut contents = String::new(); let _ = f.read_to_string(&mut contents).unwrap(); let lines: Vec<&str> = contents .split_terminator('\n') .filter(|line| line.trim() != "///") .collect(); let contents = lines.join("\n"); f.rewind()?; f.set_len(0)?; f.write_all(contents.as_bytes())?; Ok(()) }