#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RepoDirectory {
pub name: String,
pub path: String,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub remote_url: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub role: Option<String>,
#[cfg_attr(feature = "serde", serde(default = "default_anima_member"))]
pub is_anima_member: bool,
}
#[cfg(feature = "serde")]
fn default_anima_member() -> bool {
true
}
impl RepoDirectory {
pub fn new(name: impl Into<String>, path: impl Into<String>) -> Self {
Self {
name: name.into(),
path: normalize_path(&path.into()),
remote_url: None,
role: None,
is_anima_member: true,
}
}
#[must_use]
pub fn with_remote(mut self, url: impl Into<String>) -> Self {
self.remote_url = Some(url.into());
self
}
#[must_use]
pub fn with_role(mut self, role: impl Into<String>) -> Self {
self.role = Some(role.into());
self
}
}
pub fn normalize_path(path: &str) -> String {
let p = path.trim();
if p.len() > 1 {
p.trim_end_matches('/').to_string()
} else {
p.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_normalizes_trailing_slash() {
let r = RepoDirectory::new("Ijima", "/home/x/Ijima/");
assert_eq!(r.path, "/home/x/Ijima");
assert!(r.is_anima_member);
}
#[test]
fn builders_set_optional_fields() {
let r = RepoDirectory::new("Kagome", "/k")
.with_remote("git@github.com:Anima/Kagome.git")
.with_role("hardware");
assert_eq!(
r.remote_url.as_deref(),
Some("git@github.com:Anima/Kagome.git")
);
assert_eq!(r.role.as_deref(), Some("hardware"));
}
#[test]
fn root_path_preserved() {
assert_eq!(normalize_path("/"), "/");
}
}