z_mirror/fmm
git clone https://git.raiguard.me/z_mirror/fmm
59fb9e2
rewrite
1use directories:: BaseDirs ; 2use semver:: Version ; 3use serde_derive::{ Deserialize , Serialize }; 4use std:: fmt; 5use std:: fs; 6use std:: fs:: File ; 7use std:: path:: PathBuf ; 8use std:: str:: FromStr ; 9use thiserror:: Error ; 10 11use crate :: mods_set:: ModEnabledType ; 12 13# [ derive ( Clone , Debug )] 14pub struct InputMod { 15pub name : String , 16pub version : ModEnabledType , 17} 18 19impl FromStr for InputMod { 20type Err =InputModErr ; 21 22fn from_str ( s : & str ) ->Result < Self , Self :: Err > { 23let parts: Vec < & str > = s. split ( '@' ). collect (); 24match parts[ ..] { 25[ name] =>Ok ( Self { 26name : name. to_string (), 27version : ModEnabledType :: Latest , 28}), 29[ name, version] =>{ 30let parsed_version =Version :: parse ( version); 31if let Ok ( version) = parsed_version{ 32// Validate that the version does *not* have prerelease or build data 33if !version. pre . is_empty () || !version. build . is_empty () { 34Err ( InputModErr :: InvalidVersion ( version. to_string ())) 35} else { 36Ok ( Self { 37name : name. to_string (), 38version : ModEnabledType :: Version ( version), 39}) 40} 41} else { 42Err ( InputModErr :: InvalidVersion ( version. to_string ())) 43} 44} 45 _ =>Err ( InputModErr :: IncorrectArgCount ( parts. len ())), 46} 47} 48} 49 50impl fmt:: Display for InputMod { 51fn fmt ( & self , f : & mut fmt:: Formatter < ' _ >) -> fmt:: Result { 52write! ( 53 f, 54"{}{}" , 55self . name , 56match & self . version { 57ModEnabledType :: Version ( version) =>format! ( " v{}" , version), 58 _ =>"" . to_string (), 59} 60) 61} 62} 63 64# [ derive ( Debug , Error )] 65pub enum InputModErr { 66# [ error ( "Incorrect argument count: expected 1 or 2, got {0}" )] 67IncorrectArgCount ( usize ), 68# [ error ( "Invalid version identifier: `{0}`" )] 69InvalidVersion ( String ), 70} 71 72# [ derive ( Deserialize , Serialize )] 73pub struct ConfigFile { 74pub directory : Option < PathBuf >, 75} 76 77impl ConfigFile { 78pub fn new ( path : & Option < PathBuf >) ->Result < Option < Self >, ConfigFileErr > { 79// Pass custom config path, or create the default config file it it doesn't exist 80let config_path: Option < PathBuf > = path. clone (). or ({ 81if let Some ( base_dirs) =BaseDirs :: new () { 82let mut config_path: PathBuf = base_dirs. config_dir (). into (); 83 config_path. push ( "fmm" ); 84if !config_path. exists () { 85 fs:: create_dir_all ( & config_path) 86. map_err ( |_|ConfigFileErr :: CouldNotCreatePath ) ?; 87} 88 config_path. push ( "fmm.toml" ); 89if !config_path. exists () { 90 config_path. push ( "fmm.toml" ); 91File :: create ( & config_path). map_err ( |_|ConfigFileErr :: CouldNotCreateFile ) ?; 92}; 93Some ( config_path) 94} else { 95None 96} 97}); 98if config_path. is_none () { 99return Ok ( None ); 100} 101 102let file = std:: fs:: read_to_string ( config_path. unwrap ()) 103. map_err ( |_|ConfigFileErr :: CouldNotOpenFile ) ?; 104 105// FIXME: Don't unwrap here. Use anyhow? 106let config: ConfigFile = toml:: from_str ( & file). unwrap (); 107Ok ( Some ( config)) 108} 109} 110 111# [ derive ( Debug , Error )] 112pub enum ConfigFileErr { 113# [ error ( "Could not open config file." )] 114CouldNotOpenFile , 115# [ error ( "Could not create config file path." )] 116CouldNotCreatePath , 117# [ error ( "Could not create config file." )] 118CouldNotCreateFile , 119}