use clap::{Parser, Subcommand}; use std::{os::unix::process::ExitStatusExt, process::{Command, ExitStatus}}; const WEB_BUILD_DIR: &str = "web-build"; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Cli { #[command(subcommand)] command: Commands, } #[derive(Subcommand, Debug)] enum Commands { /// Builds the website and server, including wasm files Build, /// Runs the server locally Start { /// Whether to build again or not #[arg(long)] rebuild: bool, }, /// Generates new encryption keys GenKeys { /// How many keypairs to generate #[arg(short, long, default_value = "100")] number: usize, /// Directory to put the generated secret key files #[arg(short, long, default_value = ".local/secrets.json")] sk_out_dir: String, /// Directory to put the generated pubklic key pool #[arg(long, default_value = "target/public_keys.json")] pk_out_dir: String, }, /// Reads fetched messages ReadMessages { /// Source file path #[arg(short, long, default_value = ".local/messages")] source: String, /// Optional output file path for decoded messages /// Default: stdout #[arg(short, long)] out_dir: Option, }, } fn main() { let cli = Cli::parse(); match &cli.command { Commands::Build => { println!("Executing build command..."); build(); } Commands::Start { rebuild } => { println!("Starting server..."); if *rebuild { println!("Rebuilding web pages..."); build(); } // Change the current working directory of the running Rust program println!("Changing directory to {WEB_BUILD_DIR}..."); let cd_result = std::env::set_current_dir(WEB_BUILD_DIR); // Use the existing helper to check the result handle_command_status( cd_result.map(|_| std::process::ExitStatus::from_raw(0)), "cd build dir", ); println!("Running server executable..."); // Now run the server executable from within the new current directory handle_command_status(Command::new("./server").status(), "run server"); } Commands::GenKeys { number, sk_out_dir, pk_out_dir, } => { println!("Executing gen-keys command..."); message_tools::gen_keys::generate_keys_to_file(pk_out_dir, sk_out_dir, *number) .expect("write key files"); } Commands::ReadMessages { .. } => { println!("Executing read-messages command..."); // Add your message reading logic here } } } // A helper function to process the Result fn handle_command_status(status_result: std::io::Result, command_name: &str) { match status_result { Ok(exit_status) => { if !exit_status.success() { eprintln!( "\nCommand '{}' failed with exit code: {:?}", command_name, exit_status.code() ); std::process::exit(exit_status.code().unwrap_or(1)); } } Err(e) => { eprintln!("\nFailed to execute command '{}': {}", command_name, e); std::process::exit(1); // Exit with an error code } } } fn build() { println!("Building wasm package..."); // build the wasm package let status = Command::new("wasm-pack") .arg("build") .arg("--out-dir") .arg("../../routes/contact/pkg") .arg("crates/message-tools") .arg("--target") .arg("no-modules") .status(); handle_command_status(status, "wasm-pack build"); println!("Building server executable..."); // build the server executable let status = Command::new("cargo") .arg("build") .arg("--release") .args(["-p", "server"]) .args(["--target", "x86_64-unknown-linux-musl"]) .status(); handle_command_status(status, "cargo build server"); let server_bin = "target/x86_64-unknown-linux-musl/release/server"; println!("Creating build directory..."); // make webpage build directory if it doesn't already exist let status = Command::new("mkdir").args(["-p", WEB_BUILD_DIR]).status(); handle_command_status(status, "mkdir web-build"); println!("Copying files..."); // copy relevant files let status = Command::new("cp") .args(["-R", "routes"]) .arg(format!("{WEB_BUILD_DIR}/routes")) .status(); handle_command_status(status, "cp routes"); let status = Command::new("cp") .arg(server_bin) .arg(format!("{WEB_BUILD_DIR}")) .status(); handle_command_status(status, "cp server bin"); let pubkey_file = "target/public_keys.json"; if !std::path::Path::new(pubkey_file).exists() { panic!("No public key file. Please generate keys first."); } let status = Command::new("mkdir") .args(["-p", &format!("{WEB_BUILD_DIR}/pubkeys")]) .status(); handle_command_status(status, "mkdir web-build"); let status = Command::new("cp") .arg("target/public_keys.json") .arg(format!("{WEB_BUILD_DIR}/pubkeys/")) .status(); handle_command_status(status, "cp pubkeys"); println!("\nBuild successful!"); }