nominal-api 0.725.0

API bindings for the Nominal platform
Documentation
use std::path::{Path, PathBuf};
use std::{env, fs};

fn get_protos_recursively(root: &Path) -> std::io::Result<Vec<PathBuf>> {
    let mut protos = Vec::new();
    for entry in fs::read_dir(root)? {
        let entry = entry?;
        if entry.path().is_dir() {
            protos.append(&mut get_protos_recursively(&entry.path())?)
        } else if let Some(ext) = entry.path().extension() {
            if ext == "proto" {
                protos.push(entry.path())
            }
        }
    }

    Ok(protos)
}

fn main() {
    let conjure_input =
        Path::new("definitions/conjure/scout-service-api.conjure.json").to_path_buf();
    let conjure_output = Path::new(&env::var_os("OUT_DIR").unwrap()).join("conjure");

    // Check if conjure.json file exists
    if !conjure_input.exists() {
        panic!(
            "\n===\nConjure definition file '{}' not found. Run `./gradlew :scout-service-api-rust:prepareNominalApis` to copy the file to the definitions directory.\n===\n",
            conjure_input.display()
        );
    }

    println!("cargo:rerun-if-changed={}", conjure_input.display());

    conjure_codegen::Config::new()
        .strip_prefix("io.nominal".to_string())
        .generate_files(conjure_input, conjure_output)
        .unwrap();

    let proto_input = Path::new("definitions/protos/").to_path_buf();
    let proto_include = Path::new(&env::var_os("OUT_DIR").unwrap()).join("tonic.rs");

    let proto_files = get_protos_recursively(&proto_input)
    .unwrap_or_else(|_| panic!("\n===\nFailed to read proto directory '{}'. Run `./gradlew :scout-service-api-rust:prepareNominalApis` to copy the files to the definitions directory.\n===\n", proto_input.display()));

    if proto_files.is_empty() {
        panic!(
            "\n===\nNo proto files found in directory '{}'. Run `./gradlew :scout-service-api-rust:prepareNominalApis` to copy the files to the definitions directory.\n===\n",
            proto_input.display()
        );
    }

    tonic_build::configure()
        .build_server(false)
        .emit_rerun_if_changed(true)
        .compile_well_known_types(true)
        .include_file(&proto_include)
        .compile_protos(
            &proto_files,
            &[proto_input, "definitions/proto-includes/".into()],
        )
        .expect("Failed to compile tonic grpc client from proto definitions");

    // rename the `gen` module `r#gen` as `gen` is a reserved keyword in rust edition 2024
    let content =
        fs::read_to_string(&proto_include).expect("Failed to read generated tonic.rs file");
    let modified_content = content.replace("pub mod gen", "pub mod r#gen");
    fs::write(&proto_include, modified_content).expect("Failed to write modified tonic.rs file");
}