raw
1use axum::{
2 extract::Path,
3 http::StatusCode,
4 response::{IntoResponse as _, Response},
5};
6
7use crate::utils::{
8 Error, Result,
9 error::Context as _,
10 extractor::repo_name_checks,
11 filters,
12 git::{Repository, TagEntry},
13 response::Xml,
14 spawn_blocking,
15};
16
17#[derive(askama::Template)]
18#[template(path = "refs.xml")]
19struct RepoRefFeedTemplate<'a> {
20 repo: &'a Repository,
21 tags: Vec<TagEntry>,
22 base_url: &'a str,
23}
24
25#[tracing::instrument(skip_all)]
26pub async fn get(Path(repo_name): Path<String>) -> Response {
27 spawn_blocking(move || inner(&repo_name).into_response()).await
28}
29
30#[tracing::instrument(skip_all)]
31fn inner(repo_name: &str) -> Result {
32 repo_name_checks(repo_name)?;
33
34 let Some(repo) = Repository::open(repo_name).context("opening repository")? else {
35 return Err(Error::new(StatusCode::NOT_FOUND, "repo does not exist"));
36 };
37
38 if repo.is_empty()? {
39 return Err(Error::new(
41 StatusCode::SERVICE_UNAVAILABLE,
42 "Cannot show feed because there is nothing here.",
43 ));
44 }
45
46 let mut tags = repo.tag_entries()?;
47
48 tags.sort_unstable_by(|a, b| a.signature.when().cmp(&b.signature.when()).reverse());
50
51 Ok(Xml(RepoRefFeedTemplate {
52 repo: &repo,
53 tags,
54 base_url: &format!("/{repo_name}"),
55 })
56 .into_response())
57}
58