use anyhow::Result;
mod app;
mod basemap;
mod basemap_artifact;
mod cache;
mod config;
mod decode;
mod fold_ui;
mod host;
mod library;
mod library_ui;
mod map;
mod model;
mod persist;
mod source;
mod spec;
mod state;
mod tray;
mod vector_map;
mod view;
mod witness;
mod worker;
mod xdg;
pub fn run() -> Result<()> {
cleanse_relative_xdg()?;
let mut arguments = std::env::args_os().skip(1);
let Some(command) = arguments.next() else {
return run_gui();
};
match command.to_str() {
Some("--help" | "-h" | "help") => {
print_help();
Ok(())
}
Some("--version" | "-V") => {
println!("hrrr {}", env!("CARGO_PKG_VERSION"));
Ok(())
}
Some("basemap") => run_basemap(arguments),
Some(other) => anyhow::bail!("unknown command `{other}`; run `hrrr --help`"),
None => anyhow::bail!("command is not valid UTF-8"),
}
}
pub fn run_gui() -> Result<()> {
let ctx = egui::Context::default();
dwemer_poolrooms::chrome::install(&ctx);
let trace = eternalist_apps::TraceGuard::arm()?;
let result = host::run(ctx);
trace.flush();
result
}
fn run_basemap(mut arguments: impl Iterator<Item = std::ffi::OsString>) -> Result<()> {
let operation = arguments
.next()
.and_then(|argument| argument.into_string().ok())
.unwrap_or_else(|| "status".to_owned());
let lair = xdg::Lair::claim()?;
match operation.as_str() {
"install" => {
let _instance = lair.lock_instance()?;
let day = arguments.next();
if arguments.next().is_some() {
anyhow::bail!("usage: hrrr basemap install [YYYYMMDD]");
}
let day = day
.as_deref()
.map(|day| {
day.to_str()
.ok_or_else(|| anyhow::anyhow!("basemap date is not valid UTF-8"))
})
.transpose()?;
let _installed = basemap_artifact::install(&lair, day)?;
Ok(())
}
"status" if arguments.next().is_none() => basemap_artifact::status(&lair),
"remove" if arguments.next().is_none() => {
let _instance = lair.lock_instance()?;
basemap_artifact::remove(&lair)
}
_ => anyhow::bail!(
"unknown basemap operation `{operation}`; expected install, status, or remove"
),
}
}
fn print_help() {
println!(
"\
HRRR native forecast-field viewer
Usage:
hrrr
hrrr basemap install [YYYYMMDD]
hrrr basemap status
hrrr basemap remove
hrrr --help
hrrr --version
The GUI reads NOAA HRRR forecast fields directly. `basemap install` explicitly
downloads the North American Protomaps core through zoom 11. Zoom 12 detail is
fetched only for visible tiles after the map enters that zoom and is retained
in the bounded disposable cache."
);
}
fn cleanse_relative_xdg() -> Result<()> {
const ROOTS: [&str; 5] = [
"XDG_CACHE_HOME",
"XDG_CONFIG_HOME",
"XDG_DATA_HOME",
"XDG_STATE_HOME",
"XDG_RUNTIME_DIR",
];
let invalid = ROOTS
.into_iter()
.filter(|name| {
std::env::var_os(name).is_some_and(|value| !std::path::Path::new(&value).is_absolute())
})
.collect::<Vec<_>>();
if invalid.is_empty() {
return Ok(());
}
reexec_without(&invalid)
}
#[cfg(unix)]
fn reexec_without(names: &[&str]) -> Result<()> {
use std::os::unix::process::CommandExt as _;
let executable = std::env::current_exe()?;
let mut command = std::process::Command::new(executable);
let _command = command.args(std::env::args_os().skip(1));
for name in names {
let _command = command.env_remove(name);
}
Err(command.exec().into())
}
#[cfg(not(unix))]
fn reexec_without(_names: &[&str]) -> Result<()> {
Ok(())
}