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