use std::env;
use std::path::PathBuf;
use std::process::{Command, ExitCode};
fn main() -> ExitCode {
let mut forwarded: Vec<String> = env::args().skip(1).collect();
forwarded.insert(0, "server".to_string());
let invoked = env::args().next().unwrap_or_else(|| "athena-server".to_string());
match resolve_and_run(&forwarded, &invoked) {
Ok(exit_code) => exit_code,
Err(err) => {
eprintln!("{}: {}", invoked, err);
eprintln!();
eprintln!("Hints:");
eprintln!(" • Recommended: athena server (or just `athena`)");
eprintln!(" • Runtime: athena_rs server");
eprintln!(" • Build: cargo build --bin athena --bin athena_rs --bin athena-server");
ExitCode::from(1)
}
}
}
fn resolve_and_run(args: &[String], invoked: &str) -> std::io::Result<ExitCode> {
let athena = find_athena_binary()?;
if std::env::var("ATHENA_LAUNCHER_QUIET").is_err() && !is_sibling_path(&athena) {
let label = std::path::Path::new(invoked)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("athena-server");
eprintln!("[{}] → {}", label, athena.display());
}
let status = Command::new(&athena)
.args(args)
.status()?;
match status.code() {
Some(code) if code >= 0 && code <= 255 => Ok(ExitCode::from(code as u8)),
_ => Ok(ExitCode::from(1)),
}
}
fn is_sibling_path(p: &std::path::Path) -> bool {
if let Ok(me) = std::env::current_exe() {
if let (Some(my_dir), Some(target_dir)) = (me.parent(), p.parent()) {
return my_dir == target_dir;
}
}
false
}
fn find_athena_binary() -> std::io::Result<PathBuf> {
if let Some(sib) = sibling_candidate() {
if sib.is_file() {
return Ok(sib);
}
}
if let Ok(p) = which::which("athena_rs") {
return Ok(p);
}
if let Ok(p) = which::which("athena") {
return Ok(p);
}
Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"could not find 'athena_rs' (Athena runtime) or 'athena'",
))
}
fn sibling_candidate() -> Option<PathBuf> {
let current = env::current_exe().ok()?;
let dir = current.parent()?;
let names = if cfg!(windows) {
["athena.exe", "athena_rs.exe"]
} else {
["athena", "athena_rs"]
};
for name in names {
let p = dir.join(name);
if p.is_file() {
return Some(p);
}
}
None
}