mod ast;
mod expr;
mod lexer;
pub mod loader;
mod lower;
mod parser;
mod token;
mod validate;
use std::collections::{HashMap, HashSet};
use anyhow::Result;
pub use lower::ModuleArgsReport;
use crate::config;
#[cfg(test)]
pub fn parse(
input: &str,
path: &str,
extra_env: &HashMap<String, String>,
arg_values: &HashMap<String, String>,
) -> Result<(Vec<crate::config::ProcessConfig>, Option<String>)> {
let modules = loader::load(input, path)?;
let (configs, log_dir, _) = lower::lower_modules(&modules, extra_env, arg_values)?;
Ok((configs, log_dir))
}
pub fn parse_root(input: &str, path: &str) -> Result<ast::File> {
parser::parse(input, path)
}
pub fn collect_root_arg_defs(root: &ast::File, root_path: &str) -> Result<Vec<config::ArgDef>> {
let dir = lower::parent_dir_of(root_path);
let mut dir_context = HashMap::new();
dir_context.insert("__procman_dir__".to_string(), dir.clone());
dir_context.insert("__module_dir__".to_string(), dir);
let sorted = lower::topo_sort_args(&root.args)?;
let mut defs = vec![None; root.args.len()];
for idx in &sorted {
let arg = &root.args[*idx];
let def = lower::lower_arg_def_ref(arg, None, &dir_context)?;
if let Some(ref val) = def.default {
dir_context.insert(arg.name.clone(), val.clone());
}
defs[*idx] = Some(def);
}
Ok(defs.into_iter().map(|d| d.unwrap()).collect())
}
pub fn load_with_args(
root: ast::File,
path: &str,
root_arg_values: &HashMap<String, String>,
check_mode: bool,
) -> Result<(loader::LoadedModules, config::ConfigHeader)> {
let modules = loader::load_with_root(root, path, root_arg_values, check_mode)?;
let header = build_config_header(&modules)?;
Ok((modules, header))
}
pub fn load_header(
input: &str,
path: &str,
) -> Result<(loader::LoadedModules, config::ConfigHeader)> {
let modules = loader::load(input, path)?;
let header = build_config_header(&modules)?;
Ok((modules, header))
}
fn build_config_header(modules: &loader::LoadedModules) -> Result<config::ConfigHeader> {
let log_dir = modules
.root
.config
.as_ref()
.and_then(|c| c.logs.as_ref().map(|l| l.value.clone()));
let log_time = modules
.root
.config
.as_ref()
.and_then(|c| c.log_time)
.unwrap_or(false);
let root_dir = lower::parent_dir_of(&modules.root_path);
let mut root_dir_context = HashMap::new();
root_dir_context.insert("__procman_dir__".to_string(), root_dir.clone());
root_dir_context.insert("__module_dir__".to_string(), root_dir);
let mut arg_defs: Vec<config::ArgDef> = modules
.root
.args
.iter()
.map(|a| lower::lower_arg_def_ref(a, None, &root_dir_context))
.collect::<Result<_>>()?;
for import_def in &modules.root.imports {
let alias = &import_def.alias;
if let Some(module) = modules.imports.get(alias) {
let module_dir = lower::parent_dir_of(&module.path);
let mut mod_dir_context = HashMap::new();
mod_dir_context.insert(
"__procman_dir__".to_string(),
root_dir_context["__procman_dir__"].clone(),
);
mod_dir_context.insert("__module_dir__".to_string(), module_dir);
let bound_names: HashSet<&str> = import_def
.bindings
.iter()
.map(|b| b.name.as_str())
.collect();
for arg_def in &module.file.args {
let has_binding = bound_names.contains(arg_def.name.as_str());
let has_default = arg_def.default.is_some();
if !has_binding && !has_default {
arg_defs.push(lower::lower_arg_def_ref(
arg_def,
Some(alias),
&mod_dir_context,
)?);
}
}
}
}
Ok(config::ConfigHeader {
log_dir,
log_time,
arg_defs,
})
}
pub fn lower_loaded(
modules: &loader::LoadedModules,
extra_env: &HashMap<String, String>,
arg_values: &HashMap<String, String>,
) -> Result<(
Vec<crate::config::ProcessConfig>,
Option<String>,
ModuleArgsReport,
)> {
lower::lower_modules(modules, extra_env, arg_values)
}