mod args;
mod commands;
mod error;
mod exit;
mod locate;
mod term;
#[cfg(test)]
mod testing;
mod text;
mod values;
use std::process::ExitCode;
use std::sync::Arc;
use clap::Parser;
use isothrum_runner::{Runner, RunnerConfig, SystemProcesses};
use crate::args::Cli;
use crate::error::Result;
use crate::exit::Verdict;
use crate::term::Term;
#[tokio::main]
async fn main() -> ExitCode {
let cli = Cli::parse();
let term = Term::std();
let var = |name: &str| std::env::var(name).ok();
if let Some(level) = var("ISOTHRUM_LOG")
&& let Err(e) = trace_to_stderr(&level)
{
term.err(&format!("warning: ISOTHRUM_LOG={level}: {e}"));
}
let outcome = start(&cli, &term, &var).await;
let outcome = outcome.and_then(|verdict| term.finish().map(|()| verdict));
if let Err(e) = &outcome {
term.err(&format!("error: {e}"));
}
exit::code(&outcome)
}
fn trace_to_stderr(level: &str) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
let level: tracing::Level = level.parse()?;
tracing_subscriber::fmt().with_max_level(level).with_writer(std::io::stderr).try_init()
}
async fn start(cli: &Cli, term: &Term, var: &dyn Fn(&str) -> Option<String>) -> Result<Verdict> {
let user_home = std::env::home_dir();
let home = locate::home(cli.home.clone(), var("ISOTHRUM_HOME"), user_home.clone())?;
let mut config = RunnerConfig::new(home);
config.processes = Arc::new(SystemProcesses::for_host(var, user_home.as_deref()));
let runner = Runner::new(config)?;
commands::run(cli, &runner, term, var).await
}