use kconfig_parser::MacroLexer;
use kconfig_represent::{ConfigRegistry, LoadError};
use std::{
collections::HashMap,
fmt::Display,
mem::MaybeUninit,
path::{Path, PathBuf},
process::exit,
rc::Rc,
sync::{Mutex, Once},
};
use crate::util::{lex_from_file, parse};
use super::log::log_colored;
pub(crate) struct TagRegistry {
kconfig_path_expr: PathExpr,
dotconfig_path_expr: PathExpr,
config_registry: Rc<ConfigRegistry>,
dotconfig_load_error: Option<LoadError>,
}
pub(crate) struct PathExpr {
buf: PathBuf,
}
struct SingletonReader {
inner: Mutex<HashMap<String, TagRegistry>>,
}
impl TagRegistry {
pub(crate) fn register(tag: &str, kconfig_path_expr: PathExpr, dotconfig_path_expr: PathExpr) {
let mut me = singleton().inner.lock().unwrap();
match me.get(tag) {
Some(_) => (),
None => {
let mut lexer = MacroLexer::new(lex_from_file(&kconfig_path_expr.to_string()));
let ast = parse(&mut lexer);
let mut registry = match ConfigRegistry::new(&ast, &lexer.symbol_table()) {
Ok(registry) => registry,
Err(e) => {
panic!("⛔ {}", e);
}
};
let load_error: Option<LoadError> =
load_dot_config_into_registry(&mut registry, &dotconfig_path_expr);
me.insert(
tag.to_string(),
TagRegistry {
kconfig_path_expr,
dotconfig_path_expr,
config_registry: Rc::new(registry),
dotconfig_load_error: load_error,
},
);
}
}
}
pub(crate) fn report() {
let now = singleton().inner.lock().unwrap();
log_colored("Tag Registry Report", "----------");
for (tag, registry) in now.iter() {
log_colored(
&tag.to_string(),
&format!(
"Kconfig ({}) .config ({})",
registry.kconfig_path_expr, registry.dotconfig_path_expr
),
);
if let Some(load_error) = ®istry.dotconfig_load_error {
print!("{}", load_error.to_string())
}
}
log_colored("End Tag Registry Report", "----------");
}
pub(crate) fn get_config_registry(tag_name: &str) -> Rc<ConfigRegistry> {
let me = singleton().inner.lock().unwrap();
match me.get(tag_name) {
Some(registry) => registry.config_registry.clone(),
None => panic!("Tag {} not registered", tag_name),
}
}
}
impl PathExpr {
pub(crate) fn new(file: String, path: String) -> PathExpr {
let mut buf = PathBuf::new();
buf.push(path);
buf.push(file);
Self { buf }
}
}
impl Display for PathExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.buf.clone().into_os_string().into_string().unwrap()
)
}
}
fn singleton() -> &'static SingletonReader {
static mut SINGLETON: MaybeUninit<SingletonReader> = MaybeUninit::uninit();
static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
let singleton = SingletonReader {
inner: Mutex::new(HashMap::new()),
};
SINGLETON.write(singleton);
});
SINGLETON.assume_init_ref()
}
}
fn load_dot_config_into_registry(
registry: &mut ConfigRegistry,
dotconfig_path_expr: &PathExpr,
) -> Option<LoadError> {
let path = dotconfig_path_expr.to_string();
if Path::new(&path).exists() {
match registry.read_dotconfig_file(&path) {
Err(e) => Some(e),
Ok(_) => None,
}
} else {
log_colored("Severe Error", &format!("⛔ File {} not found", path));
exit(1);
}
}