tensorflow-sys 0.3.0

The package provides bindings to TensorFlow.
extern crate pkg_config;

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

const FILENAME: &'static str = "libtensorflow.so";
const LIBRARY: &'static str = "tensorflow";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const VERSION: &'static str = "0.9.0rc0";

macro_rules! get(($name:expr) => (env::var($name).unwrap()));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        return;
    }

    let output = PathBuf::from(&get!("OUT_DIR"));
    if !output.join(FILENAME).exists() {
        let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join("target/source");
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| command.arg("clone")
                                        .arg(format!("--branch=v{}", VERSION))
                                        .arg("--recursive")
                                        .arg(REPOSITORY)
                                        .arg(&source));
        }

        run("./configure", |command| command.current_dir(&source));
        run("bazel", |command| command.current_dir(&source)
                                      .arg("build")
                                      .arg(format!("--jobs={}", get!("NUM_JOBS")))
                                      .arg("--compilation_mode=opt")
                                      .arg(format!("{}:{}", LIBRARY, FILENAME)));

        fs::copy(find(&source, FILENAME).unwrap(), output.join(FILENAME)).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", output.display());
}

fn find(directory: &Path, file: &str) -> Option<PathBuf> {
    for entry in fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.is_dir() {
            if let Some(path) = find(&path, file) {
                return Some(path);
            }
        } else {
            if path.is_file() && path.ends_with(file) {
                return Some(path);
            }
        }
    }
    None
}

fn run<F>(name: &str, mut configure: F) where F: FnMut(&mut Command) -> &mut Command {
    let mut command = Command::new(name);
    if !configure(&mut command).status().unwrap().success() {
        panic!("failed to execute {:?}", command);
    }
}