Krolyxon
Commit 4030c43

ferreniumsrchandlersrefs.rs

113 lines · 3.1 KB · Rust

1//! `/{repo}/refs` — branches and tags.
2
3use askama::Template;
4use axum::http::StatusCode;
5use axum::response::Response;
6
7use super::repo::{Active, Crumb, Ctx, RepoNav, set_cache_headers};
8use super::{Layout, render};
9use crate::config::SnapshotFormat;
10use crate::git::refs::RefEntry;
11use crate::render::encode_path;
12use crate::render::time;
13
14pub struct RefRow {
15 pub name: String,
16 pub url: String,
17 pub subject: String,
18 pub age: String,
19 pub iso: String,
20 pub is_default: bool,
21 /// Snapshot downloads (`tar.gz`, `zip`), on tags.
22 pub archives: Vec<(&'static str, String)>,
23}
24
25#[derive(Template)]
26#[template(path = "refs.html")]
27pub struct RefsPage {
28 pub layout: Layout,
29 pub nav: RepoNav,
30 pub crumbs: Vec<Crumb>,
31 pub here: Option<String>,
32 pub branches: Vec<RefRow>,
33 pub tags: Vec<RefRow>,
34}
35
36pub fn page(ctx: &Ctx) -> Response {
37 let etag = ctx.etag("refs");
38 if let Some(res) = ctx.not_modified(&etag, false) {
39 return res;
40 }
41 let refs = match ctx.refs() {
42 Ok(refs) => refs,
43 Err(e) => return ctx.internal_error(e),
44 };
45 let now = time::now();
46 let default = ctx.repo.meta.default_branch.as_deref();
47 let row = |r: &RefEntry| RefRow {
48 name: r.name.clone(),
49 url: ctx.url("tree", &r.name, b""),
50 subject: r
51 .tag_subject
52 .clone()
53 .unwrap_or_else(|| r.info.subject.clone()),
54 age: time::relative(r.info.committer_time, now),
55 iso: time::iso(r.info.committer_time),
56 is_default: false,
57 archives: Vec::new(),
58 };
59 let mut branches: Vec<RefRow> = refs.branches.iter().map(row).collect();
60 // The default branch leads the list.
61 if let Some(i) = branches
62 .iter()
63 .position(|b| Some(b.name.as_str()) == default)
64 {
65 let mut b = branches.remove(i);
66 b.is_default = true;
67 branches.insert(0, b);
68 }
69 let crumbs = vec![Crumb {
70 name: ctx.repo.name.clone(),
71 url: ctx.repo_url(),
72 }];
73 let page = RefsPage {
74 layout: Layout::new(
75 ctx.state,
76 ctx.config,
77 Some(&format!("Refs · {}", ctx.repo.name)),
78 ),
79 nav: ctx.nav(Active::Refs, None, |_| String::new()),
80 crumbs,
81 here: Some("Refs".into()),
82 branches,
83 tags: refs
84 .tags
85 .iter()
86 .map(|r| {
87 let mut row = row(r);
88 row.archives = archives(ctx, &r.name);
89 row
90 })
91 .collect(),
92 };
93 let mut res = render(StatusCode::OK, &page);
94 set_cache_headers(&mut res, &etag, false);
95 res
96}
97
98/// Links to the enabled snapshot formats of `rev`.
99fn archives(ctx: &Ctx, rev: &str) -> Vec<(&'static str, String)> {
100 ctx.config
101 .repos
102 .snapshots
103 .iter()
104 .map(|format| {
105 let ext = match format {
106 SnapshotFormat::TarGz => "tar.gz",
107 SnapshotFormat::Zip => "zip",
108 };
109 let url = format!("{}/archive/{}.{ext}", ctx.repo_url(), encode_path(rev));
110 (ext, url)
111 })
112 .collect()
113}