diff --git a/Cargo.toml b/Cargo.toml index d4e8eca..ec4ada1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = ["cli"] [workspace.package] -version = "0.5.0" +version = "0.5.1" edition = "2024" repository = "https://2ndbeam.ru/git/2ndbeam/squad-quest" license = "MIT" diff --git a/cfg/config.toml b/cfg/config.toml index 1d81f41..0a9e166 100644 --- a/cfg/config.toml +++ b/cfg/config.toml @@ -1,10 +1,4 @@ -# Default config - -# Path to quests folder relative to config -quests_path = "./quests" - -# Path to accounts folder relative to config -accounts_path = "./accounts" - -# Path to map .toml file relative to config -map = "./map.toml" +quests_path = "quests" +accounts_path = "accounts" +map = "map.toml" +verbose = true diff --git a/cli/src/cli/mod.rs b/cli/src/cli/mod.rs index e44c361..db78d60 100644 --- a/cli/src/cli/mod.rs +++ b/cli/src/cli/mod.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use clap::{Parser,Subcommand}; +use clap::{Args,Parser,Subcommand}; pub mod account; pub mod map; @@ -23,6 +23,8 @@ pub struct Cli { #[derive(Subcommand)] pub enum Objects { + /// Initialize new SquadQuest in current working directory + Init(InitArgs), /// Operations on the quests #[command(subcommand)] Quest(quest::QuestCommands), @@ -34,3 +36,8 @@ pub enum Objects { Map(map::MapCommands), } +#[derive(Args)] +pub struct InitArgs { + #[arg(long,short)] + pub path: Option, +} diff --git a/cli/src/main.rs b/cli/src/main.rs index 31b5b41..d120a9d 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::{fs::DirBuilder, path::{Path, PathBuf}}; use clap::Parser; use squad_quest_cli::cli::{Cli,Objects,account::*,map::*,quest::*}; @@ -25,19 +25,17 @@ fn do_and_log(result: Result<(),Error>, log: bool, ok_text: String) { } } -fn main() { - let cli = Cli::parse(); - - let config = match cli.quiet { - false => Config::load(cli.config.clone()), +fn load_config_silent(quiet: bool, path: PathBuf) -> Config { + match quiet { + false => Config::load(path.clone()), true => { - match Config::try_load(cli.config.clone()) { + match Config::try_load(path.clone()) { Ok(mut config) => { config.verbose = false; config }, Err(_) => { - let path = cli.config.clone().parent().unwrap_or(&Path::new(".")).to_owned(); + let path = path.clone().parent().unwrap_or(&Path::new(".")).to_owned(); Config { verbose: false, path, @@ -46,9 +44,61 @@ fn main() { } } }, - }; + } +} + +fn main() { + let cli = Cli::parse(); + + let config = load_config_silent(cli.quiet, cli.config.clone()); + let map_save = |map: Map, map_path: PathBuf| { map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) }; match &cli.command { + Objects::Init(args) => { + let path = match args.path.clone() { + Some(path) => path, + None => PathBuf::new(), + }; + + match DirBuilder::new().recursive(true).create(path.clone()) { + Ok(_) if !cli.quiet => println!("Created directory {:?}", path), + Err(error) => { + if !cli.quiet { eprintln!("Error: {error}"); } + return; + }, + _ => {}, + } + + let config = Config { + path: path.clone(), + ..Default::default() + }; + + do_and_log(config.save(path.clone()), !cli.quiet, format!("Created file {:?}/config.toml", path)); + let mut config_path = path.clone(); + config_path.push("config.toml"); + let mut config = load_config_silent(true, config_path); + config.verbose = Config::default().verbose; + + let map = Map::default(); + let map_path = config.full_map_path(); + + do_and_log(map_save(map, map_path.clone()), !cli.quiet, format!("Created file {:?}/map.toml", map_path)); + + let quests_path = config.full_quests_path(); + let accounts_path = config.full_accounts_path(); + + for path in [quests_path, accounts_path] { + match DirBuilder::new().recursive(true).create(path.clone()) { + Ok(_) if !cli.quiet => println!("Created directory {:?}", path), + Err(error) => { + if !cli.quiet { eprintln!("Error: {error}"); } + return; + }, + _ => {}, + } + } + }, Objects::Quest(commands) => { let mut quests = config.load_quests(); let mut path = config.full_quests_path(); @@ -289,7 +339,6 @@ fn main() { } }; - let map_save = |map: Map, map_path: PathBuf| { map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) }; match commands { MapCommands::List => { for room in map.room { diff --git a/src/config/mod.rs b/src/config/mod.rs index c805002..f0b2f94 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,12 +1,12 @@ //! Configuration file that handles (de-)serializing other components -use std::{fs::{self, DirEntry},path::{Path, PathBuf}}; -use serde::Deserialize; +use std::{fs::{self, DirEntry}, io::Write, path::{Path, PathBuf}}; +use serde::{Deserialize, Serialize}; use crate::{SquadObject, account::Account, error::Error, quest::Quest}; /// Struct for containing paths to other (de-)serializable things -#[derive(Deserialize)] +#[derive(Serialize, Deserialize)] #[serde(default)] pub struct Config { /// Path to config directory @@ -112,6 +112,42 @@ impl Config { } } + /// Serialize config into TOML. + /// Config will be saved as `path/config.toml` + /// + /// # Examples + /// ```rust + /// use squad_quest::config::Config; + /// + /// let path = "cfg".into(); + /// + /// let config = Config::default(); + /// + /// if let Err(error) = config.save(path) { + /// // handle error + /// } + /// ``` + pub fn save(&self, path: PathBuf) -> Result<(), Error> { + let mut path = path; + path.push("config.toml"); + + let str = match toml::to_string_pretty(&self) { + Ok(string) => string, + Err(error) => return Err(Error::TomlSerializeError(error)), + }; + + let mut file = match fs::File::create(path) { + Ok(f) => f, + Err(error) => return Err(Error::IoError(error)), + }; + + if let Err(error) = file.write_all(str.as_bytes()) { + return Err(Error::IoError(error)); + } + + Ok(()) + } + /// Deserialize config from TOML /// /// # Examples