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