mygit

[UNMAINTAINED] A cgit/webgit alternative, written in Rust
Log | Files | Refs | README | LICENSE

commit 7410f5d964eb9b5b7403823f80f0be5500a58d07
parent 85984344b025b563e7c044e90760952c2a7bd141
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sat, 13 Mar 2021 16:32:54 -0800

Create basic git log page

Diffstat:
MCargo.lock | 1+
MCargo.toml | 1+
Msrc/main.rs | 52+++++++++++++++++++++++++++++++++++++++++++---------
Mtemplates/log.html | 22++++++++++++++++++++++
Mtemplates/static/style.css | 13++++++++-----
5 files changed, 75 insertions(+), 14 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1120,6 +1120,7 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" name = "mygit" version = "0.1.0" dependencies = [ + "anyhow", "askama", "askama_tide", "async-std", diff --git a/Cargo.toml b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0" askama = {version = "0.10", features = ["with-tide"]} askama_tide = "0.13" async-std = { version = "1.8.0", features = ["attributes"] } diff --git a/src/main.rs b/src/main.rs @@ -1,5 +1,6 @@ +use anyhow::Result; use askama::Template; -use git2::Repository; +use git2::{Commit, Repository}; use once_cell::sync::OnceCell; use pico_args; use pulldown_cmark::{html, Options, Parser}; @@ -56,11 +57,16 @@ struct RepoHomeTemplate<'a> { config: &'a Config, } +fn repo_from_request(repo_name: &str) -> Result<Repository> { + let repo_path = Path::new(&Config::global().repo_directory).join(repo_name); + // TODO CLEAN PATH! VERY IMPORTANT! DONT FORGET! + let r = Repository::open(repo_path)?; + Ok(r) +} + async fn repo_home(req: Request<()>) -> tide::Result { let config = &Config::global(); - let repo_path = Path::new(&config.repo_directory).join(req.param("repo_name")?); - // TODO CLEAN PATH! VERY IMPORTANT! DONT FORGET! - let repo = Repository::open(repo_path)?; + let repo = repo_from_request(&req.param("repo_name")?)?; let readme = &repo.revparse_single("HEAD:README.md")?; // TODO allow more incl plaintext let markdown_input = str::from_utf8(readme.as_blob().unwrap().content())?; let mut options = Options::empty(); @@ -75,6 +81,33 @@ async fn repo_home(req: Request<()>) -> tide::Result { Ok(tmpl.into()) } +#[derive(Template)] +#[template(path = "log.html")] // using the template in this path, relative +struct RepoLogTemplate<'a> { + repo: &'a Repository, + config: &'a Config, + commits: Vec<Commit<'a>>, +} + +async fn repo_log(req: Request<()>) -> tide::Result { + let config = &Config::global(); + let repo = repo_from_request(&req.param("repo_name")?)?; + let mut revwalk = repo.revwalk()?; + match req.param("ref") { + Ok(r) => revwalk.push_ref(&format!("refs/heads/{}", r))?, + _ => revwalk.push_head()?, + }; + let commits = revwalk + .map(|oid| repo.find_commit(oid.unwrap()).unwrap().clone()) // TODO error handling + .collect(); + let tmpl = RepoLogTemplate { + repo: &repo, + config, + commits, + }; + Ok(tmpl.into()) +} + const HELP: &str = "\ mygit @@ -109,11 +142,12 @@ async fn main() -> Result<(), std::io::Error> { app.at("/:repo_name").get(repo_home); // ALSO do git pull at this url somehow ^ // app.at("/:repo_name/commit/:hash").get(repo_log); - // app.at("/:repo_name/log/:ref").get(repo_log); ref optional, default master/main - // app.at("/:repo_name/tree/:ref").get(repo_log); ref = master/main when not present - // app.at("/:repo_name/tree/:ref/item/:file").get(repo_log); ref = master/main when not present - // app.at("/:repo_name/refs").get(repo_log); ref = master/main when not present - // Bonus: raw files, patchsets + app.at("/:repo_name/log").get(repo_log); + app.at("/:repo_name/log/:ref").get(repo_log); // ref optional + // app.at("/:repo_name/tree/:ref").get(repo_log); ref = master/main when not present + // app.at("/:repo_name/tree/:ref/item/:file").get(repo_log); ref = master/main when not present + // app.at("/:repo_name/refs").get(repo_log); ref = master/main when not present + // Bonus: raw files, patchsets app.listen("127.0.0.1:8081").await?; Ok(()) } diff --git a/templates/log.html b/templates/log.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block content %} + {% let name = repo.workdir().unwrap().file_name().unwrap().to_str().unwrap() %} + {% include "repo-navbar.html" %} + <table> + {% for commit in commits %} + <tr> + <td class="commit-hash"><a href="/{{name}}/commits/{{commit.id()}}">{{commit.id().to_string()[..7]}}</td> + {% let summary = commit.summary().unwrap_or("") %} + {% if summary.len() > 72 %} + <td>{{summary[..69]}}...</td> + {% else %} + <td>{{summary}}</td> + {% endif %} + <td><a href="mailto:{{commit.author().email().unwrap_or("")}}">{{commit.author().name().unwrap_or("")}}</a></td> + <td>{{commit.time().seconds()}}</td> + </tr> + {% endfor %} + </table> +{% endblock %} + diff --git a/templates/static/style.css b/templates/static/style.css @@ -1,5 +1,5 @@ body { - max-width: 90ch; + max-width: 95ch; padding: 2ch; margin: auto; font-family: "Roboto", Helvetica, Arial, Sans-serif; @@ -42,10 +42,6 @@ h2 { margin: 0px; } -table { - width: 100%; - overflow-x: auto; -} pre { line-height: 1.2; @@ -58,11 +54,18 @@ tr:hover { } td { + white-space: nowrap; margin: 0px; border-style:hidden; padding: 0; } + +table td { + padding: 0 0.4em; + } + table { + width: 100%; border-collapse: collapse; }