use core::panic; use std::{collections::HashMap, env::args, fs::read_to_string, process::exit}; use clap::Parser; mod content_generation; mod deser; mod parse_deser; mod validation; use content_generation::*; use deser::*; use parse_deser::*; /// ngen is a build file generator for the ninja build system. #[derive(Parser)] struct Args { /// Path to the toml configuration file #[arg(short, long, default_value = "ngen.toml")] config_file: String, /// Path to generated ninja file #[arg(short, long, default_value = "build.ninja")] output_file: String, #[arg(long, hide = true)] write_compile_commands: Option, } fn main() { let args = Args::parse(); let ngen_toml = read_to_string(&args.config_file) .unwrap_or_else(|e| panic!("error reading config file `{}`: {e}", args.config_file)); let deser_ngen_toml: DeserNgenToml = toml::from_str(&ngen_toml) .unwrap_or_else(|e| panic!("error parsing config file `{}`: {e}", args.config_file)); let target_option_list: TargetOptionList; let deser_target_list: &DeserTargetList; match &deser_ngen_toml.targets { Some(v) => { target_option_list = TargetOptionList::from(v); deser_target_list = &v; } None => panic!("no targets provided, nothing to do. Exiting"), }; target_option_list .check_for_dependency_cycle() .unwrap_or_else(|e| panic!("{e}. cannont continue. Exiting")); let inheritance_order = target_option_list .get_inheritance_order() .unwrap_or_else(|e| panic!("{e}. cannot continue. Exiting")); let mut target_list: TargetList = TargetList(HashMap::new()); for order in &inheritance_order { for name in order.into_iter().rev() { let opts = target_option_list.0.get(name as &str).unwrap(); let deser = deser_target_list.get(name as &str).unwrap(); let parent: Option<&Target>; if opts.inherit && (name != opts.inherit_from) { parent = Some(target_list.0.get(opts.inherit_from as &str).unwrap()); } else { parent = None; } target_list.0.insert(name, Target::new(opts, deser, parent)); } } target_list .check_if_any_sources_are_provided() .unwrap_or_else(|e| panic!("{e}, nothing to do. Exiting")); let config = match &deser_ngen_toml.config { Some(v) => Config::from(v), None => Config::get_default(), }; config .check_compile_commands_target(&target_list) .unwrap_or_else(|e| panic!("{e}")); if let Some(filename) = &args.write_compile_commands { let name = config.compile_commands_target; let target = target_list.0.get(name).unwrap(); let content = create_compile_commands_content(name, target, &config) .unwrap_or_else(|e| panic!("{e}")); write_compile_commands(filename, content.as_bytes()).unwrap_or_else(|e| { panic!("could not write compile commands file `{}`: {e}", filename) }); exit(0); } let ninja_file_content = create_ninja_file_content(&target_list, &config, &args).unwrap_or_else(|e| panic!("{e}")); write_ninja_file(&args.output_file, ninja_file_content.as_bytes()) .unwrap_or_else(|e| panic!("could not write ninja file `{}`: {e}", args.output_file)); }