cog-task 0.2.0

CogTask: a general-purpose low-latency application to serve cognitive tasks
use heck::ToUpperCamelCase;
use itertools::Itertools;
use std::ffi::OsStr;
use std::fs;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=src/action/include.rs");
    println!("cargo:rerun-if-changed=src/action/core/");
    println!("cargo:rerun-if-changed=src/action/core/mod.rs");
    println!("cargo:rerun-if-changed=src/action/extra/");
    println!("cargo:rerun-if-changed=src/action/extra/mod.rs");

    let core = fs::read_dir("src/action/core/")
        .unwrap()
        .into_iter()
        .map(|p| p.unwrap().path())
        .filter(|p| p.is_file())
        .filter(|p| p.extension().unwrap_or_else(|| OsStr::new("")).to_str() == Some("rs"))
        .map(|p| {
            p.with_extension("")
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string()
        })
        .filter(|n| n != "mod")
        .sorted()
        .collect_vec();

    let core_stateful = core
        .clone()
        .into_iter()
        .filter(|n| {
            fs::read_to_string(
                Path::new("src/action/core/").join(Path::new(n).with_extension("rs")),
            )
            .unwrap()
            .contains(&format!("Stateful{}", n.to_upper_camel_case()))
        })
        .collect_vec();

    let extra = fs::read_dir("src/action/extra/")
        .unwrap()
        .into_iter()
        .map(|p| p.unwrap().path())
        .filter(|p| p.is_file())
        .filter(|p| p.extension().unwrap_or_else(|| OsStr::new("")).to_str() == Some("rs"))
        .map(|p| {
            p.with_extension("")
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string()
        })
        .filter(|n| n != "mod")
        .sorted()
        .collect_vec();

    let extra_stateful = extra
        .clone()
        .into_iter()
        .filter(|n| {
            fs::read_to_string(
                Path::new("src/action/extra/").join(Path::new(n).with_extension("rs")),
            )
            .unwrap()
            .contains(&format!("Stateful{}", n.to_upper_camel_case()))
        })
        .collect_vec();

    let content = format!(
        "\
        // This file is automatically generated by the crate build script.\n\
        // DO NOT MODIFY THIS FILE MANUALLY! CHANGES WILL BE REVERTED.\n\n\
        {}\n\
        ",
        core.iter()
            .map(|n| format!("pub mod {n};"))
            .collect::<Vec<_>>()
            .join("\n"),
    );

    let path = "src/action/core/mod.rs";
    match fs::read_to_string(path) {
        Ok(current) if current == content => {}
        _ => {
            fs::write(path, content)
                .expect("Failed to generate src/action/core/mod.rs automatically!");
        }
    }

    let content = format!(
        "\
        // This file is automatically generated by the crate build script.\n\
        // DO NOT MODIFY THIS FILE MANUALLY! CHANGES WILL BE REVERTED.\n\n\
        {}\n\
        ",
        extra
            .iter()
            .map(|n| format!("pub mod {n};"))
            .collect::<Vec<_>>()
            .join("\n"),
    );

    let path = "src/action/extra/mod.rs";
    match fs::read_to_string(path) {
        Ok(current) if current == content => {}
        _ => {
            fs::write(path, content)
                .expect("Failed to generate src/action/extra/mod.rs automatically!");
        }
    }

    let content = format!(
        "\
        // This file is automatically generated by the crate build script.\n\
        // DO NOT MODIFY THIS FILE MANUALLY! CHANGES WILL BE REVERTED.\n\n\
        include_actions!(\n{}\n{}\n);\n\n\
        include_stateful_actions!(\n{}\n{}\n);\n\
        ",
        core.into_iter()
            .map(|n| format!("    core::{n},"))
            .collect::<Vec<_>>()
            .join("\n"),
        extra
            .into_iter()
            .map(|n| format!("    extra::{n},"))
            .collect::<Vec<_>>()
            .join("\n"),
        core_stateful
            .into_iter()
            .map(|n| format!("    core::{n},"))
            .collect::<Vec<_>>()
            .join("\n"),
        extra_stateful
            .into_iter()
            .map(|n| format!("    extra::{n},"))
            .collect::<Vec<_>>()
            .join("\n"),
    );

    let path = "src/action/include.rs";
    match fs::read_to_string(path) {
        Ok(current) if current == content => {}
        _ => {
            fs::write(path, content)
                .expect("Failed to generate src/action/include.rs automatically!");
        }
    }
}