//
// Syd: rock-solid application kernel
// build.rs: Helper file for build-time information
//
// Copyright (c) 2021, 2024, 2025 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::{env, path::Path, process::Command};

const VERSION: &str = env!("CARGO_PKG_VERSION");

const LIBSECCOMP_LIB_PATH: &str = "LIBSECCOMP_LIB_PATH";

#[expect(clippy::disallowed_methods)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Check if page size is 4k.
    // This is required by GrapheneOS hardened allocator.
    let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
    if page_size == 4096 {
        println!("cargo:rustc-cfg=target_page_size_4k");
    }

    // libseccomp/build.rs
    println!("cargo:rerun-if-env-changed={LIBSECCOMP_LIB_PATH}");

    if let Ok(path) = env::var(LIBSECCOMP_LIB_PATH) {
        println!("cargo:rustc-link-search=native={path}");
        let pkgconfig = Path::new(&path).join("pkgconfig");
        env::set_var("PKG_CONFIG_PATH", pkgconfig);
    }

    let target = env::var("TARGET").unwrap_or_default();
    let host = env::var("HOST").unwrap_or_default();
    if target != host {
        env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");
    }

    if pkg_config::Config::new()
        .atleast_version("2.6.0")
        .probe("libseccomp")
        .is_ok()
    {
        println!("cargo:rustc-cfg=libseccomp_v2_6");
    }
    // end of libseccomp/build.rs

    // Gather information on target.
    println!(
        "cargo:rustc-env=SYD_TARGET_ENV={}",
        env::var("CARGO_CFG_TARGET_ENV").unwrap_or("?".to_string())
    );
    println!(
        "cargo:rustc-env=SYD_TARGET_POINTER_WIDTH={}",
        env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap_or("?".to_string())
    );
    println!(
        "cargo:rustc-env=SYD_TARGET_ENDIAN={}",
        env::var("CARGO_CFG_TARGET_ENDIAN").unwrap_or("?".to_string())
    );
    println!(
        "cargo:rustc-env=SYD_TARGET_FEATURE={}",
        env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or("?".to_string())
    );

    // Gather information on build host (unless SDE is set for reproducible builds).
    let host = if env::var_os("SOURCE_DATE_EPOCH").is_none() {
        if let Ok(output) = Command::new("uname").arg("-mr").output() {
            String::from_utf8_lossy(&output.stdout).trim().to_string()
        } else {
            "?".to_string()
        }
    } else {
        "?".to_string()
    };
    println!("cargo:rustc-env=SYD_BUILDHOST={host}");

    // We don't want to build libgit2 library just to get the git version.
    let root = Path::new(env!("CARGO_MANIFEST_DIR"));
    let root = root.join(".git");
    let mut comm = String::new();
    let mut head = String::new();

    if root.exists() {
        // Try to get the git commit ID.
        if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
            comm = String::from_utf8_lossy(&output.stdout).trim().to_string();
        }

        // Try to get the description.
        if let Ok(output) = Command::new("git").arg("describe").output() {
            head = String::from_utf8_lossy(&output.stdout).trim().to_string();
        }

        // If description is empty, try to get the short HEAD
        // Only use main version tags, skip pandora, libsyd etc. tags
        if head.is_empty() || !head.starts_with('v') {
            if let Ok(output) = Command::new("git")
                .args(["rev-parse", "--short", "HEAD"])
                .output()
            {
                head = format!(
                    "v{VERSION}-{}",
                    String::from_utf8_lossy(&output.stdout).trim()
                );
            }
        }

        // Check for any changes
        if let Ok(output) = Command::new("git")
            .args(["diff-index", "-m", "--name-only", "HEAD"])
            .output()
        {
            let changes = String::from_utf8_lossy(&output.stdout);
            if !changes.is_empty() {
                head = format!("{head}-dirty");
            }
        }

        // Strip prefix v$VERSION -> $VERSION
        if head.starts_with('v') {
            head = head[1..].to_string();
        }
    }

    if comm.is_empty() {
        comm = "unknown".to_string();
    }

    println!("cargo:rustc-env=SYD_GIT_COMMIT={comm}");
    println!("cargo:rustc-env=SYD_GIT_HEAD={head}");

    Ok(())
}
