boltbuild 0.1.0

BoltBuild is a programmable build system.
Documentation
use crate::command::SerializedHash;
use crate::context::Context;
use crate::environment::EnvironmentValue;
use crate::node::Node;
use blake3::Hasher;
use mlua::prelude::{LuaError, LuaResult};
use mlua::Lua;
use std::fs;
use std::ops::Deref;

pub(super) fn search(
    _lua: &Lua,
    this: &mut Context,
    (path, pattern, include_directories): (Node, String, Option<bool>),
) -> LuaResult<Vec<Node>> {
    let mut result = Vec::new();
    if path.is_dir() {
        let include_directories = include_directories.unwrap_or(false);
        let path = Node::from(&fs::canonicalize(path.path())?);
        let paths = glob::glob(path.path().join(&pattern).to_string_lossy().deref())
            .map_err(|e| LuaError::RuntimeError(format!("pattern error: {}", e)))?;
        let mut hasher = Hasher::new();
        for path in paths.flatten() {
            hasher.update(path.as_os_str().as_encoded_bytes());
            if include_directories || !path.is_dir() {
                result.push(Node::from(&path));
            }
        }
        let mut store = true;
        let hash = hasher.finalize();
        for (prev_path, prev_pattern, prev_hash) in &this.output.stored_hash.glob_dependencies {
            if prev_path.path().eq(path.path()) & prev_pattern.eq(&pattern) {
                if !hash.eq(&prev_hash.0) {
                    todo!();
                }
                store = false;
            }
        }
        if store {
            this.output.stored_hash.glob_dependencies.push((
                path.clone(),
                pattern,
                SerializedHash(hash),
            ));
        }
    }
    result.sort();
    Ok(result)
}

pub(super) fn find_program(
    _lua: &Lua,
    this: &mut Context,
    (program, paths): (String, Option<Vec<Node>>),
) -> LuaResult<Option<Node>> {
    let paths = paths.unwrap_or_else(|| {
        let paths = this.options.get_value("path");
        if let Some(paths) = paths {
            paths
                .into_list()
                .into_iter()
                .flat_map(|x| x.as_node(&this.path))
                .collect()
        } else {
            Vec::new()
        }
    });
    let suffix = this
        .options
        .get_value("exe_suffix")
        .unwrap_or(EnvironmentValue::String("".to_string()))
        .as_string();
    let pattern = program + suffix.as_str();

    for path in paths {
        let canonical_path = fs::canonicalize(path.path());
        if let Ok(canonical_path) = canonical_path {
            let path = Node::from(&canonical_path);
            let executable = path.path().join(&pattern);
            let mut hasher = Hasher::new();
            if executable.is_file() {
                hasher.update(executable.as_os_str().as_encoded_bytes());
                this.output.stored_hash.glob_dependencies.push((
                    path.clone(),
                    pattern.clone(),
                    SerializedHash(hasher.finalize()),
                ));
                return Ok(Some(Node::from(&executable)));
            } else {
                this.output.stored_hash.glob_dependencies.push((
                    path.clone(),
                    pattern.clone(),
                    SerializedHash(hasher.finalize()),
                ));
            }
        } else {
            let hasher = Hasher::new();
            this.output.stored_hash.glob_dependencies.push((
                path.clone(),
                pattern.clone(),
                SerializedHash(hasher.finalize()),
            ));
        }
    }
    Ok(None)
}