use crate::cmd::enforce_commands; use crate::commands::api::{build_api, build_api_prod, run_api, run_api_prod}; use crate::commands::assets::build_assets; use crate::commands::clean::clean; use crate::commands::client::{build_client_prod, client_protobuf, run_http}; use crate::commands::docker::{ build_docker, build_docker_api, build_docker_api_beta, build_docker_api_stable, build_docker_beta, build_docker_server, build_docker_server_beta, build_docker_server_stable, build_docker_stable, build_docker_web, build_docker_web_beta, build_docker_web_stable, }; use crate::commands::server::{build_server, build_server_prod, run_server, run_server_prod}; use std::collections::HashMap; use std::error::Error; use std::io::Write; use std::path::PathBuf; use std::time::SystemTime; use tabwriter::TabWriter; pub mod cmd; pub mod commands; pub mod config; pub mod configure; pub mod ninja; fn main() { let mut bcm = BuildCommandManager::new(); bcm.register( "run_http", Box::new(run_http), "Compile the client and then run a development HTTP server", false, ); bcm.register( "build_assets", Box::new(build_assets), "Compile the asset source files into spritesheets", false, ); bcm.register( "client_protobuf", Box::new(client_protobuf), "Update the client protocol bindings", false, ); bcm.register( "clean", Box::new(clean), "Remove all compilation artifacts", false, ); bcm.register( "build_api", Box::new(build_api), "Compile the API server", false, ); bcm.register("run_api", Box::new(run_api), "Run the API server", false); bcm.register( "build_api_prod", Box::new(build_api_prod), "Compile the API server with optimizations", false, ); bcm.register( "run_api_prod", Box::new(run_api_prod), "Run the API server with optimizations", false, ); bcm.register( "build_server", Box::new(build_server), "Compile the game server", false, ); bcm.register( "run_server", Box::new(run_server), "Run the game server", false, ); bcm.register( "build_server_prod", Box::new(build_server_prod), "Compile the game server with optimizations", false, ); bcm.register( "run_server_prod", Box::new(run_server_prod), "Run the game server with optimizations", false, ); bcm.register( "build_docker_beta", Box::new(build_docker_beta), "Build all three docker images for the beta channel", false, ); bcm.register( "build_docker_api_beta", Box::new(build_docker_api_beta), "Build the API docker image for the beta channel", false, ); bcm.register( "build_docker_server_beta", Box::new(build_docker_server_beta), "Build the main docker image for the beta channel", false, ); bcm.register( "build_docker_web_beta", Box::new(build_docker_web_beta), "Build the webserver docker image for the beta channel", false, ); bcm.register( "build_docker_stable", Box::new(build_docker_stable), "Build all three docker images for the stable channel", false, ); bcm.register( "build_docker_api_stable", Box::new(build_docker_api_stable), "Build the API docker image for the stable channel", false, ); bcm.register( "build_docker_server_stable", Box::new(build_docker_server_stable), "Build the main docker image for the stable channel", false, ); bcm.register( "build_docker_web_stable", Box::new(build_docker_web_stable), "Build the webserver docker image for the stable channel", false, ); bcm.register( "build_docker", Box::new(build_docker), "Build all three docker images for the bleeding channel", false, ); bcm.register( "build_docker_api", Box::new(build_docker_api), "Build the API docker image for the bleeding channel", false, ); bcm.register( "build_docker_server", Box::new(build_docker_server), "Build the main docker image for the bleeding channel", false, ); bcm.register( "build_docker_web", Box::new(build_docker_web), "Build the webserver docker image for the bleeding channel", false, ); bcm.register( "build_client_prod", Box::new(build_client_prod), "Build the production-ready client bundle", false, ); let start = SystemTime::now(); let args: Vec = std::env::args().collect(); match bcm.exec(args) { Ok(_) => (), Err(e) => { let end = SystemTime::now(); let duration = end.duration_since(start).unwrap(); println!("[spacetime] Done in {} seconds", duration.as_secs_f32()); eprintln!("[!] Error executing build command: {}", e); std::process::exit(-1); } } let end = SystemTime::now(); let duration = end.duration_since(start).unwrap(); println!("[spacetime] Done in {} seconds", duration.as_secs_f32()); } type BuildCommandCallback = Box, PathBuf) -> Result<(), Box>>; #[derive(Default)] pub struct BuildCommandManager { commands: HashMap, } impl BuildCommandManager { pub fn new() -> Self { Self { commands: HashMap::new(), } } pub fn register( &mut self, name: &str, command: BuildCommandCallback, description: &str, hidden: bool, ) { self.commands .insert(name.to_string(), (command, description.to_string(), hidden)); } pub fn help(&self) { println!("Spacetime - StarKingdoms build utility"); println!("Spacetime is a small Rust utility to assist in compiling StarKingdoms."); println!("Available targets:"); let mut tw = TabWriter::new(vec![]); for (target, (_, description, hidden)) in &self.commands { if *hidden { continue; }; writeln!(tw, "\t{}\t{}", target, description).unwrap(); } std::io::stdout() .write_all(&tw.into_inner().unwrap()) .unwrap(); } pub fn exec(&self, args: Vec) -> Result<(), Box> { if args.len() < 2 || args[1] == "help" || args[1] == "h" { self.help(); return Ok(()); } enforce_commands(); let main_path = PathBuf::from(args[2].to_string()); if let Some((callback, _, _)) = self.commands.get(&args[1]) { callback(args[2..].to_owned(), main_path) } else { eprintln!("Unrecognized build command {}", args[1]); self.help(); Ok(()) } } }