use git2::Repository;
use regex::Regex;
use url::Url;
use crate::error::*;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RepoInfo {
#[serde(default)]
pub name: String,
#[serde(default)]
pub fork: bool,
#[serde(default)]
pub github_name: Option<String>,
#[serde(default)]
pub clone_url: String,
#[serde(default)]
pub refs: Vec<String>,
}
impl RepoInfo {
pub fn from_url(url: &str) -> Result<RepoInfo> {
let name = if let Ok(url) = Url::parse(&url) {
url.path().to_owned().split_off(1)
} else {
lazy_static! {
static ref SSH_URL_REGEX: Regex =
Regex::new(r#"(.+@)?(.+):(?P<path>.+).git"#).unwrap();
}
SSH_URL_REGEX
.captures(url)
.and_then(|captures| captures.name("path"))
.ok_or::<Error>(ErrorKind::InvalidRepo(url.to_owned()).into())?
.as_str()
.to_owned()
};
Ok(RepoInfo {
name: name.clone(),
github_name: if url.contains("github") {
Some(name)
} else {
None
},
clone_url: url.to_owned(),
..Default::default()
})
}
pub fn from_repository(repo: &Repository) -> Result<RepoInfo> {
let mut repo_info = Self::default();
if let Ok(remote) = repo.find_remote("origin") {
let url = remote.url().ok_or::<Error>(
ErrorKind::InvalidRepo(repo.path().to_string_lossy().to_string()).into(),
)?;
repo_info.clone_url = url.to_owned();
lazy_static! {
static ref GITHUB_REGEX: Regex = Regex::new(
r#"(git@github.com:(?P<a>.+/.+).git)|(https://github.com/(?P<b>.+/.+)(?:.git)?)"#
)
.unwrap();
}
GITHUB_REGEX.captures(url).map(|captures| {
repo_info.github_name.replace(
captures
.name("a")
.or_else(|| captures.name("b"))
.unwrap()
.as_str()
.to_owned(),
);
});
}
if let Some(ref github_name) = repo_info.github_name {
repo_info.name = github_name.to_owned();
} else {
repo_info.name = repo
.path()
.parent()
.unwrap()
.file_name()
.unwrap()
.to_string_lossy()
.to_string();
}
Ok(repo_info)
}
pub fn partial(&self) -> PartialRepoInfo {
PartialRepoInfo {
name: self.name.clone(),
fork: self.fork,
}
}
}
impl Default for RepoInfo {
fn default() -> Self {
RepoInfo {
name: "".to_owned(),
fork: false,
github_name: None,
clone_url: "".to_owned(),
refs: vec!["refs/remotes/origin/master".to_owned()],
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartialRepoInfo {
name: String,
fork: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_url() -> Result<()> {
assert_eq!(
RepoInfo::from_url("https://github.com/actix/actix-web")?.name,
"actix/actix-web"
);
assert_eq!(
RepoInfo::from_url("git@github.com:getoutreach/broccoli-babel.git")?.name,
"getoutreach/broccoli-babel"
);
Ok(())
}
}