liboj 0.2.3

A high performance framework for building online judge system
use std::collections::HashMap;
use std::env;
use std::fs::{read_dir, read_to_string, write};
use std::io;
use std::path::PathBuf;

use bincode;
use bindgen;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use serde_json;

lazy_static! {
    static ref OUT_DIR: PathBuf = {
        let out_dir = env::var("OUT_DIR").unwrap();
        PathBuf::from(out_dir)
    };
    static ref ROOT_DIR: PathBuf = {
        let root_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
        PathBuf::from(root_dir)
    };
}

fn main() -> io::Result<()> {
    watch_changes()?;
    generate_compiler_backends()?;
    generate_seccomp_binding()?;
    Ok(())
}

fn watch_changes() -> io::Result<()> {
    println!("cargo:rerun-if-changed={}", "Cargo.toml");
    read_dir(&ROOT_DIR.join("src/compiler/backends"))?.for_each(|backend| {
        println!(
            "cargo:rerun-if-changed={}",
            backend.unwrap().path().to_str().unwrap()
        );
    });
    println!("cargo:rerun-if-changed=/usr/include/seccomp.h");
    Ok(())
}

fn generate_seccomp_binding() -> io::Result<()> {
    println!("cargo:rustc-link-lib=dylib=seccomp");
    bindgen::builder()
        .header_contents("seccomp_wrapper.h", "#include<seccomp.h>")
        .generate()
        .expect("Failed to generate seccomp bindings")
        .write_to_file(OUT_DIR.join("seccomp_wrapper.rs"))?;
    Ok(())
}

#[derive(Serialize, Deserialize)]
struct Config {
    suffix: String,
    command: String,
    args: Vec<String>,
    timeout: u64,
}

fn generate_compiler_backends() -> io::Result<()> {
    let backends: HashMap<String, Config> = read_dir(&ROOT_DIR.join("src/compiler/backends"))?
        .map(|entry| entry.unwrap())
        .filter(|entry| entry.file_name().to_str().unwrap().ends_with(".json"))
        .map(|entry| (entry.file_name(), read_to_string(&entry.path()).unwrap()))
        .map(|(filename, config)| {
            let language = filename
                .to_str()
                .unwrap()
                .trim_end_matches(".json")
                .to_owned();
            let config: Config = serde_json::from_str(&config)
                .expect(&format!("Configuration file {} is unavailable", &language));
            (language, config)
        })
        .collect();
    write(
        OUT_DIR.join("compiler_backends"),
        bincode::serialize(&backends).unwrap(),
    )?;
    Ok(())
}