2018-01-26 12:15:53 +00:00
|
|
|
use std::str::FromStr;
|
|
|
|
|
2020-09-28 23:28:58 +00:00
|
|
|
use anyhow::{anyhow, ensure, Error};
|
2020-10-01 20:49:11 +00:00
|
|
|
use hyper::Uri;
|
|
|
|
use relative_path::RelativePath;
|
2018-02-05 09:23:40 +00:00
|
|
|
|
2018-02-05 08:38:04 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2018-02-03 09:12:00 +00:00
|
|
|
pub struct Repository {
|
|
|
|
pub path: RepoPath,
|
2020-09-28 22:53:20 +00:00
|
|
|
pub description: String,
|
2018-02-03 09:12:00 +00:00
|
|
|
}
|
|
|
|
|
2018-02-11 08:09:49 +00:00
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
2018-01-26 12:15:53 +00:00
|
|
|
pub struct RepoPath {
|
|
|
|
pub site: RepoSite,
|
|
|
|
pub qual: RepoQualifier,
|
2020-09-28 22:53:20 +00:00
|
|
|
pub name: RepoName,
|
2018-01-26 12:15:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RepoPath {
|
2018-02-05 09:23:40 +00:00
|
|
|
pub fn from_parts(site: &str, qual: &str, name: &str) -> Result<RepoPath, Error> {
|
2018-01-26 12:15:53 +00:00
|
|
|
Ok(RepoPath {
|
|
|
|
site: site.parse()?,
|
|
|
|
qual: qual.parse()?,
|
2020-09-28 22:53:20 +00:00
|
|
|
name: name.parse()?,
|
2018-01-26 12:15:53 +00:00
|
|
|
})
|
|
|
|
}
|
2020-10-01 20:49:11 +00:00
|
|
|
|
|
|
|
pub fn to_usercontent_file_uri(&self, path: &RelativePath) -> Result<Uri, Error> {
|
|
|
|
let url = format!(
|
|
|
|
"{}/{}/{}/{}/{}",
|
|
|
|
self.site.to_usercontent_base_uri(),
|
|
|
|
self.qual.as_ref(),
|
|
|
|
self.name.as_ref(),
|
|
|
|
self.site.to_usercontent_repo_suffix(),
|
|
|
|
path.normalize()
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok(url.parse::<Uri>()?)
|
|
|
|
}
|
2018-01-26 12:15:53 +00:00
|
|
|
}
|
|
|
|
|
2018-02-11 08:09:49 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
2018-01-27 11:49:43 +00:00
|
|
|
pub enum RepoSite {
|
2018-02-12 17:21:22 +00:00
|
|
|
Github,
|
|
|
|
Gitlab,
|
2018-02-12 20:32:00 +00:00
|
|
|
Bitbucket,
|
2018-01-27 11:49:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RepoSite {
|
|
|
|
pub fn to_base_uri(&self) -> &'static str {
|
|
|
|
match self {
|
2018-02-12 17:21:22 +00:00
|
|
|
&RepoSite::Github => "https://github.com",
|
2018-02-12 20:32:00 +00:00
|
|
|
&RepoSite::Gitlab => "https://gitlab.com",
|
|
|
|
&RepoSite::Bitbucket => "https://bitbucket.org",
|
2018-01-27 11:49:43 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-01 20:49:11 +00:00
|
|
|
|
|
|
|
pub fn to_usercontent_base_uri(&self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
RepoSite::Github => "https://raw.githubusercontent.com",
|
|
|
|
RepoSite::Gitlab => "https://gitlab.com",
|
|
|
|
RepoSite::Bitbucket => "https://bitbucket.org",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn to_usercontent_repo_suffix(&self) -> &'static str {
|
|
|
|
match self {
|
|
|
|
RepoSite::Github => "HEAD",
|
|
|
|
RepoSite::Gitlab | RepoSite::Bitbucket => "raw/HEAD",
|
|
|
|
}
|
|
|
|
}
|
2018-01-27 11:49:43 +00:00
|
|
|
}
|
2018-01-26 12:15:53 +00:00
|
|
|
|
|
|
|
impl FromStr for RepoSite {
|
2018-02-05 09:23:40 +00:00
|
|
|
type Err = Error;
|
2018-01-26 12:15:53 +00:00
|
|
|
|
2018-02-05 09:23:40 +00:00
|
|
|
fn from_str(input: &str) -> Result<RepoSite, Error> {
|
2018-01-27 11:49:43 +00:00
|
|
|
match input {
|
|
|
|
"github" => Ok(RepoSite::Github),
|
2018-02-12 17:21:22 +00:00
|
|
|
"gitlab" => Ok(RepoSite::Gitlab),
|
2018-02-12 20:32:00 +00:00
|
|
|
"bitbucket" => Ok(RepoSite::Bitbucket),
|
2020-09-28 23:28:58 +00:00
|
|
|
_ => Err(anyhow!("unknown repo site identifier")),
|
2018-01-26 12:15:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for RepoSite {
|
|
|
|
fn as_ref(&self) -> &str {
|
2018-01-27 11:49:43 +00:00
|
|
|
match self {
|
2018-02-12 17:21:22 +00:00
|
|
|
&RepoSite::Github => "github",
|
2018-02-12 20:32:00 +00:00
|
|
|
&RepoSite::Gitlab => "gitlab",
|
2018-02-13 04:37:29 +00:00
|
|
|
&RepoSite::Bitbucket => "bitbucket",
|
2018-01-27 11:49:43 +00:00
|
|
|
}
|
2018-01-26 12:15:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 08:09:49 +00:00
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
2018-01-26 12:15:53 +00:00
|
|
|
pub struct RepoQualifier(String);
|
|
|
|
|
|
|
|
impl FromStr for RepoQualifier {
|
2018-02-05 09:23:40 +00:00
|
|
|
type Err = Error;
|
2018-01-26 12:15:53 +00:00
|
|
|
|
2018-02-05 09:23:40 +00:00
|
|
|
fn from_str(input: &str) -> Result<RepoQualifier, Error> {
|
2020-09-28 22:53:20 +00:00
|
|
|
let is_valid = input
|
|
|
|
.chars()
|
|
|
|
.all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_');
|
2018-01-26 12:15:53 +00:00
|
|
|
|
2018-02-05 09:23:40 +00:00
|
|
|
ensure!(is_valid, "invalid repo qualifier");
|
|
|
|
Ok(RepoQualifier(input.to_string()))
|
2018-01-26 12:15:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for RepoQualifier {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
self.0.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 08:09:49 +00:00
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
2018-01-26 12:15:53 +00:00
|
|
|
pub struct RepoName(String);
|
|
|
|
|
|
|
|
impl FromStr for RepoName {
|
2018-02-05 09:23:40 +00:00
|
|
|
type Err = Error;
|
2018-01-26 12:15:53 +00:00
|
|
|
|
2018-02-05 09:23:40 +00:00
|
|
|
fn from_str(input: &str) -> Result<RepoName, Error> {
|
2020-09-28 22:53:20 +00:00
|
|
|
let is_valid = input
|
|
|
|
.chars()
|
|
|
|
.all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '_');
|
2018-01-26 12:15:53 +00:00
|
|
|
|
2018-02-05 09:23:40 +00:00
|
|
|
ensure!(is_valid, "invalid repo name");
|
|
|
|
Ok(RepoName(input.to_string()))
|
2018-01-26 12:15:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for RepoName {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
self.0.as_ref()
|
|
|
|
}
|
|
|
|
}
|
2020-10-01 20:49:11 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn correct_raw_url_generation() {
|
|
|
|
let paths = [
|
|
|
|
("Cargo.toml", "Cargo.toml"),
|
|
|
|
("/Cargo.toml", "Cargo.toml"),
|
|
|
|
("libs/badge/Cargo.toml", "libs/badge/Cargo.toml"),
|
|
|
|
("/libs/badge/Cargo.toml", "libs/badge/Cargo.toml"),
|
|
|
|
("src/../libs/badge/Cargo.toml", "libs/badge/Cargo.toml"),
|
|
|
|
("/src/../libs/badge/Cargo.toml", "libs/badge/Cargo.toml"),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (input, expected) in &paths {
|
|
|
|
let repo = RepoPath::from_parts("github", "deps-rs", "deps.rs").unwrap();
|
|
|
|
let out = repo
|
|
|
|
.to_usercontent_file_uri(RelativePath::new(input))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let exp = format!(
|
|
|
|
"https://raw.githubusercontent.com/deps-rs/deps.rs/HEAD/{}",
|
|
|
|
expected
|
|
|
|
);
|
|
|
|
assert_eq!(out.to_string(), exp);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (input, expected) in &paths {
|
|
|
|
let repo = RepoPath::from_parts("gitlab", "deps-rs", "deps.rs").unwrap();
|
|
|
|
let out = repo
|
|
|
|
.to_usercontent_file_uri(RelativePath::new(input))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let exp = format!("https://gitlab.com/deps-rs/deps.rs/raw/HEAD/{}", expected);
|
|
|
|
assert_eq!(out.to_string(), exp);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (input, expected) in &paths {
|
|
|
|
let repo = RepoPath::from_parts("bitbucket", "deps-rs", "deps.rs").unwrap();
|
|
|
|
let out = repo
|
|
|
|
.to_usercontent_file_uri(RelativePath::new(input))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let exp = format!(
|
|
|
|
"https://bitbucket.org/deps-rs/deps.rs/raw/HEAD/{}",
|
|
|
|
expected
|
|
|
|
);
|
|
|
|
assert_eq!(out.to_string(), exp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|