From 0d03a0fbc214dd3fb9a8af562f9d88cccaf5f2c0 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Sun, 26 Dec 2021 21:54:26 +0100 Subject: [PATCH] refactor commands --- planetwars-cli/src/commands/init.rs | 38 +++++++ planetwars-cli/src/commands/mod.rs | 36 +++++++ planetwars-cli/src/commands/run_match.rs | 61 +++++++++++ planetwars-cli/src/commands/serve.rs | 18 ++++ planetwars-cli/src/lib.rs | 125 +---------------------- 5 files changed, 156 insertions(+), 122 deletions(-) create mode 100644 planetwars-cli/src/commands/init.rs create mode 100644 planetwars-cli/src/commands/mod.rs create mode 100644 planetwars-cli/src/commands/run_match.rs create mode 100644 planetwars-cli/src/commands/serve.rs diff --git a/planetwars-cli/src/commands/init.rs b/planetwars-cli/src/commands/init.rs new file mode 100644 index 0000000..42491bc --- /dev/null +++ b/planetwars-cli/src/commands/init.rs @@ -0,0 +1,38 @@ +use std::path::PathBuf; + +use clap::Parser; +use futures::io; + +#[derive(Parser)] +pub struct InitCommand { + /// project root directory + path: String, +} + +macro_rules! copy_asset { + ($path:expr, $file_name:literal) => { + ::std::fs::write( + $path.join($file_name), + include_bytes!(concat!("../../assets/", $file_name)), + )?; + }; +} + +impl InitCommand { + pub async fn run(self) -> io::Result<()> { + let path = PathBuf::from(&self.path); + + // create directories + std::fs::create_dir_all(&path)?; + std::fs::create_dir(path.join("maps"))?; + std::fs::create_dir(path.join("matches"))?; + std::fs::create_dir_all(path.join("bots/simplebot"))?; + + // create files + copy_asset!(path, "pw_project.toml"); + copy_asset!(path.join("maps"), "hex.json"); + copy_asset!(path.join("bots/simplebot"), "simplebot.py"); + + Ok(()) + } +} diff --git a/planetwars-cli/src/commands/mod.rs b/planetwars-cli/src/commands/mod.rs new file mode 100644 index 0000000..6606c77 --- /dev/null +++ b/planetwars-cli/src/commands/mod.rs @@ -0,0 +1,36 @@ +mod init; +mod run_match; +mod serve; + +use clap::{Parser, Subcommand}; +use std::io; + +#[derive(Parser)] +#[clap(name = "pwcli")] +#[clap(author, version, about)] +pub struct Cli { + #[clap(subcommand)] + command: Command, +} + +impl Cli { + pub async fn run() -> io::Result<()> { + let cli = Self::parse(); + + match cli.command { + Command::Init(command) => command.run().await, + Command::RunMatch(command) => command.run().await, + Command::Serve(command) => command.run().await, + } + } +} + +#[derive(Subcommand)] +enum Command { + /// Initialize a new project + Init(init::InitCommand), + /// Run a match + RunMatch(run_match::RunMatchCommand), + /// Host local webserver + Serve(serve::ServeCommand), +} diff --git a/planetwars-cli/src/commands/run_match.rs b/planetwars-cli/src/commands/run_match.rs new file mode 100644 index 0000000..a5512f4 --- /dev/null +++ b/planetwars-cli/src/commands/run_match.rs @@ -0,0 +1,61 @@ +use std::env; +use std::io; + +use clap::Parser; + +use crate::match_runner; +use crate::match_runner::MatchBot; +use crate::match_runner::MatchConfig; +use crate::resolve_bot_config; +use crate::ProjectConfig; + +#[derive(Parser)] +pub struct RunMatchCommand { + /// map name + map: String, + /// bot names + bots: Vec, +} + +impl RunMatchCommand { + pub async fn run(self) -> io::Result<()> { + let project_dir = env::current_dir().unwrap(); + + let config_path = project_dir.join("pw_project.toml"); + + let map_path = project_dir.join(format!("maps/{}.json", self.map)); + + let timestamp = chrono::Local::now().format("%Y-%m-%d-%H-%M-%S"); + let log_path = project_dir.join(format!("matches/{}.log", timestamp)); + + let config_str = std::fs::read_to_string(config_path).unwrap(); + let project_config: ProjectConfig = toml::from_str(&config_str).unwrap(); + + let players = self + .bots + .into_iter() + .map(|bot_name| { + let bot_config = project_config.bots.get(&bot_name).unwrap().clone(); + let resolved_config = resolve_bot_config(&project_dir, bot_config); + MatchBot { + name: bot_name, + bot_config: resolved_config, + } + }) + .collect(); + + let match_config = MatchConfig { + map_name: self.map, + map_path, + log_path, + players, + }; + + match_runner::run_match(match_config).await; + println!("match completed successfully"); + // TODO: don't hardcode match path. + // maybe print the match result as well? + println!("wrote match log to matches/{}.log", timestamp); + Ok(()) + } +} diff --git a/planetwars-cli/src/commands/serve.rs b/planetwars-cli/src/commands/serve.rs new file mode 100644 index 0000000..2a2e59b --- /dev/null +++ b/planetwars-cli/src/commands/serve.rs @@ -0,0 +1,18 @@ +use std::env; +use std::io; + +use clap::Parser; + +use crate::web; + +#[derive(Parser)] +pub struct ServeCommand; + +impl ServeCommand { + pub async fn run(self) -> io::Result<()> { + let project_dir = env::current_dir().unwrap(); + + web::run(project_dir).await; + Ok(()) + } +} diff --git a/planetwars-cli/src/lib.rs b/planetwars-cli/src/lib.rs index 7eea75a..de9905d 100644 --- a/planetwars-cli/src/lib.rs +++ b/planetwars-cli/src/lib.rs @@ -1,51 +1,12 @@ -use match_runner::{MatchBot, MatchConfig}; use serde::Deserialize; +mod commands; mod match_runner; +mod web; use serde::Serialize; use std::collections::HashMap; -use std::env; -use std::io; use std::path::{Path, PathBuf}; -use toml; - -use clap::{Parser, Subcommand}; - -#[derive(Parser)] -#[clap(name = "pwcli")] -#[clap(author, version, about)] -struct Cli { - #[clap(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - /// Initialize a new project - InitProject(InitProjectCommand), - /// Run a match - RunMatch(RunMatchCommand), - /// Host local webserver - Serve(ServeCommand), -} - -#[derive(Parser)] -struct RunMatchCommand { - /// map name - map: String, - /// bot names - bots: Vec, -} - -#[derive(Parser)] -struct InitProjectCommand { - /// project root directory - path: String, -} - -#[derive(Parser)] -struct ServeCommand; #[derive(Serialize, Deserialize, Debug)] struct ProjectConfig { @@ -59,59 +20,13 @@ pub struct BotConfig { } pub async fn run() { - let matches = Cli::parse(); - let res = match matches.command { - Commands::RunMatch(command) => run_match(command).await, - Commands::InitProject(command) => init_project(command), - Commands::Serve(_) => run_webserver().await, - }; + let res = commands::Cli::run().await; if let Err(err) = res { eprintln!("{}", err); std::process::exit(1); } } -async fn run_match(command: RunMatchCommand) -> io::Result<()> { - let project_dir = env::current_dir().unwrap(); - - let config_path = project_dir.join("pw_project.toml"); - - let map_path = project_dir.join(format!("maps/{}.json", command.map)); - - let timestamp = chrono::Local::now().format("%Y-%m-%d-%H-%M-%S"); - let log_path = project_dir.join(format!("matches/{}.log", timestamp)); - - let config_str = std::fs::read_to_string(config_path).unwrap(); - let project_config: ProjectConfig = toml::from_str(&config_str).unwrap(); - - let players = command - .bots - .into_iter() - .map(|bot_name| { - let bot_config = project_config.bots.get(&bot_name).unwrap().clone(); - let resolved_config = resolve_bot_config(&project_dir, bot_config); - MatchBot { - name: bot_name, - bot_config: resolved_config, - } - }) - .collect(); - - let match_config = MatchConfig { - map_name: command.map, - map_path, - log_path, - players, - }; - - match_runner::run_match(match_config).await; - println!("match completed successfully"); - // TODO: don't hardcode match path. - // maybe print the match result as well? - println!("wrote match log to matches/{}.log", timestamp); - Ok(()) -} - fn resolve_bot_config(project_dir: &Path, config: BotConfig) -> BotConfig { let mut path = PathBuf::from(project_dir); path.push(&config.path); @@ -120,37 +35,3 @@ fn resolve_bot_config(project_dir: &Path, config: BotConfig) -> BotConfig { argv: config.argv, } } - -macro_rules! copy_asset { - ($path:expr, $file_name:literal) => { - ::std::fs::write( - $path.join($file_name), - include_bytes!(concat!("../assets/", $file_name)), - )?; - }; -} - -fn init_project(command: InitProjectCommand) -> io::Result<()> { - let path = PathBuf::from(&command.path); - - // create directories - std::fs::create_dir_all(&path)?; - std::fs::create_dir(path.join("maps"))?; - std::fs::create_dir(path.join("matches"))?; - std::fs::create_dir_all(path.join("bots/simplebot"))?; - - // create files - copy_asset!(path, "pw_project.toml"); - copy_asset!(path.join("maps"), "hex.json"); - copy_asset!(path.join("bots/simplebot"), "simplebot.py"); - - Ok(()) -} - -mod web; -async fn run_webserver() -> io::Result<()> { - let project_dir = env::current_dir().unwrap(); - - web::run(project_dir).await; - Ok(()) -}