//
// build.rs
//
// Copyright (C) 2023 Posit Software, PBC. All rights reserved.
//
//

use std::path::Path;
use std::process::Command;
extern crate embed_resource;

fn main() {
    // Ensures that env vars are refreshed on any `src/` or `resources/` change, which is
    // required for `.ps.ark.version()` to work as you'd expect. Notably this also ensures
    // changes to `src/debug.c` force a refresh, which otherwise aren't considered by
    // cargo's defaults as requiring a rebuild.
    println!("cargo:rerun-if-changed=src");
    println!("cargo:rerun-if-changed=resources");

    // Every first-party crate directory name. Used by `logger::internal_crates()`
    // to `ark`'s `RUST_LOG` level to all our crates.
    let workspace_crates_dir = Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap())
        .join("..")
        .canonicalize()
        .unwrap();
    println!("cargo:rerun-if-changed={}", workspace_crates_dir.display());

    let internal_crates: Vec<String> = std::fs::read_dir(&workspace_crates_dir)
        .unwrap()
        .filter_map(|entry| entry.ok())
        .filter(|entry| entry.path().is_dir())
        .filter_map(|entry| entry.file_name().into_string().ok())
        .collect();
    println!(
        "cargo:rustc-env=ARK_INTERNAL_CRATES={}",
        internal_crates.join(",")
    );

    // Attempt to use `git rev-parse HEAD` to get the current git hash. If this
    // fails, we'll just use the string "<unknown>" to indicate that the git hash
    // could not be determined..
    let git_hash = match Command::new("git")
        .args(["rev-parse", "--short", "HEAD"])
        .output()
    {
        Ok(output) => String::from_utf8(output.stdout).unwrap(),
        Err(_) => String::from("<unknown>"),
    };
    println!("cargo:rustc-env=BUILD_GIT_HASH={}", git_hash);

    let git_branch = match Command::new("git")
        .args(["branch", "--show-current"])
        .output()
    {
        Ok(output) => String::from_utf8(output.stdout).unwrap(),
        Err(_) => String::from("<unknown>"),
    };
    println!("cargo:rustc-env=BUILD_GIT_BRANCH={}", git_branch);

    // Get the build date as a string
    let build_date = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
    println!("cargo:rustc-env=BUILD_DATE={}", build_date);

    // Allow downstream builds (e.g. Positron prebuilds, which embed the public
    // release version plus the submodule commit distance, like "0.1.251+10")
    // to override the version string baked into the binary. Defaults to the
    // version declared in `Cargo.toml`.
    let build_version = option_env!("ARK_BUILD_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"));
    println!("cargo:rustc-env=BUILD_VERSION={}", build_version);

    // Embed an Application Manifest file on Windows.
    // Turns on UTF-8 support and declares our Windows version compatibility.
    // Documented to do nothing on non-Windows.
    // See <crates/ark/resources/manifest/ark.exe.manifest>.
    //
    // We also do this for harp to support its unit tests.
    //
    // We can't just use `compile()`, as that uses `cargo:rustc-link-arg-bins`,
    // which targets the main `ark.exe` (good) but not the test binaries (bad).
    // We need the application manifest to get embedded into the ark/harp test
    // binaries too, so that the instance of R started by our tests also has
    // UTF-8 support.
    //
    // We can't use `compile_for_tests()` because `cargo:rustc-link-arg-tests`
    // only targets integration tests right now, not unit tests.
    // https://github.com/rust-lang/cargo/issues/10937
    //
    // Instead we use `compile_for_everything()` which uses the kitchen sink
    // instruction of `cargo:rustc-link-arg`, and that seems to work.
    // https://github.com/nabijaczleweli/rust-embed-resource/issues/69
    let resource = Path::new("resources")
        .join("manifest")
        .join("ark-manifest.rc");
    embed_resource::compile_for_everything(resource, embed_resource::NONE)
        .manifest_required()
        .unwrap();

    cc::Build::new().file("src/debug.c").compile("debug");
}
