1use std::{fmt::Write, sync::Arc};
2
3use askama::Template;
4use axum::{
5 extract::Query,
6 http::HeaderValue,
7 response::{IntoResponse, Response},
8 Extension,
9};
10use bytes::{BufMut, BytesMut};
11use clap::crate_version;
12use time::format_description::well_known::Rfc2822;
13
14use crate::{
15 git::Commit,
16 http, into_response,
17 methods::{
18 filters,
19 repo::{commit::UriQuery, Repository, RepositoryPath, Result},
20 },
21 Git,
22};
23
24#[derive(Template)]
25#[template(path = "repo/diff.html")]
26pub struct View {
27 pub repo: Repository,
28 pub commit: Arc<Commit>,
29 pub branch: Option<Arc<str>>,
30}
31
32pub async fn handle(
33 Extension(repo): Extension<Repository>,
34 Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
35 Extension(git): Extension<Arc<Git>>,
36 Query(query): Query<UriQuery>,
37) -> Result<impl IntoResponse> {
38 let open_repo = git.repo(repository_path, query.branch.clone()).await?;
39 let commit = if let Some(commit) = query.id {
40 open_repo.commit(&commit, true).await?
41 } else {
42 Arc::new(open_repo.latest_commit(true).await?)
43 };
44
45 Ok(into_response(View {
46 repo,
47 commit,
48 branch: query.branch,
49 }))
50}
51
52pub async fn handle_plain(
53 Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
54 Extension(git): Extension<Arc<Git>>,
55 Query(query): Query<UriQuery>,
56) -> Result<Response> {
57 let open_repo = git.repo(repository_path, query.branch).await?;
58 let commit = if let Some(commit) = query.id {
59 open_repo.commit(&commit, false).await?
60 } else {
61 Arc::new(open_repo.latest_commit(false).await?)
62 };
63
64 let headers = [(
65 http::header::CONTENT_TYPE,
66 HeaderValue::from_static("text/plain"),
67 )];
68
69 let mut data = BytesMut::new();
70
71 writeln!(data, "From {} Mon Sep 17 00:00:00 2001", commit.get().oid()).unwrap();
72 writeln!(
73 data,
74 "From: {} <{}>",
75 commit.get().author().name(),
76 commit.get().author().email()
77 )
78 .unwrap();
79
80 write!(data, "Date: ").unwrap();
81 let mut writer = data.writer();
82 commit
83 .get()
84 .author()
85 .time()
86 .format_into(&mut writer, &Rfc2822)
87 .unwrap();
88 let mut data = writer.into_inner();
89 writeln!(data).unwrap();
90
91 writeln!(data, "Subject: [PATCH] {}\n", commit.get().summary()).unwrap();
92
93 write!(data, "{}", commit.get().body()).unwrap();
94
95 writeln!(data, "---").unwrap();
96
97 data.extend_from_slice(commit.diff_stats.as_bytes());
98 data.extend_from_slice(b"\n");
99 data.extend_from_slice(commit.diff.as_bytes());
100
101 writeln!(data, "--\nrgit {}", crate_version!()).unwrap();
102
103 Ok((headers, data.freeze()).into_response())
104}