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