raw
1use axum::{
2 extract::Path,
3 http::StatusCode,
4 response::{IntoResponse as _, Response},
5};
6use git2::Reference;
7
8use crate::utils::{
9 Error, Result,
10 error::Context as _,
11 extractor::repo_name_checks,
12 filters,
13 git::{Repository, TagEntry},
14 response::{Html, Redirect},
15 spawn_blocking,
16};
17
18#[derive(askama::Template)]
19#[template(path = "refs.html")]
20struct RepoRefTemplate<'a> {
21 repo: &'a Repository,
22 branches: Vec<Reference<'a>>,
23 tags: Vec<TagEntry>,
24}
25
26#[tracing::instrument(skip_all)]
27pub async fn get(Path(repo_name): Path<String>) -> Response {
28 spawn_blocking(move || inner(&repo_name).into_response()).await
29}
30
31#[tracing::instrument(skip_all)]
32fn inner(repo_name: &str) -> Result {
33 repo_name_checks(repo_name)?;
34
35 let Some(repo) = Repository::open(repo_name).context("opening repository")? else {
36 return Err(Error::new(StatusCode::NOT_FOUND, "repo does not exist"));
37 };
38
39 if repo.is_empty()? {
40 return Ok(Redirect::permanent(&format!("/{repo_name}"))
41 .unwrap_or(Redirect::PERMANENT_ROOT)
42 .into_response());
43 }
44
45 let branches = repo.branches()?;
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(Html(RepoRefTemplate {
53 repo: &repo,
54 branches,
55 tags,
56 })
57 .into_response())
58}
59