galion 0.2.0

rclone sync on ratatui
Documentation
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let lib_name = "librclone";
    let rclone_repo = format!("github.com/rclone/rclone/{}", lib_name);
    let target_triple = env::var("TARGET")?;
    let out_dir = env::var("CARGO_MANIFEST_DIR")?;
    let out_path = PathBuf::from(&out_dir).join("src").join(lib_name);

    // return early for docs.rs
    if env::var("DOCS_RS").is_ok() {
        return Ok(());
    }

    // Re-run build script if these files change
    println!(
        "cargo:rerun-if-changed={}",
        out_path.join("go.mod").display()
    );
    println!(
        "cargo:rerun-if-changed={}",
        out_path.join("go.sum").display()
    );

    let mut gofile_buf = String::new();
    gofile_buf.push_str("package main\n\n");
    gofile_buf.push_str(&format!("import \"{}\"", rclone_repo));
    std::fs::write(out_path.join(format!("{}.go", lib_name)), gofile_buf)?;

    // Build the Go static library
    let status = Command::new("go")
        .current_dir("src/librclone")
        .args(["build", "--buildmode=c-archive", "-o"])
        .arg(out_path.join(format!("{}.a", lib_name)))
        .arg(rclone_repo)
        .status()?;

    if !status.success() {
        return Err("`go build` failed. Ensure Go is installed and up-to-date.".into());
    }

    // Tell Rust where to find and link the library
    println!("cargo:rustc-link-search=native={}", out_path.display());
    println!("cargo:rustc-link-lib=static=rclone");

    // macOS-specific frameworks
    if target_triple.ends_with("darwin") {
        for framework in &["CoreFoundation", "IOKit", "Security"] {
            println!("cargo:rustc-link-lib=framework={}", framework);
        }
        println!("cargo:rustc-link-lib=resolv");
    }

    // Generate Rust bindings using bindgen
    let bindings = bindgen::Builder::default()
        .header(out_path.join(format!("{}.h", lib_name)).to_string_lossy())
        .allowlist_function("RcloneRPC")
        .allowlist_function("RcloneInitialize")
        .allowlist_function("RcloneFinalize")
        .allowlist_function("RcloneFreeString")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()?;

    let mut out_file = File::create(out_path.join("bindings.rs"))?;

    writeln!(out_file, "//! Bindings generated by build.rs")?;
    writeln!(out_file, "#![allow(missing_docs)]")?;
    writeln!(out_file, "#![allow(non_upper_case_globals)]")?;
    writeln!(out_file, "#![allow(non_camel_case_types)]")?;
    writeln!(out_file, "#![allow(non_snake_case)]")?;
    writeln!(out_file, "#![allow(clippy::all)]")?;
    writeln!(out_file)?;

    bindings.write(Box::new(out_file))?;

    let mut makefile_buf = String::new();
    makefile_buf.push_str("update:\n");
    makefile_buf.push_str("\trm -f go.mod go.sum\n");
    makefile_buf.push_str("\tgo mod init github.com/Its-Just-Nans/galion\n");
    makefile_buf.push_str("\tgo mod tidy -go=1.24.4\n");
    std::fs::write(out_path.join("Makefile"), makefile_buf)?;

    Ok(())
}