use std::{ collections::HashMap, fmt::{Display, Formatter}, }; use serde::Deserialize; use terrors::OneOf; use crate::filesystem::FileSystem; #[derive(Debug, PartialEq, Eq, Deserialize)] pub struct Config { forge: HashMap, } #[derive(Debug, PartialEq, Eq, Deserialize)] pub struct Forge { forge_type: ForgeType, hostname: String, user: String, // API Token // Private SSH Key Path repos: HashMap, } impl Forge { pub const fn forge_type(&self) -> &ForgeType { &self.forge_type } pub fn hostname(&self) -> &str { &self.hostname } pub fn user(&self) -> &str { &self.user } pub fn repos(&self) -> impl Iterator { self.repos.iter() } } #[derive(Clone)] pub struct ForgeName(pub String); impl Display for ForgeName { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } pub struct Hostname(pub String); pub struct User(pub String); pub struct ForgeDetails { pub name: ForgeName, pub forge_type: ForgeType, pub hostname: Hostname, pub user: User, // API Token // Private SSH Key Path } impl From<(&ForgeName, &Forge)> for ForgeDetails { fn from(forge: (&ForgeName, &Forge)) -> Self { Self { name: forge.0.clone(), forge_type: forge.1.forge_type.clone(), hostname: Hostname(forge.1.hostname.clone()), user: User(forge.1.user.clone()), } } } #[derive(Clone)] pub struct RepoName(pub String); impl Display for RepoName { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } pub struct RepoPath(pub String); pub struct RepoDetails { pub name: RepoName, pub path: RepoPath, pub forge: ForgeDetails, } #[derive(Clone, Debug, PartialEq, Eq, Deserialize)] pub enum ForgeType { ForgeJo, // Gitea, // GitHub, // GitLab, // BitBucket, } impl Display for ForgeType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } #[allow(dead_code)] impl Config { pub(crate) fn load(fs: &FileSystem) -> Result> { let str = fs.read_file("git-next-server.toml").map_err(OneOf::new)?; toml::from_str(&str).map_err(OneOf::new) } pub(crate) fn forges(&self) -> impl Iterator { self.forge.iter() } } #[cfg(test)] mod tests { use assert2::let_assert; use crate::filesystem::FileSystem; use super::*; #[test] fn test_config_load() -> Result<(), OneOf<(std::io::Error, toml::de::Error)>> { let fs = FileSystem::new_temp().map_err(OneOf::new)?; fs.write_file( "git-next-server.toml", r#" [forge.default] forge_type = "ForgeJo" hostname = "git.example.net" user = "Bob" [forge.default.repos] hello = "user/world" "#, ) .map_err(OneOf::new)?; let config = Config::load(&fs)?; let_assert!(Some(default) = config.forge.get("default")); assert_eq!(default.forge_type, ForgeType::ForgeJo); assert_eq!(default.hostname, "git.example.net".to_string()); assert_eq!(default.user, "Bob".to_string()); assert_eq!(default.repos.get("hello"), Some(&"user/world".to_string())); Ok(()) } }