repos
/ repos-rust master

repos-rust

mirror archived upstream

A minimal self-hosted git browser on Rust axum: bare repos rendered as a website with commits, diffs, syntax-highlighted blobs, atom feeds, and clone over HTTPS.

axumdockergitgit-browsergitoxidegixrustself-hosted

2.1 KB · 68 lines · Rust Raw History
 1use axum::{
 2    extract::{Path, State},
 3    response::{IntoResponse, Response},
 4    routing::get,
 5    Router,
 6};
 7
 8use crate::render::{not_found, render};
 9use crate::AppState;
10
11pub fn router() -> Router<AppState> {
12    Router::new()
13        .route("/{name}/tree/{rev}", get(tree_root))
14        .route("/{name}/tree/{rev}/{*path}", get(tree_nested))
15}
16
17async fn tree_root(
18    Path((name, rev)): Path<(String, String)>,
19    State(state): State<AppState>,
20) -> Response {
21    tree_inner(state, name, rev, String::new()).await
22}
23
24async fn tree_nested(
25    Path((name, rev, path)): Path<(String, String, String)>,
26    State(state): State<AppState>,
27) -> Response {
28    tree_inner(state, name, rev, path).await
29}
30
31async fn tree_inner(state: AppState, name: String, rev: String, path: String) -> Response {
32    let repo_root = state.config.repo_root.clone();
33    let clone_base = state.config.clone_base.clone();
34    let name_for_blocking = name.clone();
35    let rev_for_blocking = rev.clone();
36    let path_for_blocking = path.clone();
37    let result = tokio::task::spawn_blocking(move || -> anyhow::Result<_> {
38        let repo = crate::git::open(&repo_root, &name_for_blocking)?;
39        let summary = crate::git::repo_summary(
40            &crate::git::resolve_path(&repo_root, &name_for_blocking)?,
41            &clone_base,
42        )?;
43        let oid = crate::git::resolve_rev(&repo, &rev_for_blocking)?;
44        let (entries, breadcrumb) = crate::git::list_tree(&repo, oid, &path_for_blocking)?;
45        Ok((summary, entries, breadcrumb))
46    })
47    .await;
48    match result {
49        Ok(Ok((summary, entries, breadcrumb))) => render(
50            &state,
51            "tree.html",
52            &format!("/{name}/tree/{rev}/{path}"),
53            minijinja::context! {
54                repo => &summary,
55                rev => &rev,
56                path => &path,
57                entries => &entries,
58                breadcrumb => &breadcrumb,
59            },
60        ),
61        Ok(Err(e)) => not_found(&state, &name, e),
62        Err(e) => {
63            tracing::error!("tree_page join: {e}");
64            (axum::http::StatusCode::INTERNAL_SERVER_ERROR, "render error").into_response()
65        }
66    }
67}