🏡 index : ~doyle/rgit.git

author Jordan Doyle <jordan@doyle.la> 2022-07-06 1:56:48.0 +01:00:00
committer Jordan Doyle <jordan@doyle.la> 2022-07-06 1:56:48.0 +01:00:00
commit
c856af78b169e9609eba4475d043a025cd59efd2 [patch]
tree
05aeeb5b734b0a3cd4a3571cc07015a133a226b2
parent
01742ecb810c1c7e2184f9c91985a954a5d9d485
download
c856af78b169e9609eba4475d043a025cd59efd2.tar.gz

Commit & metadata caching



Diff

 Cargo.lock           | 535 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 Cargo.toml           |   4 +++-
 src/git.rs           | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 src/main.rs          |  11 +++++------
 templates/index.html |   2 +-
 src/methods/index.rs |  10 ++++++----
 src/methods/repo.rs  |  13 +++++++------
 7 files changed, 671 insertions(+), 92 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 8565f39..4b7d73e 100644
--- a/Cargo.lock
+++ a/Cargo.lock
@@ -12,6 +12,12 @@
]

[[package]]
name = "arc-swap"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f"

[[package]]
name = "askama"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -57,6 +63,34 @@
 "serde",
 "syn",
 "toml",
]

[[package]]
name = "async-io"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07"
dependencies = [
 "concurrent-queue",
 "futures-lite",
 "libc",
 "log",
 "once_cell",
 "parking",
 "polling",
 "slab",
 "socket2",
 "waker-fn",
 "winapi",
]

[[package]]
name = "async-lock"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
dependencies = [
 "event-listener",
]

[[package]]
@@ -137,12 +171,61 @@
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"

[[package]]
name = "bumpalo"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"

[[package]]
name = "bytecount"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"

[[package]]
name = "bytes"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"

[[package]]
name = "cache-padded"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"

[[package]]
name = "camino"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412"
dependencies = [
 "serde",
]

[[package]]
name = "cargo-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
dependencies = [
 "serde",
]

[[package]]
name = "cargo_metadata"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
dependencies = [
 "camino",
 "cargo-platform",
 "semver",
 "serde",
 "serde_json",
]

[[package]]
name = "cc"
@@ -152,6 +235,12 @@
dependencies = [
 "jobserver",
]

[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"

[[package]]
name = "cfg-if"
@@ -182,6 +271,85 @@
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
 "os_str_bytes",
]

[[package]]
name = "concurrent-queue"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
dependencies = [
 "cache-padded",
]

[[package]]
name = "crossbeam-channel"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
dependencies = [
 "cfg-if 1.0.0",
 "crossbeam-utils 0.8.10",
]

[[package]]
name = "crossbeam-epoch"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
 "autocfg",
 "cfg-if 0.1.10",
 "crossbeam-utils 0.7.2",
 "lazy_static",
 "maybe-uninit",
 "memoffset",
 "scopeguard",
]

[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
 "autocfg",
 "cfg-if 0.1.10",
 "lazy_static",
]

[[package]]
name = "crossbeam-utils"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
dependencies = [
 "cfg-if 1.0.0",
 "once_cell",
]

[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
 "version_check",
]

[[package]]
name = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"

[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
 "instant",
]

[[package]]
@@ -247,6 +415,21 @@
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"

[[package]]
name = "futures-lite"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
dependencies = [
 "fastrand",
 "futures-core",
 "futures-io",
 "memchr",
 "parking",
 "pin-project-lite",
 "waker-fn",
]

[[package]]
name = "futures-macro"
@@ -295,9 +478,9 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
 "cfg-if",
 "cfg-if 1.0.0",
 "libc",
 "wasi",
 "wasi 0.11.0+wasi-snapshot-preview1",
]

[[package]]
@@ -314,6 +497,12 @@
 "openssl-sys",
 "url",
]

[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"

[[package]]
name = "hashbrown"
@@ -329,6 +518,12 @@
dependencies = [
 "libc",
]

[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"

[[package]]
name = "http"
@@ -427,6 +622,15 @@
]

[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
 "cfg-if 1.0.0",
]

[[package]]
name = "itoa"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -439,6 +643,15 @@
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
dependencies = [
 "libc",
]

[[package]]
name = "js-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
dependencies = [
 "wasm-bindgen",
]

[[package]]
@@ -508,8 +721,17 @@
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
 "cfg-if 1.0.0",
]

[[package]]
name = "mach"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
dependencies = [
 "cfg-if",
 "libc",
]

[[package]]
@@ -523,12 +745,27 @@
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb"

[[package]]
name = "maybe-uninit"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"

[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"

[[package]]
name = "memoffset"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
 "autocfg",
]

[[package]]
name = "mime"
@@ -560,8 +797,33 @@
dependencies = [
 "libc",
 "log",
 "wasi",
 "wasi 0.11.0+wasi-snapshot-preview1",
 "windows-sys",
]

[[package]]
name = "moka"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b3caf8ff6db712c7f7fe018e7fb6d2ddbaf428b74f94a48fe075ef09a6b8a1"
dependencies = [
 "async-io",
 "async-lock",
 "crossbeam-channel",
 "crossbeam-epoch",
 "crossbeam-utils 0.8.10",
 "futures-util",
 "num_cpus",
 "once_cell",
 "parking_lot",
 "quanta",
 "scheduled-thread-pool",
 "skeptic",
 "smallvec",
 "tagptr",
 "thiserror",
 "triomphe",
 "uuid",
]

[[package]]
@@ -634,13 +896,10 @@
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"

[[package]]
name = "owning_ref"
version = "0.4.1"
name = "parking"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
dependencies = [
 "stable_deref_trait",
]
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"

[[package]]
name = "parking_lot"
@@ -658,7 +917,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
dependencies = [
 "cfg-if",
 "cfg-if 1.0.0",
 "libc",
 "redox_syscall",
 "smallvec",
@@ -714,6 +973,19 @@
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"

[[package]]
name = "polling"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259"
dependencies = [
 "cfg-if 1.0.0",
 "libc",
 "log",
 "wepoll-ffi",
 "winapi",
]

[[package]]
name = "proc-macro2"
@@ -722,6 +994,33 @@
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "pulldown-cmark"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
dependencies = [
 "bitflags",
 "memchr",
 "unicase",
]

[[package]]
name = "quanta"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bafd74c340a0a7e79415981ede3460df16b530fd071541901a57416eea950b17"
dependencies = [
 "crossbeam-utils 0.8.10",
 "libc",
 "mach",
 "once_cell",
 "raw-cpuid",
 "wasi 0.10.2+wasi-snapshot-preview1",
 "web-sys",
 "winapi",
]

[[package]]
@@ -731,6 +1030,15 @@
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "raw-cpuid"
version = "10.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "738bc47119e3eeccc7e94c4a506901aea5e7b4944ecd0829cbebf4af04ceda12"
dependencies = [
 "bitflags",
]

[[package]]
@@ -740,19 +1048,30 @@
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
dependencies = [
 "bitflags",
]

[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
 "winapi",
]

[[package]]
name = "rgit"
version = "0.1.0"
dependencies = [
 "arc-swap",
 "askama",
 "axum",
 "clap",
 "futures",
 "git2",
 "hex",
 "humantime",
 "owning_ref",
 "moka",
 "path-clean",
 "serde",
 "time",
@@ -772,10 +1091,37 @@
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"

[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
 "winapi-util",
]

[[package]]
name = "scheduled-thread-pool"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf"
dependencies = [
 "parking_lot",
]

[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"

[[package]]
name = "semver"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
dependencies = [
 "serde",
]

[[package]]
name = "serde"
@@ -839,6 +1185,21 @@
]

[[package]]
name = "skeptic"
version = "0.13.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8"
dependencies = [
 "bytecount",
 "cargo_metadata",
 "error-chain",
 "glob",
 "pulldown-cmark",
 "tempfile",
 "walkdir",
]

[[package]]
name = "slab"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -859,12 +1220,6 @@
 "libc",
 "winapi",
]

[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"

[[package]]
name = "strsim"
@@ -888,6 +1243,26 @@
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"

[[package]]
name = "tagptr"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"

[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
 "cfg-if 1.0.0",
 "fastrand",
 "libc",
 "redox_syscall",
 "remove_dir_all",
 "winapi",
]

[[package]]
name = "termcolor"
@@ -903,6 +1278,26 @@
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"

[[package]]
name = "thiserror"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
dependencies = [
 "thiserror-impl",
]

[[package]]
name = "thiserror-impl"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "thread_local"
@@ -1031,7 +1426,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
dependencies = [
 "cfg-if",
 "cfg-if 1.0.0",
 "log",
 "pin-project-lite",
 "tracing-attributes",
@@ -1085,6 +1480,12 @@
]

[[package]]
name = "triomphe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0abf5a9b5ad4a5ac1393956ae03fb57033749d3983e2cac9afbfd5ae04ec2"

[[package]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1158,6 +1559,23 @@
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"

[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
 "same-file",
 "winapi",
 "winapi-util",
]

[[package]]
name = "want"
@@ -1168,12 +1586,91 @@
 "log",
 "try-lock",
]

[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"

[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

[[package]]
name = "wasm-bindgen"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
dependencies = [
 "cfg-if 1.0.0",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
dependencies = [
 "bumpalo",
 "lazy_static",
 "log",
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-macro"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
]

[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-shared"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"

[[package]]
name = "web-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "wepoll-ffi"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
dependencies = [
 "cc",
]

[[package]]
name = "winapi"
diff --git a/Cargo.toml b/Cargo.toml
index 5a09a41..9db11b0 100644
--- a/Cargo.toml
+++ a/Cargo.toml
@@ -7,13 +7,15 @@

[dependencies]
askama = "0.11"
arc-swap = "1.5"
axum = "0.5"
clap = { version = "3.2", features = ["cargo"] }
futures = "0.3"
git2 = "0.14"
hex = "0.4"
humantime = "2.1"
moka = { version = "0.9", features = ["future"] }
path-clean = "0.1"
owning_ref = "0.4"
serde = { version = "1.0", features = ["derive"] }
time = "0.3"
tokio = { version = "1.19", features = ["full"] }
diff --git a/src/git.rs b/src/git.rs
index 2d7eeb9..cfb66f8 100644
--- a/src/git.rs
+++ a/src/git.rs
@@ -1,98 +1,176 @@
use std::{borrow::Cow, collections::BTreeMap, fmt::Display, path::Path, time::Duration};

use std::{
    borrow::Cow,
    collections::BTreeMap,
    path::{Path, PathBuf},
    sync::Arc,
    time::Duration,
};

use arc_swap::ArcSwapOption;
use git2::{Oid, Repository, Signature};
use owning_ref::OwningHandle;
use time::OffsetDateTime;

pub type RepositoryMetadataList = BTreeMap<Option<String>, Vec<RepositoryMetadata>>;

#[derive(Clone)]
pub struct Git {
    commits: moka::future::Cache<String, Arc<Commit>>,
    repository_metadata: Arc<ArcSwapOption<RepositoryMetadataList>>,
}

impl Default for Git {
    fn default() -> Self {
        Self {
            commits: moka::future::Cache::new(100),
            repository_metadata: Arc::new(ArcSwapOption::default()),
        }
    }
}

impl Git {
    pub async fn get_commit<'a>(&'a self, repo: PathBuf, commit: &str) -> Arc<Commit> {
        let commit = Oid::from_str(commit).unwrap();

        self.commits
            .get_with(commit.to_string(), async {
                tokio::task::spawn_blocking(move || {
                    let repo = Repository::open_bare(repo).unwrap();
                    let commit = repo.find_commit(commit).unwrap();

                    Arc::new(Commit::from(commit))
                })
                .await
                .unwrap()
            })
            .await
    }

    pub async fn get_latest_commit<'a>(&'a self, repo: PathBuf) -> Commit {
        tokio::task::spawn_blocking(move || {
            let repo = Repository::open_bare(repo).unwrap();
            let head = repo.head().unwrap();
            let commit = head.peel_to_commit().unwrap();

            Commit::from(commit)
        })
        .await
        .unwrap()
    }

    pub async fn fetch_repository_metadata(&self) -> Arc<RepositoryMetadataList> {
        if let Some(metadata) = self.repository_metadata.load().as_ref() {
            return Arc::clone(&metadata);
        }

        let start = Path::new("../test-git").canonicalize().unwrap();

        let repos = tokio::task::spawn_blocking(move || {
            let mut repos: RepositoryMetadataList = RepositoryMetadataList::new();
            fetch_repository_metadata_impl(&start, &start, &mut repos);
            repos
        })
        .await
        .unwrap();

        let repos = Arc::new(repos);
        self.repository_metadata.store(Some(repos.clone()));

        repos
    }
}

#[derive(Debug)]
pub struct RepositoryMetadata {
    pub name: String,
    pub description: Option<Cow<'static, str>>,
    pub owner: Option<String>,
    pub last_modified: Duration,
}

pub struct CommitUser {
    name: String,
    email: String,
    time: String,
}

pub struct CommitUser<'a>(Signature<'a>);
impl From<Signature<'_>> for CommitUser {
    fn from(v: Signature<'_>) -> Self {
        CommitUser {
            name: v.name().unwrap().to_string(),
            email: v.email().unwrap().to_string(),
            time: OffsetDateTime::from_unix_timestamp(v.when().seconds())
                .unwrap()
                .to_string(),
        }
    }
}

impl CommitUser<'_> {
impl CommitUser {
    pub fn name(&self) -> &str {
        self.0.name().unwrap()
        &self.name
    }

    pub fn email(&self) -> &str {
        self.0.email().unwrap()
        &self.email
    }

    pub fn time(&self) -> String {
        OffsetDateTime::from_unix_timestamp(self.0.when().seconds())
            .unwrap()
            .to_string()
    pub fn time(&self) -> &str {
        &self.time
    }
}

pub struct Commit {
    author: CommitUser,
    committer: CommitUser,
    oid: String,
    tree: String,
    parents: Vec<String>,
    summary: String,
    body: String,
}

pub struct Commit(OwningHandle<Box<Repository>, Box<git2::Commit<'static>>>);
impl From<git2::Commit<'_>> for Commit {
    fn from(commit: git2::Commit<'_>) -> Self {
        Commit {
            author: commit.author().into(),
            committer: commit.committer().into(),
            oid: commit.id().to_string(),
            tree: commit.tree_id().to_string(),
            parents: commit.parent_ids().map(|v| v.to_string()).collect(),
            summary: commit.summary().unwrap().to_string(),
            body: commit.body().map(ToString::to_string).unwrap_or_default(),
        }
    }
}

impl Commit {
    pub fn author(&self) -> CommitUser<'_> {
        CommitUser(self.0.author())
    pub fn author(&self) -> &CommitUser {
        &self.author
    }

    pub fn committer(&self) -> CommitUser<'_> {
        CommitUser(self.0.committer())
    pub fn committer(&self) -> &CommitUser {
        &self.committer
    }

    pub fn oid(&self) -> impl Display {
        self.0.id()
    pub fn oid(&self) -> &str {
        &self.oid
    }

    pub fn tree(&self) -> impl Display {
        self.0.tree_id()
    pub fn tree(&self) -> &str {
        &self.tree
    }

    pub fn parents(&self) -> impl Iterator<Item = impl Display + '_> {
        self.0.parent_ids()
    pub fn parents(&self) -> impl Iterator<Item = &str> {
        self.parents.iter().map(String::as_str)
    }

    pub fn summary(&self) -> &str {
        self.0.summary().unwrap()
        &self.summary
    }

    pub fn body(&self) -> &str {
        self.0.message().unwrap()
        &self.body
    }
}

pub fn get_commit(path: &Path, commit: &str) -> Commit {
    let repo = Repository::open_bare(path).unwrap();

    let commit = OwningHandle::new_with_fn(Box::new(repo), |v| {
        Box::new(unsafe { (*v).find_commit(Oid::from_str(commit).unwrap()).unwrap() })
    });

    // TODO: we can cache this
    Commit(commit)
}

pub fn get_latest_commit(path: &Path) -> Commit {
    let repo = Repository::open_bare(path).unwrap();

    let commit = OwningHandle::new_with_fn(Box::new(repo), |v| {
        let head = unsafe { (*v).head().unwrap() };
        Box::new(head.peel_to_commit().unwrap())
    });

    // TODO: we can cache this
    Commit(commit)
}

pub fn fetch_repository_metadata() -> RepositoryMetadataList {
    let start = Path::new("../test-git").canonicalize().unwrap();

    let mut repos: RepositoryMetadataList = RepositoryMetadataList::new();
    fetch_repository_metadata_impl(&start, &start, &mut repos);
    repos
}

fn fetch_repository_metadata_impl(
diff --git a/src/main.rs b/src/main.rs
index fd2a40e..5fc349e 100644
--- a/src/main.rs
+++ a/src/main.rs
@@ -1,14 +1,12 @@
#![deny(clippy::pedantic)]

use axum::{
    body::Body, handler::Handler, http::HeaderValue, response::Response, routing::get, Router,
    body::Body, handler::Handler, http::HeaderValue, response::Response, routing::get, Extension,
    Router,
};
use tower_layer::layer_fn;

use crate::{
    git::{fetch_repository_metadata, get_latest_commit},
    layers::logger::LoggingMiddleware,
};
use crate::{git::Git, layers::logger::LoggingMiddleware};

mod git;
mod layers;
@@ -30,7 +28,8 @@
            get(static_css(include_bytes!("../statics/style.css"))),
        )
        .fallback(methods::repo::service.into_service())
        .layer(layer_fn(LoggingMiddleware));
        .layer(layer_fn(LoggingMiddleware))
        .layer(Extension(Git::default()));

    axum::Server::bind(&"127.0.0.1:3333".parse().unwrap())
        .serve(app.into_make_service_with_connect_info::<std::net::SocketAddr>())
diff --git a/templates/index.html b/templates/index.html
index b0fb288..6fdaf58 100644
--- a/templates/index.html
+++ a/templates/index.html
@@ -14,7 +14,7 @@
        </thead>

        <tbody>
        {% for (path, repositories) in repositories %}
        {% for (path, repositories) in repositories.iter() %}
            {% if let Some(path) = path %}
                <tr><td class="repo-section" colspan="4">{{ path }}</td></tr>
            {% endif %}
diff --git a/src/methods/index.rs b/src/methods/index.rs
index 9ca2503..6575bdc 100644
--- a/src/methods/index.rs
+++ a/src/methods/index.rs
@@ -1,19 +1,21 @@
use askama::Template;
use axum::response::Html;
use axum::Extension;
use std::sync::Arc;

use crate::{fetch_repository_metadata, git::RepositoryMetadataList};
use crate::{git::RepositoryMetadataList, Git};

#[allow(clippy::unused_async)]
pub async fn handle() -> Html<String> {
pub async fn handle(Extension(git): Extension<Git>) -> Html<String> {
    #[derive(Template)]
    #[template(path = "index.html")]
    pub struct View {
        pub repositories: RepositoryMetadataList,
        pub repositories: Arc<RepositoryMetadataList>,
    }

    Html(
        View {
            repositories: fetch_repository_metadata(),
            repositories: git.fetch_repository_metadata().await,
        }
        .render()
        .unwrap(),
diff --git a/src/methods/repo.rs b/src/methods/repo.rs
index a494568..915ea2f 100644
--- a/src/methods/repo.rs
+++ a/src/methods/repo.rs
@@ -1,11 +1,12 @@
use std::{
    ops::Deref,
    path::{Path, PathBuf},
    sync::Arc,
};

use askama::Template;
use axum::extract::Query;
use axum::{
    extract::Query,
    handler::Handler,
    http::Request,
    response::{Html, IntoResponse, Response},
@@ -15,8 +16,7 @@
use serde::Deserialize;
use tower::{util::BoxCloneService, Service};

use crate::git::get_commit;
use crate::{get_latest_commit, git::Commit, layers::UnwrapInfallible};
use crate::{git::Commit, layers::UnwrapInfallible, Git};

#[derive(Clone)]
pub struct Repository(pub PathBuf);
@@ -130,22 +130,23 @@
pub async fn handle_commit(
    Extension(repo): Extension<Repository>,
    Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
    Extension(git): Extension<Git>,
    Query(query): Query<CommitQuery>,
) -> Html<String> {
    #[derive(Template)]
    #[template(path = "repo/commit.html")]
    pub struct View {
        pub repo: Repository,
        pub commit: Commit,
        pub commit: Arc<Commit>,
    }

    Html(
        View {
            repo,
            commit: if let Some(commit) = query.id {
                get_commit(&repository_path, &commit)
                git.get_commit(repository_path, &commit).await
            } else {
                get_latest_commit(&repository_path)
                Arc::new(git.get_latest_commit(repository_path).await)
            },
        }
        .render()