use std::{
env::current_dir,
ffi::OsStr,
fs::{create_dir, create_dir_all},
io::Write,
path::PathBuf,
sync::{Arc, OnceLock},
};
use anyhow::bail;
use cliargs::parse_args;
use console::style;
use env_logger::Env;
use indicatif::MultiProgress;
use indicatif_log_bridge::LogWrapper;
use lazy_static::lazy_static;
use log::warn;
use crate::envs::HOME;
use crate::envs::LOCALAPPDATA;
pub mod caching;
pub mod cliargs;
pub mod config;
pub mod plugin;
pub mod pom;
pub mod submodules;
pub mod tui;
lazy_static! {
pub static ref MULTI_PROGRESS_BAR: Arc<MultiProgress> = Arc::new(MultiProgress::new());
}
static PROJECT_ROOT: OnceLock<PathBuf> = OnceLock::new();
static LABT_HOME_PATH: OnceLock<PathBuf> = OnceLock::new();
pub const LABT_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const USER_AGENT: &str = concat!("Labt/", env!("CARGO_PKG_VERSION"));
pub const TARGET: &str = env!("TARGET");
pub mod envs {
pub const LABT_HOME: &str = "LABT_HOME";
pub const HOME: &str = "HOME";
pub const LOCALAPPDATA: &str = "LOCALAPPDATA";
}
pub fn get_home() -> anyhow::Result<PathBuf> {
get_home_ref().cloned()
}
#[cfg(not(target_os = "windows"))]
pub fn get_home_ref() -> anyhow::Result<&'static PathBuf> {
if let Some(path) = LABT_HOME_PATH.get() {
return Ok(path);
}
if let Ok(path) = std::env::var(envs::LABT_HOME) {
return Ok(LABT_HOME_PATH.get_or_init(|| PathBuf::from(path)));
}
if let Ok(path) = std::env::var(envs::HOME) {
let mut path = PathBuf::from(path);
path.push(".labt");
if path.exists() {
return Ok(LABT_HOME_PATH.get_or_init(|| path));
} else {
bail!(std::io::Error::new(
std::io::ErrorKind::NotFound,
".labt folder does not exist on $HOME",
));
}
}
bail!("No apropriate Labt home directory detected!");
}
#[cfg(target_os = "windows")]
pub fn get_home_ref() -> anyhow::Result<&'static PathBuf> {
if let Some(path) = LABT_HOME_PATH.get() {
return Ok(path);
}
if let Ok(path) = std::env::var(envs::LABT_HOME) {
return Ok(LABT_HOME_PATH.get_or_init(|| PathBuf::from(path)));
}
if let Ok(path) = std::env::var(envs::LOCALAPPDATA) {
let mut path = PathBuf::from(path);
path.push(".labt");
if path.exists() {
return Ok(LABT_HOME_PATH.get_or_init(|| path));
} else {
bail!(std::io::Error::new(
std::io::ErrorKind::NotFound,
".labt folder does not exist on %LOCALAPPDATA%",
));
}
}
bail!("No apropriate Labt home directory detected!");
}
pub fn get_project_root<'a>() -> std::io::Result<&'a PathBuf> {
if let Some(path) = PROJECT_ROOT.get() {
return Ok(path);
}
let cwd = current_dir()?;
let path = get_project_root_recursive(cwd)?;
Ok(PROJECT_ROOT.get_or_init(|| path))
}
fn get_project_root_recursive(current_dir: PathBuf) -> std::io::Result<PathBuf> {
for entry in (current_dir.read_dir()?).flatten() {
let file = entry.path();
if file.is_file() && file.file_name() == Some(OsStr::new("Labt.toml")) {
return Ok(current_dir);
}
}
if let Some(path) = current_dir.parent() {
get_project_root_recursive(PathBuf::from(path))
} else {
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Failed to get project root",
))
}
}
fn first_run(path: &mut PathBuf) -> anyhow::Result<()> {
path.push(".labt");
path.push("cache");
create_dir_all(path.clone())?;
path.pop();
path.push("plugins");
create_dir(path)?;
Ok(())
}
fn main() -> anyhow::Result<()> {
if get_home().is_err() {
if cfg!(windows) {
if let Ok(home) = std::env::var(LOCALAPPDATA) {
println!("Initializing LABt configs on home directory at {}.", home);
let mut path = PathBuf::from(home);
first_run(&mut path)?;
}
} else if let Ok(home) = std::env::var(HOME) {
println!("Initializing LABt configs on home directory.");
let mut path = PathBuf::from(home);
first_run(&mut path)?;
} else {
warn!(target: "labt", "Failed to initialize labt home, please set LABT_HOME environmental variable pointing to where you want LABt to store its files.");
}
};
let logger = env_logger::Builder::from_env(Env::default().default_filter_or("info"))
.format_timestamp(None)
.format(|buf, record| {
let level = match record.level() {
log::Level::Error => style("ERROR").red().bold(),
log::Level::Warn => style(" WARN").yellow().bold(),
log::Level::Info => style(" INFO").green().bold(),
log::Level::Debug => style("DEBUG").blue().bold(),
log::Level::Trace => style("TRACE").blue().bold(),
};
writeln!(
buf,
"{}{} {}{} {}",
style("[").dim(),
level,
style(record.target()).dim(),
style("]").dim(),
record.args()
)
})
.build();
let multi = Arc::clone(&MULTI_PROGRESS_BAR);
LogWrapper::new((*multi).clone(), logger).try_init()?;
parse_args();
Ok(())
}