bwapi-sys 0.1.2

FFI bindings to the bwapi-c library
Documentation
extern crate reqwest;
extern crate flate2;
extern crate tar;
extern crate cmake;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::File;

use flate2::read::GzDecoder;
use tar::Archive;
use std::process::Command;
use cmake::Config;

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("bwapi-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("bwapi-sys/build.rs:{}: ", $fmt),
    line!(), $($arg)*));
}
macro_rules! log_var (($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn download(url: &str, into: &Path) {
    if into.exists() {
        log!("File {} was already downloaded", into.display());
    } else {
        log!("Downloading to {:?}", &into);

        let mut response = reqwest::get(url).unwrap();

        if !response.status().is_success() {
            log!("Status: {}", response.status());
            log!("Headers:\n{}", response.headers());
            panic!("Could not download file");
        }

        let mut file = File::create(&into).unwrap();
        std::io::copy(&mut response, &mut file).unwrap();
    }
}

fn extract(archive_path: &Path, extract_to: &Path) {
    let file = File::open(archive_path).unwrap();
    let unzipped = GzDecoder::new(file);
    let mut archive = Archive::new(unzipped);
    archive.unpack(extract_to).unwrap();
}

fn download_bwapic_library(platform: String, output_dir: &PathBuf, bwapic_version: &str, build_mode: &str) {
    // download windows or linux bwapic binary and extract it
    let binary_url = format!(
        "https://github.com/RnDome/bwapi-c/releases/download/v{version}/bwapi-c-{mode}-{platform}.tar.gz",
        version = &bwapic_version, mode = &build_mode, platform = &platform);
    let short_file_name = binary_url.split("/").last().unwrap();
    let zip_path = output_dir.join(short_file_name);
    log_var!(binary_url);
    log_var!(short_file_name);
    log_var!(zip_path);
    log!("Obtaining BWAPI-C distribution (for {})...", platform);
    download(&binary_url, &zip_path);
    log!("Unpacking archive (for {})...", platform);
    extract(&zip_path, &output_dir);
}

fn main() {
    let output_dir = PathBuf::from(&get!("OUT_DIR"));
    let target = &get!("TARGET");
    let build_mode = &get!("PROFILE");
    let cur_dir = PathBuf::from(&get!("CARGO_MANIFEST_DIR"));
    let submodules_dir = cur_dir.join("submodules");
    let bwapic_version = "1.0.0";

    log_var!(output_dir);
    log_var!(target);
    log_var!(build_mode);
    log_var!(cur_dir);
    log_var!(submodules_dir);

    if target.contains("i686-pc-windows-gnu") {
        // for windows download bwapic library release
        download_bwapic_library("win32".to_owned(), &output_dir, bwapic_version, build_mode);
        println!("cargo:rerun-if-changed={}", output_dir.display());
    } else {
        log!("Trying to build bwapi & bwapi-c from sources for {}", target);

        // OpenBW/openbw and OpenBW/bwapi are added as the submodules, download them in case of absence
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
            .status();

        // OpenBW/bwapi is being built by cmake
        let openbw_dir = submodules_dir.join("openbw").join("openbw");
        let bwapi_dir = submodules_dir.join("openbw").join("bwapi");
        log_var!(openbw_dir);
        log_var!(bwapi_dir);
        let bwapi_build_dir = Config::new(&bwapi_dir)
            .define("OPENBW_DIR", &openbw_dir)
            .define("OPENBW_ENABLE_UI", "0")
            .build();
        log_var!(bwapi_build_dir);

        // previous variant: download_bwapic_library("linux".to_owned(), &output_dir, bwapic_version, build_mode);
        let bwapic_dir = submodules_dir.join("bwapi-c");
        log_var!(bwapic_dir);
        let bwapic_build_dir = Config::new(&bwapic_dir)
            .define("BWAPI_PATH", &openbw_dir)
            .build();
        log_var!(bwapic_build_dir);
        println!("cargo:rerun-if-changed={}", openbw_dir.display());
        println!("cargo:rerun-if-changed={}", bwapi_dir.display());
        println!("cargo:rerun-if-changed={}", bwapic_dir.display());
    }
    println!("cargo:rustc-link-search=native={}", output_dir.join("lib").display());
    println!("cargo:rustc-link-lib=dylib=BWAPIC");
}