vex-sdk-vexcode 0.0.1

A build script helper to download and link to official VEXcode SDKs.
Documentation
use std::{fs::File, io::Cursor, path::Path};

#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)]
struct Manifest {
    latest: String,
    catalog: Vec<String>,
}

pub fn link_sdk(version: &str) {
    let target = std::env::var("TARGET").expect("TARGET environment variable not set");
    let target_env = std::env::var("CARGO_CFG_TARGET_ENV")
        .expect("CARGO_CFG_TARGET_ENV environment variable not set");
    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable not set");

    if !target.contains("vex") {
        panic!("`vex-sdk-vexcode` only supports building for VEX targets.")
    }

    let (cdn_base, folder_name, runtime_library_name) = match target_env.as_ref() {
        "v5" => ("https://content.vexrobotics.com/vexos/public/V5/vscode/sdk/cpp", "vexv5", "v5rt"),
        "exp" => ("https://content.vexrobotics.com/vexos/public/EXP/vscode/sdk/cpp", "vexexp", "exprt"),
        "iq2" => ("https://content.vexrobotics.com/vexos/public/IQ2/vscode/sdk/cpp", "vexiq2", "viq2rt"),
        _ => panic!("unsupported `target_vendor` value. `vex-sdk-vexcode` only supports building for VEX targets.")
    };

    let manifest: Manifest = ureq::get(format!("{cdn_base}/manifest.json"))
        .call()
        .expect("failed to download VEX SDK manifest")
        .body_mut()
        .read_json()
        .expect("failed to parse VEX SDK manifest");

    if !manifest.catalog.contains(&version.to_string()) {
        panic!("{} is not a valid VEX SDK version", version);
    }

    let zip_data = ureq::get(format!("{cdn_base}/{version}.zip"))
        .call()
        .expect("failed to download VEX SDK")
        .body_mut()
        .read_to_vec()
        .expect("failed to read VEX SDK");

    let runtime_library_file = format!("lib{runtime_library_name}.a");
    let mut archive =
        zip::ZipArchive::new(Cursor::new(zip_data)).expect("failed to read VEX SDK zip archive");
    let runtime_library_path = format!("{version}/{folder_name}/{runtime_library_file}");

    std::io::copy(
        &mut archive.by_name(&runtime_library_path).expect(&format!(
            "VEX SDK is missing runtime library {runtime_library_path}"
        )),
        &mut File::create(&Path::new(&out_dir).join(runtime_library_file)).unwrap(),
    )
    .unwrap();

    println!("cargo::rerun-if-changed=build.rs");
    println!("cargo:rustc-link-search=native={out_dir}");
    println!("cargo:rustc-link-lib=static={runtime_library_name}");
}