z_mirror/fmm

git clone https://git.raiguard.me/z_mirror/fmm

raiguardMove old code to remove warnings59fb9e2

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