tsdl 1.2.0

A downloader/builder of many tree-sitter parsers
Documentation
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

use cargo_metadata::MetadataCommand;
use indoc::formatdoc;

const TARGETS: &[(&str, &str)] = &[
    ("linux-arm", "arm-unknown-linux-gnueabi"),
    ("linux-arm64", "aarch64-unknown-linux-gnu"),
    ("linux-x64", "x86_64-unknown-linux-gnu"),
    ("linux-x86", "i686-unknown-linux-gnu"),
    ("macos-arm64", "aarch64-apple-darwin"),
    ("macos-x64", "x86_64-apple-darwin"),
];

const fn platform_for_target(target: &str) -> &str {
    let mut i = 0;
    while i < TARGETS.len() {
        if const_str::equal!(TARGETS[i].1, target) {
            return TARGETS[i].0;
        }
        i += 1;
    }
    target
}

fn main() {
    let out_dir = env::var_os("OUT_DIR").unwrap();
    let build_target = env::var_os("TARGET").unwrap();
    let metadata = MetadataCommand::new().exec().unwrap();
    let meta = metadata
        .root_package()
        .unwrap()
        .metadata
        .as_object()
        .unwrap();
    write_tree_sitter_consts(meta, &build_target, &out_dir);
    write_tsdl_consts(meta, &out_dir);
    let sha1 = Command::new("git")
        .args(["rev-parse", "HEAD"])
        .output()
        .ok()
        .and_then(|output| String::from_utf8(output.stdout).ok())
        .map(|str| format!(" ({})", str.trim()))
        .unwrap_or_default();
    fs::write(
        Path::new(&out_dir).join("tsdl.version"),
        format!("{}{}", env!("CARGO_PKG_VERSION"), sha1),
    )
    .unwrap();
}

fn write_tsdl_consts(meta: &serde_json::Map<String, serde_json::Value>, out_dir: &OsString) {
    let root = PathBuf::from(file!());
    let tsdl_bin_build_dir = root.parent().unwrap().join("src").canonicalize().unwrap();
    let tsdl_bin_build_dir = tsdl_bin_build_dir.to_str().unwrap();
    let tsdl = meta.get("tsdl").unwrap();
    let tsdl_build_dir = tsdl.get("build-dir").unwrap().as_str().unwrap();
    let tsdl_config_file = tsdl.get("config").unwrap().as_str().unwrap();
    let tsdl_fresh = tsdl.get("fresh").unwrap().as_bool().unwrap();
    let tsdl_from = tsdl.get("from").unwrap().as_str().unwrap();
    let tsdl_out_dir = tsdl.get("out").unwrap().as_str().unwrap();
    let tsdl_prefix = tsdl.get("prefix").unwrap().as_str().unwrap();
    let tsdl_ref = tsdl.get("ref").unwrap().as_str().unwrap();
    let tsdl_show_config = tsdl.get("show-config").unwrap().as_bool().unwrap();
    let tsdl_consts = Path::new(&out_dir).join("tsdl_consts.rs");
    fs::write(
        tsdl_consts,
        formatdoc!(
            r#"
              pub const TSDL_BIN_BUILD_DIR: &str = "{tsdl_bin_build_dir}/";
              pub const TSDL_BUILD_DIR: &str = "{tsdl_build_dir}";
              pub const TSDL_CONFIG_FILE: &str = "{tsdl_config_file}";
              pub const TSDL_FRESH: bool = {tsdl_fresh};
              pub const TSDL_FROM: &str = "{tsdl_from}";
              pub const TSDL_OUT_DIR: &str = "{tsdl_out_dir}";
              pub const TSDL_PREFIX: &str = "{tsdl_prefix}";
              pub const TSDL_REF: &str = "{tsdl_ref}";
              pub const TSDL_SHOW_CONFIG: bool = {tsdl_show_config};
            "#
        ),
    )
    .unwrap();
}

fn write_tree_sitter_consts(
    meta: &serde_json::Map<String, serde_json::Value>,
    build_target: &OsString,
    out_dir: &OsString,
) {
    let tree_sitter = meta.get("tree-sitter").unwrap();
    let tree_sitter_version = tree_sitter.get("version").unwrap().as_str().unwrap();
    let tree_sitter_repo = tree_sitter.get("repo").unwrap().as_str().unwrap();
    let tree_sitter_platform = platform_for_target(build_target.to_str().unwrap());
    let tree_sitter_consts = Path::new(out_dir).join("tree_sitter_consts.rs");
    fs::write(
        tree_sitter_consts,
        formatdoc!(
            r#"
              pub const TREE_SITTER_PLATFORM: &str = "{tree_sitter_platform}";
              pub const TREE_SITTER_REPO: &str = "{tree_sitter_repo}";
              pub const TREE_SITTER_VERSION: &str = "{tree_sitter_version}";
            "#
        ),
    )
    .unwrap();
}