wayver's git archive


a simple self-hosted git server
git clone https://git.wayver.dev/bile

src/handlers/repo_refs.rs@7016b1e2e8158b6496a17a520c7f6da5dc38e9ee

raw
Date Commit Message Author Files + -
2026-02-17 21:07 initial mvp wayverd 74 10800 0
...

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    // sort so that newest tags are at the top
50    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