xds-types 0.1.0

Generated protobuf types for Envoy xDS APIs
Documentation
//! Build script for xds-types.
//!
//! **Default mode (`cargo build`):** copies pre-generated `*.rs` files from
//! `generated/` into `OUT_DIR` so `src/lib.rs` can `include!` them. This is
//! what crates.io consumers see — no `protoc`, no `tonic-build`, just a
//! file copy. Keeps the published tarball small.
//!
//! **Regenerate mode (`cargo build --features regenerate-protos`):** runs the
//! full `tonic-build` pipeline against the proto submodules under `proto/`,
//! writes the result into `generated/`, then copies to `OUT_DIR`. Developers
//! commit the updated `generated/` files; the pipeline treats them as the
//! source of truth for consumers.

use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn main() -> io::Result<()> {
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR must be set by cargo"));
    let generated_dir = PathBuf::from("generated");

    #[cfg(feature = "regenerate-protos")]
    regenerate_from_proto(&generated_dir)?;

    // Copy pre-generated .rs files into OUT_DIR so `include!(concat!(env!("OUT_DIR"), ...))`
    // in src/lib.rs resolves correctly.
    copy_generated_to_out_dir(&generated_dir, &out_dir)?;

    println!("cargo:rerun-if-changed=generated");
    Ok(())
}

fn copy_generated_to_out_dir(generated: &Path, out_dir: &Path) -> io::Result<()> {
    for entry in fs::read_dir(generated)? {
        let entry = entry?;
        let path = entry.path();
        if path.extension().and_then(|s| s.to_str()) == Some("rs") {
            let dest = out_dir.join(path.file_name().expect("rs file has a name"));
            fs::copy(&path, &dest)?;
        }
    }
    Ok(())
}

#[cfg(feature = "regenerate-protos")]
fn regenerate_from_proto(generated_dir: &Path) -> io::Result<()> {
    let protos: Vec<PathBuf> = glob::glob("proto/data-plane-api/envoy/**/v3/*.proto")
        .expect("failed to read proto glob pattern")
        .filter_map(Result::ok)
        .collect();

    fs::create_dir_all(generated_dir)?;

    let mut config = prost_build::Config::new();
    config.disable_comments(["."]);

    tonic_build::configure()
        .build_server(true)
        .build_client(true)
        .compile_well_known_types(true)
        .include_file("mod.rs")
        .out_dir(generated_dir)
        .compile_protos_with_config(
            config,
            &protos,
            &[
                "proto/data-plane-api",
                "proto/googleapis",
                "proto/protoc-gen-validate",
                "proto/xds",
                "proto/opencensus-proto/src",
                "proto/opentelemetry-proto",
                "proto/client_model",
                "proto/cel-spec/proto",
            ],
        )?;

    Ok(())
}