initial template rendering
This commit is contained in:
@@ -1 +0,0 @@
|
||||
fn main() { }
|
||||
164
src/render.rs
Normal file
164
src/render.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This file is part of Mintee.
|
||||
*
|
||||
* Mintee is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* Mintee is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Mintee. If not, see https://www.gnu.org/licenses/.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
env::current_dir,
|
||||
fs::metadata,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use git2::{ Commit, Repository, Sort };
|
||||
use serde::Serialize;
|
||||
use tera::{ Context, Tera };
|
||||
|
||||
trait ToContext {
|
||||
fn to_context(self) -> Result<Context, git2::Error>;
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Entry {
|
||||
class: String,
|
||||
committer: String,
|
||||
last_commit: String,
|
||||
last_commit_short: String,
|
||||
last_commit_time: i64,
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl ToContext for Repository {
|
||||
fn to_context(self) -> Result<Context, git2::Error> {
|
||||
let repo = self.commondir();
|
||||
let _index = self.index()?;
|
||||
let head = self.head()?;
|
||||
let branch = if head.is_branch() {
|
||||
head.shorthand().unwrap()
|
||||
} else { "detached" };
|
||||
let head_commit = head.peel_to_commit()?;
|
||||
let entries = get_entries(&self)?;
|
||||
let committer = head_commit.committer().name().unwrap().to_owned();
|
||||
let _author = head_commit.author().name().unwrap().to_owned();
|
||||
|
||||
let mut ctx = Context::new();
|
||||
|
||||
// stub until we have database
|
||||
ctx.insert("user", "anon");
|
||||
ctx.insert("site", "TiB.");
|
||||
ctx.insert("notif_count", "");
|
||||
ctx.insert("ticket_count", "(47)");
|
||||
ctx.insert("owner", &committer);
|
||||
ctx.insert("repo", repo);
|
||||
ctx.insert("branch", &branch);
|
||||
ctx.insert("directory", repo);
|
||||
ctx.insert("entries", &entries);
|
||||
ctx.insert("readme_content", "this is a readme");
|
||||
|
||||
Ok(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
fn new(commit: &Commit, path: String) -> Result<Self, git2::Error> {
|
||||
let commit_id = commit.id();
|
||||
let ft = metadata(&path).unwrap().file_type();
|
||||
let class: String;
|
||||
|
||||
if ft.is_dir() {
|
||||
class = "directory".to_owned();
|
||||
} else {
|
||||
class = "file".to_owned();
|
||||
}
|
||||
|
||||
Ok(Entry {
|
||||
class,
|
||||
committer: commit
|
||||
.committer()
|
||||
.name()
|
||||
.unwrap_or("")
|
||||
.to_owned(),
|
||||
last_commit: commit_id.to_string(),
|
||||
last_commit_short: commit.as_object().short_id()?.as_str().unwrap_or("").to_owned(),
|
||||
last_commit_time: commit.time().seconds(),
|
||||
path,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_entries(repo: &Repository) -> Result<Vec<Entry>, git2::Error> {
|
||||
let mut entries = Vec::new();
|
||||
let mut revwalk = repo.revwalk()?;
|
||||
|
||||
revwalk.set_sorting(Sort::TOPOLOGICAL | Sort::TIME)?;
|
||||
revwalk.push_head()?;
|
||||
|
||||
for commit_id in revwalk {
|
||||
let commit_id = commit_id?;
|
||||
let commit = repo.find_commit(commit_id)?;
|
||||
if commit.parent_count() <= 1 {
|
||||
let tree = commit.tree()?;
|
||||
let prev_tree = match commit.parent_count() {
|
||||
1 => Some(commit.parent(0)?.tree()?),
|
||||
0 => None,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let diff = repo.diff_tree_to_tree(prev_tree.as_ref(), Some(&tree), None)?;
|
||||
for delta in diff.deltas() {
|
||||
if let Some(file_path) = delta.new_file().path() {
|
||||
entries.push(Entry::new(&commit, file_path.to_str().unwrap_or("Invalid UTF-8").to_owned())?);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
fn render_path(path: PathBuf) -> tera::Result<String> {
|
||||
let tera = Tera::new("./assets/templates/repo/*")?;
|
||||
let repo = Repository::discover(path).unwrap();
|
||||
let context = repo.to_context().unwrap();
|
||||
|
||||
tera.render("code.html", &context)
|
||||
}
|
||||
Reference in New Issue
Block a user