git-next/src/server/config.rs

239 lines
6.1 KiB
Rust
Raw Normal View History

use std::{
collections::HashMap,
fmt::{Display, Formatter},
};
2024-04-07 13:47:39 +01:00
use serde::Deserialize;
use terrors::OneOf;
use crate::filesystem::FileSystem;
2024-04-07 16:09:16 +01:00
#[derive(Debug, PartialEq, Eq, Deserialize)]
pub struct Config {
forge: HashMap<String, Forge>,
}
impl Config {
pub(crate) fn load(fs: &FileSystem) -> Result<Self, OneOf<(std::io::Error, toml::de::Error)>> {
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<Item = (ForgeName, &Forge)> {
self.forge
.iter()
.map(|(name, forge)| (ForgeName(name.clone()), forge))
}
}
#[derive(Debug, PartialEq, Eq, Deserialize)]
pub struct Forge {
forge_type: ForgeType,
hostname: String,
2024-04-07 13:47:39 +01:00
user: String,
// API Token
// Private SSH Key Path
repos: HashMap<String, Repo>,
}
impl Forge {
pub const fn forge_type(&self) -> &ForgeType {
&self.forge_type
}
pub fn hostname(&self) -> Hostname {
Hostname(self.hostname.clone())
}
pub fn user(&self) -> User {
User(self.user.clone())
}
pub fn repos(&self) -> impl Iterator<Item = (RepoName, &Repo)> {
self.repos
.iter()
.map(|(name, repo)| (RepoName(name.clone()), repo))
}
2024-04-07 13:47:39 +01:00
}
#[derive(Debug, PartialEq, Eq, Deserialize)]
pub struct Repo {
repo: String,
branch: String,
}
impl Repo {
#[cfg(test)]
pub fn new(repo: &str, branch: &str) -> Self {
Self {
repo: repo.to_string(),
branch: branch.to_string(),
}
}
#[allow(dead_code)]
pub fn repo(&self) -> RepoPath {
RepoPath(self.repo.clone())
}
#[allow(dead_code)]
pub fn branch(&self) -> BranchName {
BranchName(self.branch.clone())
}
}
#[cfg(test)]
impl AsRef<Repo> for Repo {
fn as_ref(&self) -> &Repo {
self
}
}
impl Display for Repo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} - {}", self.repo, self.branch)
}
}
#[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);
impl Display for Hostname {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
pub struct User(pub String);
impl Display for User {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
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);
impl Display for RepoPath {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
pub struct BranchName(pub String);
impl Display for BranchName {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
pub struct RepoDetails {
pub name: RepoName,
pub repo: RepoPath,
pub branch: BranchName,
pub forge: ForgeDetails,
}
impl RepoDetails {
pub fn new(name: &RepoName, repo: &Repo, forge_name: &ForgeName, forge: &Forge) -> Self {
Self {
name: name.clone(),
repo: RepoPath(repo.repo.clone()),
branch: BranchName(repo.branch.clone()),
forge: ForgeDetails {
name: forge_name.clone(),
forge_type: forge.forge_type.clone(),
hostname: Hostname(forge.hostname.clone()),
user: User(forge.user.clone()),
},
}
}
}
impl Display for RepoDetails {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}/{} ({}): {}:{}/{} @ {}",
self.forge.name,
self.name,
self.forge.forge_type,
self.forge.hostname,
self.forge.user,
self.repo,
self.branch,
)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
2024-04-07 16:09:16 +01:00
pub enum ForgeType {
2024-04-07 13:47:39 +01:00
ForgeJo,
// Gitea,
// GitHub,
// GitLab,
// BitBucket,
}
impl Display for ForgeType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
2024-04-07 13:47:39 +01:00
#[cfg(test)]
mod tests {
use assert2::let_assert;
2024-04-07 13:47:39 +01:00
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"
2024-04-07 13:47:39 +01:00
user = "Bob"
[forge.default.repos]
hello = { repo = "user/hello", branch = "main" }
world = { repo = "user/world", branch = "master" }
2024-04-07 13:47:39 +01:00
"#,
)
.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(Repo::new("user/hello", "main").as_ref())
);
assert_eq!(
default.repos.get("world"),
Some(Repo::new("user/world", "master").as_ref())
);
2024-04-07 13:47:39 +01:00
Ok(())
}
}