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
1use axum::{
2 http::StatusCode,
3 response::{Html, IntoResponse, Response},
4};
5use chrono::Datelike;
6
7use crate::templates::RequestCtx;
8use crate::AppState;
9
10pub fn render(
11 state: &AppState,
12 template: &str,
13 path: &str,
14 extra: minijinja::Value,
15) -> Response {
16 let tmpl = match state.env.get_template(template) {
17 Ok(t) => t,
18 Err(e) => {
19 tracing::error!("template '{}': {}", template, e);
20 return (StatusCode::INTERNAL_SERVER_ERROR, "template error").into_response();
21 }
22 };
23 let body = tmpl.render(minijinja::context! {
24 request => RequestCtx { path: path.to_string() },
25 now => minijinja::context! { year => chrono::Local::now().year() },
26 site => minijinja::context! {
27 title => &state.config.site_title,
28 tagline => &state.config.site_tagline,
29 clone_base => &state.config.clone_base,
30 },
31 base_url => &state.config.base_url,
32 ..extra
33 });
34 match body {
35 Ok(s) => Html(s).into_response(),
36 Err(e) => {
37 tracing::error!("render '{}': {}", template, e);
38 (StatusCode::INTERNAL_SERVER_ERROR, "render error").into_response()
39 }
40 }
41}
42
43/// Log the underlying reason, then render the themed 404. Used everywhere
44/// instead of returning the raw error string so filesystem paths and gix
45/// internals don't leak into the response.
46pub fn not_found(state: &AppState, name: &str, reason: impl std::fmt::Display) -> Response {
47 tracing::info!("{name}: {reason}");
48 let body = render(
49 state,
50 "not_found.html",
51 &format!("/{name}"),
52 minijinja::context! { name => name },
53 );
54 (StatusCode::NOT_FOUND, body).into_response()
55}
56