use super::GitProvider;
use crate::{GitUrl, GitUrlParseError};
use getset::{CloneGetters, Getters};
use nom::Parser;
use nom::bytes::complete::tag;
use nom::combinator::opt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "url")]
use url::Url;
#[derive(Clone, Debug, PartialEq, Eq, Default, Getters, CloneGetters)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GitLabProvider {
#[getset(get = "pub")]
owner: String,
subgroup: Option<Vec<String>>,
#[getset(get = "pub")]
repo: String,
}
impl GitLabProvider {
pub fn subgroup(&self) -> Option<Vec<&str>> {
if let Some(s) = &self.subgroup {
let subgroup_vec: Vec<&str> = s.iter().map(|s| s.as_str()).collect();
Some(subgroup_vec)
} else {
None
}
}
pub fn fullname(&self) -> String {
if let Some(subgroup) = self.subgroup() {
let subgroup_str = subgroup.join("/");
format!("{}/{subgroup_str}/{}", self.owner, self.repo)
} else {
format!("{}/{}", self.owner, self.repo)
}
}
fn parse_path(input: &str) -> Result<(&str, GitLabProvider), GitUrlParseError> {
let (input, _) = opt(tag("/")).parse(input)?;
let input = input.trim_end_matches(".git");
let parts: Vec<&str> = input.split('/').filter(|s| !s.is_empty()).collect();
if parts.len() < 2 {
return Err(GitUrlParseError::ProviderParseFail(
"Path needs at least 2 parts: ex. \'/owner/repo\'".into(),
));
}
let repo = parts[parts.len() - 1].to_string();
let (owner, subgroup) = if parts.len() > 2 {
let subgroup: Vec<String> = parts[1..(parts.len() - 1)]
.iter()
.copied()
.map(|s| s.to_string())
.collect();
(parts[0].to_string(), Some(subgroup))
} else {
(parts[0].to_string(), None)
};
Ok((
input,
GitLabProvider {
owner,
subgroup,
repo,
},
))
}
}
impl GitProvider<GitUrl, GitUrlParseError> for GitLabProvider {
fn from_git_url(url: &GitUrl) -> Result<Self, GitUrlParseError> {
let path = url.path();
Self::parse_path(path).map(|(_, provider)| provider)
}
}
#[cfg(feature = "url")]
impl GitProvider<Url, GitUrlParseError> for GitLabProvider {
fn from_git_url(url: &Url) -> Result<Self, GitUrlParseError> {
let path = url.path();
Self::parse_path(path).map(|(_, provider)| provider)
}
}