use clap::{Parser, Subcommand}; use std::env; use std::path::{Path, PathBuf}; use std::process::Command; #[derive(Parser)] #[command(name = "prometeu")] #[command(about = "Dispatcher for the Prometeu ecosystem", long_about = None)] struct Cli { #[command(subcommand)] command: Option, } #[derive(Subcommand)] enum Commands { /// Executes a cartridge Run { /// Path to the cartridge cart: String, }, /// Debugs a cartridge Debug { /// Path to the cartridge cart: String, /// Port for the debugger (default: 7777) #[arg(long, default_value_t = 7777)] port: u16, }, /// Builds a project Build { /// Project directory project_dir: String, }, /// Packages a cartridge Pack { /// Cartridge directory cart_dir: String, }, /// Verifies the integrity of a project or cartridge Verify { #[command(subcommand)] target: VerifyCommands, }, } #[derive(Subcommand)] enum VerifyCommands { /// Verifies a project C { /// Project directory project_dir: String, }, /// Verifies a cartridge or PMC file P { /// Path to the cartridge or PMC cart_or_pmc: String, }, } fn main() { let cli = Cli::parse(); let exe_dir = match env::current_exe() { Ok(exe_path) => exe_path.parent().unwrap_or_else(|| Path::new(".")).to_path_buf(), Err(e) => { eprintln!("Error obtaining executable path: {}", e); std::process::exit(1); } }; match cli.command { Some(Commands::Run { cart }) => { dispatch(&exe_dir, "prometeu-runtime", &["--run", &cart]); } Some(Commands::Debug { cart, port }) => { dispatch( &exe_dir, "prometeu-runtime", &["--debug", &cart, "--port", &port.to_string()], ); } Some(Commands::Build { .. }) => { not_implemented("build", "prometeuc"); } Some(Commands::Pack { .. }) => { not_implemented("pack", "prometeup"); } Some(Commands::Verify { target }) => match target { VerifyCommands::C { .. } => not_implemented("verify c", "prometeuc"), VerifyCommands::P { .. } => not_implemented("verify p", "prometeup"), }, None => { use clap::CommandFactory; Cli::command().print_help().unwrap(); println!(); } } } fn get_binary_path(dir: &Path, name: &str) -> PathBuf { let mut path = dir.join(name); if cfg!(target_os = "windows") { path.set_extension("exe"); } path } fn dispatch(exe_dir: &Path, bin_name: &str, args: &[&str]) { let bin_path = get_binary_path(exe_dir, bin_name); if !bin_path.exists() { // Tries to find the runtime with the exact name (prometeu-runtime-desktop) // in case prometeu-runtime is just an alias or link that doesn't exist yet let alt_bin_name = if bin_name == "prometeu-runtime" { Some("prometeu-runtime-desktop") } else { None }; let final_bin_path = if let Some(alt_name) = alt_bin_name { let alt_path = get_binary_path(exe_dir, alt_name); if alt_path.exists() { alt_path } else { bin_path } } else { bin_path }; if !final_bin_path.exists() { eprintln!( "prometeu: command '{}' is not yet available in this distribution", match bin_name { "prometeu-runtime" => "run/debug", "prometeuc" => "build/verify c", "prometeup" => "pack/verify p", _ => bin_name, } ); std::process::exit(1); } execute_bin(&final_bin_path, args); } else { execute_bin(&bin_path, args); } } fn execute_bin(bin_path: &Path, args: &[&str]) { let status = Command::new(bin_path) .args(args) .stdin(std::process::Stdio::inherit()) .stdout(std::process::Stdio::inherit()) .stderr(std::process::Stdio::inherit()) .status(); match status { Ok(status) => { std::process::exit(status.code().unwrap_or(0)); } Err(e) => { eprintln!("Error executing {}: {}", bin_path.display(), e); std::process::exit(1); } } } fn not_implemented(cmd: &str, _bin_name: &str) { eprintln!( "prometeu: command '{}' is not yet available in this distribution", cmd ); std::process::exit(1); }