mise 2024.1.16

The front-end to your dev env
extern crate simplelog;

use std::fs::{create_dir_all, File, OpenOptions};
use std::path::Path;

use crate::config::Settings;
use crate::env;
use miette::{IntoDiagnostic, Result};
use simplelog::*;

pub fn init(settings: &Settings) {
    static INIT: std::sync::Once = std::sync::Once::new();
    INIT.call_once(|| _init(settings));
}

pub fn _init(settings: &Settings) {
    if cfg!(test) {
        return;
    }
    let mut loggers: Vec<Box<dyn SharedLogger>> = vec![];
    let level = settings.log_level.parse().unwrap();
    loggers.push(init_term_logger(level));

    if let Some(log_file) = &*env::MISE_LOG_FILE {
        let file_level = env::MISE_LOG_FILE_LEVEL.unwrap_or(level);
        if let Some(logger) = init_write_logger(file_level, log_file) {
            loggers.push(logger)
        }
    }
    CombinedLogger::init(loggers).unwrap_or_else(|err| {
        eprintln!("mise: could not initialize logger: {err}");
    });
}

fn init_log_file(log_file: &Path) -> Result<File> {
    if let Some(log_dir) = log_file.parent() {
        create_dir_all(log_dir).into_diagnostic()?;
    }
    OpenOptions::new()
        .create(true)
        .append(true)
        .open(log_file)
        .into_diagnostic()
}

fn init_term_logger(level: LevelFilter) -> Box<dyn SharedLogger> {
    let trace_level = if level >= LevelFilter::Trace {
        LevelFilter::Error
    } else {
        LevelFilter::Off
    };
    TermLogger::new(
        level,
        ConfigBuilder::new()
            .set_time_level(LevelFilter::Off)
            .set_thread_level(trace_level)
            .set_location_level(trace_level)
            .set_target_level(trace_level)
            .build(),
        TerminalMode::Stderr,
        ColorChoice::Auto,
    )
}

fn init_write_logger(level: LevelFilter, log_path: &Path) -> Option<Box<dyn SharedLogger>> {
    match init_log_file(log_path) {
        Ok(log_file) => Some(WriteLogger::new(
            level,
            ConfigBuilder::new()
                .set_thread_level(LevelFilter::Trace)
                .build(),
            log_file,
        )),
        Err(err) => {
            eprintln!("mise: could not write to log file: {err}");

            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_init() {
        init(&Settings::get());
    }
}