objdiff-core 2.5.0

A local diffing tool for decompilation projects.
fn main() {
    #[cfg(feature = "bindings")]
    compile_protos();
}

#[cfg(feature = "bindings")]
fn compile_protos() {
    use std::path::{Path, PathBuf};
    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("protos");
    let descriptor_path = root.join("proto_descriptor.bin");
    println!("cargo:rerun-if-changed={}", descriptor_path.display());
    let descriptor_mtime = std::fs::metadata(&descriptor_path)
        .map(|m| m.modified().unwrap())
        .unwrap_or(std::time::SystemTime::UNIX_EPOCH);
    let mut run_protoc = false;
    let proto_files = vec![root.join("diff.proto"), root.join("report.proto")];
    for proto_file in &proto_files {
        println!("cargo:rerun-if-changed={}", proto_file.display());
        let mtime = match std::fs::metadata(proto_file) {
            Ok(m) => m.modified().unwrap(),
            Err(e) => panic!("Failed to stat proto file {}: {:?}", proto_file.display(), e),
        };
        if mtime > descriptor_mtime {
            run_protoc = true;
        }
    }

    fn prost_config(descriptor_path: &Path, run_protoc: bool) -> prost_build::Config {
        let mut config = prost_build::Config::new();
        config.file_descriptor_set_path(descriptor_path);
        // If our cached descriptor is up-to-date, we don't need to run protoc.
        // This is helpful so that users don't need to have protoc installed
        // unless they're updating the protos.
        if !run_protoc {
            config.skip_protoc_run();
        }
        config
    }
    if let Err(e) =
        prost_config(&descriptor_path, run_protoc).compile_protos(&proto_files, &[root.as_path()])
    {
        if e.kind() == std::io::ErrorKind::NotFound && e.to_string().contains("protoc") {
            eprintln!("protoc not found, skipping protobuf compilation");
            prost_config(&descriptor_path, false)
                .compile_protos(&proto_files, &[root.as_path()])
                .expect("Failed to compile protos");
        } else {
            panic!("Failed to compile protos: {e:?}");
        }
    }

    let descriptor_set = std::fs::read(descriptor_path).expect("Failed to read descriptor set");
    pbjson_build::Builder::new()
        .register_descriptors(&descriptor_set)
        .expect("Failed to register descriptors")
        .preserve_proto_field_names()
        .build(&[".objdiff"])
        .expect("Failed to build pbjson");
}