Skip to content

Commit dd8d16a

Browse files
committed
Support for self-hosted Gitea
deps.rs is now available for self-hosted Gitea at `/repo/gitea/<DOMAIN>/owner/repo`, e. g. `/repo/gitea/git.example.org/deps-rs/deps.rs`, `/repo/gitea/git.example.org:1234/deps-rs/deps.rs`, `/repo/gitea/http://unsafe-gitea.org/deps-rs/deps.rs`. This _should_ also include support for Gitea hosted in subdirectories, e. g. `www.example.org/gitea`, though I haven't tested this yet. If no protocol (`https://`/`http://`) is specified, `https://` is automatically added to the beginning of the gitea server's URL. However I could also change this to only accept https. Another option might be the use of URL-encoding. I am open for feedback, feel free to suggest changes. Implementation notes: - The Router now matches `/repo/*site/:qual/:name` instead of `/repo/:site/:qual/:name` to allow for an arbitrary number of `/`s before qual and name. - `RepoSite` now has a new variant `Gitea(GiteaDomain)`. - `RepoSite` no longer implements `Copy`. However this should not be problematic because `Copy`ing was only used for `to_base_uri`, `to_usercontent_base_uri` and `to_usercontent_repo_suffix` which now accept `&self` references. - `RepoSite` no longer implements `AsRef` and now uses `Display` instead. - updated test `correct_raw_url_generation` - updated readme Related to deps-rs#84, deps-rs#141
1 parent a991fa8 commit dd8d16a

File tree

5 files changed

+88
-28
lines changed

5 files changed

+88
-28
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ We currently support projects and crates hosted on crates.io, Github, Gitlab, Bi
1313
To analyze the state of your dependencies you can use the following URLs:
1414

1515
- for projects on crates.io: `https://deps.rs/crate/<NAME>`
16-
- for projects on Github, Gitlab, Bitbucket, SourceHut, or Codeberg: `https://deps.rs/repo/<HOSTER>/<USER>/<REPO>` (where `<HOSTER>` is either `github`, `gitlab`, `bitbucket`, `sourcehut`, or `codeberg`)
16+
- for projects on Github, Gitlab, Bitbucket, SourceHut, Codeberg, or Gitea: `https://deps.rs/repo/<HOSTER>/<USER>/<REPO>` (where `<HOSTER>` is either `github`, `gitlab`, `bitbucket`, `sourcehut`, `codeberg`, or `gitea/<DOMAIN>`)
1717

1818
## Badges
1919

src/models/repo.rs

+78-20
Original file line numberDiff line numberDiff line change
@@ -42,49 +42,52 @@ impl fmt::Display for RepoPath {
4242
write!(
4343
f,
4444
"{} => {}/{}",
45-
self.site.as_ref(),
45+
self.site.to_string(),
4646
self.qual.as_ref(),
4747
self.name.as_ref()
4848
)
4949
}
5050
}
5151

52-
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
52+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
5353
pub enum RepoSite {
5454
Github,
5555
Gitlab,
5656
Bitbucket,
5757
Sourcehut,
5858
Codeberg,
59+
Gitea(GiteaDomain),
5960
}
6061

6162
impl RepoSite {
62-
pub fn to_base_uri(self) -> &'static str {
63+
pub fn to_base_uri(&self) -> &str {
6364
match self {
6465
RepoSite::Github => "https://github.com",
6566
RepoSite::Gitlab => "https://gitlab.com",
6667
RepoSite::Bitbucket => "https://bitbucket.org",
6768
RepoSite::Sourcehut => "https://git.sr.ht",
6869
RepoSite::Codeberg => "https://codeberg.org",
70+
RepoSite::Gitea(domain) => domain.as_ref(),
6971
}
7072
}
7173

72-
pub fn to_usercontent_base_uri(self) -> &'static str {
74+
pub fn to_usercontent_base_uri(&self) -> &str {
7375
match self {
7476
RepoSite::Github => "https://raw.githubusercontent.com",
7577
RepoSite::Gitlab => "https://gitlab.com",
7678
RepoSite::Bitbucket => "https://bitbucket.org",
7779
RepoSite::Sourcehut => "https://git.sr.ht",
7880
RepoSite::Codeberg => "https://codeberg.org",
81+
RepoSite::Gitea(domain) => domain.as_ref(),
7982
}
8083
}
8184

82-
pub fn to_usercontent_repo_suffix(self) -> &'static str {
85+
pub fn to_usercontent_repo_suffix(&self) -> &'static str {
8386
match self {
8487
RepoSite::Github => "HEAD",
8588
RepoSite::Gitlab | RepoSite::Bitbucket => "raw/HEAD",
8689
RepoSite::Sourcehut => "blob/HEAD",
87-
RepoSite::Codeberg => "raw",
90+
RepoSite::Codeberg | RepoSite::Gitea(_) => "raw",
8891
}
8992
}
9093
}
@@ -93,25 +96,64 @@ impl FromStr for RepoSite {
9396
type Err = Error;
9497

9598
fn from_str(input: &str) -> Result<RepoSite, Error> {
96-
match input {
97-
"github" => Ok(RepoSite::Github),
98-
"gitlab" => Ok(RepoSite::Gitlab),
99-
"bitbucket" => Ok(RepoSite::Bitbucket),
100-
"sourcehut" => Ok(RepoSite::Sourcehut),
101-
"codeberg" => Ok(RepoSite::Codeberg),
102-
_ => Err(anyhow!("unknown repo site identifier")),
99+
if let Some((site, domain)) = input.split_once("/") {
100+
match site {
101+
"gitea" => Ok(RepoSite::Gitea(domain.parse()?)),
102+
_ => Err(anyhow!("unknown repo site identifier")),
103+
}
104+
} else {
105+
match input {
106+
"github" => Ok(RepoSite::Github),
107+
"gitlab" => Ok(RepoSite::Gitlab),
108+
"bitbucket" => Ok(RepoSite::Bitbucket),
109+
"sourcehut" => Ok(RepoSite::Sourcehut),
110+
"codeberg" => Ok(RepoSite::Codeberg),
111+
_ => Err(anyhow!("unknown repo site identifier")),
112+
}
103113
}
104114
}
105115
}
106116

107-
impl AsRef<str> for RepoSite {
108-
fn as_ref(&self) -> &str {
117+
impl fmt::Display for RepoSite {
118+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109119
match self {
110-
RepoSite::Github => "github",
111-
RepoSite::Gitlab => "gitlab",
112-
RepoSite::Bitbucket => "bitbucket",
113-
RepoSite::Sourcehut => "sourcehut",
114-
RepoSite::Codeberg => "codeberg",
120+
RepoSite::Github => write!(f, "github"),
121+
RepoSite::Gitlab => write!(f, "gitlab"),
122+
RepoSite::Bitbucket => write!(f, "bitbucket"),
123+
RepoSite::Sourcehut => write!(f, "sourcehut"),
124+
RepoSite::Codeberg => write!(f, "codeberg"),
125+
RepoSite::Gitea(s) => write!(f, "gitea/{s}"),
126+
}
127+
}
128+
}
129+
130+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
131+
pub struct GiteaDomain(String);
132+
133+
impl FromStr for GiteaDomain {
134+
type Err = Error;
135+
136+
fn from_str(input: &str) -> Result<GiteaDomain, Error> {
137+
if input.starts_with("https://") || input.starts_with("http://") {
138+
Ok(GiteaDomain(input.to_string()))
139+
} else {
140+
Ok(GiteaDomain(format!("https://{input}")))
141+
}
142+
}
143+
}
144+
145+
impl AsRef<str> for GiteaDomain {
146+
fn as_ref(&self) -> &str {
147+
self.0.as_ref()
148+
}
149+
}
150+
151+
impl fmt::Display for GiteaDomain {
152+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153+
if self.0.starts_with("https://") {
154+
f.write_str(&self.0["https://".len()..])
155+
} else {
156+
self.0.fmt(f)
115157
}
116158
}
117159
}
@@ -215,5 +257,21 @@ mod tests {
215257
let exp = format!("https://codeberg.org/deps-rs/deps.rs/raw/{}", expected);
216258
assert_eq!(out.to_string(), exp);
217259
}
260+
261+
for (input, expected) in &paths {
262+
let repo = RepoPath::from_parts("gitea/gitea.com", "deps-rs", "deps.rs").unwrap();
263+
let out = repo.to_usercontent_file_url(RelativePath::new(input));
264+
265+
let exp = format!("https://gitea.com/deps-rs/deps.rs/raw/{}", expected);
266+
assert_eq!(out.to_string(), exp);
267+
}
268+
269+
for (input, expected) in &paths {
270+
let repo = RepoPath::from_parts("gitea/example.com/git", "deps-rs", "deps.rs").unwrap();
271+
let out = repo.to_usercontent_file_url(RelativePath::new(input));
272+
273+
let exp = format!("https://example.com/git/deps-rs/deps.rs/raw/{}", expected);
274+
assert_eq!(out.to_string(), exp);
275+
}
218276
}
219277
}

src/server/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ impl App {
5858
router.add("/static/logo.svg", Route::Static(StaticFile::FaviconPng));
5959

6060
router.add(
61-
"/repo/:site/:qual/:name",
61+
"/repo/*site/:qual/:name",
6262
Route::RepoStatus(StatusFormat::Html),
6363
);
6464
router.add(
65-
"/repo/:site/:qual/:name/status.svg",
65+
"/repo/*site/:qual/:name/status.svg",
6666
Route::RepoStatus(StatusFormat::Svg),
6767
);
6868

src/server/views/html/index.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ fn popular_table(popular_repos: Vec<Repository>, popular_crates: Vec<CratePath>)
2121
@for repo in popular_repos.into_iter().take(10) {
2222
tr {
2323
td {
24-
a href=(format!("{}/repo/{}/{}/{}", &super::SELF_BASE_URL as &str, repo.path.site.as_ref(), repo.path.qual.as_ref(), repo.path.name.as_ref())) {
24+
a href=(format!("{}/repo/{}/{}/{}", &super::SELF_BASE_URL as &str, repo.path.site, repo.path.qual.as_ref(), repo.path.name.as_ref())) {
2525
(format!("{} / {}", repo.path.qual.as_ref(), repo.path.name.as_ref()))
2626
}
2727
}
2828
td class="has-text-right" {
29-
img src=(format!("{}/repo/{}/{}/{}/status.svg", &super::SELF_BASE_URL as &str, repo.path.site.as_ref(), repo.path.qual.as_ref(), repo.path.name.as_ref()));
29+
img src=(format!("{}/repo/{}/{}/{}/status.svg", &super::SELF_BASE_URL as &str, repo.path.site, repo.path.qual.as_ref(), repo.path.name.as_ref()));
3030
}
3131
}
3232
}

src/server/views/html/status.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,11 @@ fn get_site_icon(site: &RepoSite) -> (FaType, &'static str) {
127127
RepoSite::Github => (FaType::Brands, "github"),
128128
RepoSite::Gitlab => (FaType::Brands, "gitlab"),
129129
RepoSite::Bitbucket => (FaType::Brands, "bitbucket"),
130-
// FIXME: There is no brands/{sourcehut, codeberg} icon, so just use a
130+
// FIXME: There is no brands/{sourcehut, codeberg, gitea} icon, so just use a
131131
// regular circle which looks close enough.
132-
RepoSite::Sourcehut | RepoSite::Codeberg => (FaType::Regular, "circle"),
132+
RepoSite::Sourcehut | RepoSite::Codeberg | RepoSite::Gitea(_) => {
133+
(FaType::Regular, "circle")
134+
}
133135
}
134136
}
135137

@@ -334,7 +336,7 @@ fn render_success(
334336
let self_path = match subject_path {
335337
SubjectPath::Repo(ref repo_path) => format!(
336338
"repo/{}/{}/{}",
337-
repo_path.site.as_ref(),
339+
repo_path.site,
338340
repo_path.qual.as_ref(),
339341
repo_path.name.as_ref()
340342
),

0 commit comments

Comments
 (0)