raw
1use git2::{Commit, Signature, Time};
2use jiff::{
3 Timestamp,
4 tz::{self, TimeZone},
5};
6use num_conv::Truncate as _;
7
8use crate::utils::git::Repository;
9
10#[askama::filter_fn]
11#[tracing::instrument(skip_all)]
12pub fn format_datetime<'f>(
13 time: Time,
14 _: &dyn askama::Values,
15 format: &'f str,
16) -> askama::Result<jiff::fmt::strtime::Display<'f>> {
17 let tz = TimeZone::fixed(tz::offset((time.offset_minutes() / 60).truncate::<i8>()));
18
19 let timestamp = Timestamp::from_second(time.seconds()).map_err(|err| {
20 tracing::error!(err=%err, "failed to convert seconds into a timestamp");
21
22 askama::Error::Fmt
23 })?;
24
25 let zoned = timestamp.to_zoned(tz);
26
27 let format = zoned.strftime(format);
28
29 Ok(format)
30}
31
32#[askama::filter_fn]
33pub fn unix_perms(m: i32, _: &dyn askama::Values) -> askama::Result<String> {
34 Ok(match m {
39 0o040_000 => "drwxr-xr-x", 0o100_755 => "-rwxr-xr-x", 0o100_644 => "-rw-r--r--", 0o120_000 => "lrwxrwxrwx", 0o160_000 => "m---------", _ => unreachable!("unknown file mode"),
45 }
46 .into())
47}
48
49#[askama::filter_fn]
50pub fn repo_name<'r>(repo: &'r Repository, _: &dyn askama::Values) -> askama::Result<&'r str> {
51 repo.name().ok_or(askama::Error::Fmt)
52}
53
54#[askama::filter_fn]
55pub fn description(repo: &Repository, _: &dyn askama::Values) -> askama::Result<String> {
56 Ok(repo.description())
57}
58
59#[askama::filter_fn]
60#[tracing::instrument(skip_all)]
61pub fn last_modified(repo: &Repository, _: &dyn askama::Values) -> askama::Result<Time> {
62 repo.last_modified().map_err(|err| {
63 tracing::error!(err=?err, "failed to get repo's last modified date");
64 askama::Error::Fmt
65 })
66}
67
68#[askama::filter_fn]
69pub fn repo_owner(repo: &Repository, _: &dyn askama::Values) -> askama::Result<String> {
70 Ok(repo.owner())
71}
72
73#[askama::filter_fn]
74pub fn signature_email_link(
75 signature: &Signature<'_>,
76 _: &dyn askama::Values,
77) -> askama::Result<String> {
78 let Some(email) = signature.email() else {
79 return Ok(signature.to_string());
80 };
81
82 Ok(format!(
83 "<a href=\"mailto:{}\">{}</a>",
84 email,
85 signature.name().unwrap_or("�")
86 ))
87}
88
89#[askama::filter_fn]
90#[tracing::instrument(skip_all)]
91pub fn short_id(commit: &Commit<'_>, _: &dyn askama::Values) -> askama::Result<String> {
92 let id = match commit.as_object().short_id() {
93 Ok(id) => id,
94 Err(err) => {
95 tracing::error!(err=?err, "failed to get short id of commit");
96
97 return Err(askama::Error::Fmt);
98 }
99 };
100
101 id.as_str().map(str::to_string).ok_or(askama::Error::Fmt)
102}
103