git.rs, render.rs, test_render.rs: updates rendering code and exposes rendering API
This commit is contained in:
+72
-55
@@ -21,9 +21,8 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use gix::{
|
use gix::{
|
||||||
Repository,
|
Object,
|
||||||
Tree,
|
Tree,
|
||||||
object::tree::EntryKind,
|
|
||||||
revision::walk::Sorting,
|
revision::walk::Sorting,
|
||||||
};
|
};
|
||||||
use gix_traverse::commit::simple::CommitTimeOrder;
|
use gix_traverse::commit::simple::CommitTimeOrder;
|
||||||
@@ -45,12 +44,13 @@ fn get_entries(tree: Tree) -> Result<Vec<Entry>, Box<dyn Error>> {
|
|||||||
let order = Sorting::ByCommitTime(CommitTimeOrder::NewestFirst);
|
let order = Sorting::ByCommitTime(CommitTimeOrder::NewestFirst);
|
||||||
|
|
||||||
for e in tree.iter() {
|
for e in tree.iter() {
|
||||||
let entry = e.unwrap();
|
let entry = e?;
|
||||||
let mut entry_t = Entry::default();
|
let mut entry_t = Entry::default();
|
||||||
entry_t.path = entry.filename().to_string();
|
entry_t.path = entry.filename().to_string();
|
||||||
|
|
||||||
|
use gix::object::tree::EntryKind::*;
|
||||||
entry_t.class = match entry.kind() {
|
entry_t.class = match entry.kind() {
|
||||||
EntryKind::Tree | EntryKind::Commit => "directory",
|
Tree | Commit => "directory",
|
||||||
_ => "file",
|
_ => "file",
|
||||||
}.to_owned();
|
}.to_owned();
|
||||||
|
|
||||||
@@ -60,7 +60,9 @@ fn get_entries(tree: Tree) -> Result<Vec<Entry>, Box<dyn Error>> {
|
|||||||
|
|
||||||
if commit.tree()?.lookup_entry([path_slice])?.is_some() {
|
if commit.tree()?.lookup_entry([path_slice])?.is_some() {
|
||||||
entry_t.last_commit = commit.id.to_string();
|
entry_t.last_commit = commit.id.to_string();
|
||||||
entry_t.last_commit_message = commit.message_raw()?.to_string();
|
entry_t.last_commit_message = commit
|
||||||
|
.message_raw()?
|
||||||
|
.to_string();
|
||||||
entry_t.last_commit_time = format_iso8601_utc(
|
entry_t.last_commit_time = format_iso8601_utc(
|
||||||
commit.time()?.seconds
|
commit.time()?.seconds
|
||||||
)?;
|
)?;
|
||||||
@@ -75,61 +77,76 @@ fn get_entries(tree: Tree) -> Result<Vec<Entry>, Box<dyn Error>> {
|
|||||||
Ok(entries)
|
Ok(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repo_to_context(r: Repository) -> Result<Context, Box<dyn Error>> {
|
pub trait ToContext {
|
||||||
let branches = r.clone().branch_names()
|
type Error;
|
||||||
.iter()
|
fn to_context(&self) -> Result<Context, Self::Error>;
|
||||||
.map(|x| x.to_owned().to_owned())
|
}
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
impl ToContext for Object<'_> {
|
||||||
/* @ is HEAD */
|
type Error = Box<dyn Error>;
|
||||||
let tree = r.rev_parse_single("@")?.object()?.peel_to_tree()?;
|
|
||||||
|
fn to_context(&self) -> Result<Context, Self::Error> {
|
||||||
/* replace with configurable branch name when we have a database */
|
let mut ctx = Context::new();
|
||||||
let current_branch = r.head()?.referent_name().unwrap().shorten().to_string();
|
let current_branch = self.repo
|
||||||
|
.head()?
|
||||||
let entries = get_entries(tree)?;
|
.referent_name()
|
||||||
|
.unwrap()
|
||||||
/*
|
.shorten()
|
||||||
let mut readme_content = String::new();
|
.to_string();
|
||||||
|
|
||||||
/* TODO: determine what file to use as README better */
|
use gix::object::Kind;
|
||||||
let readme_candidates = entries.iter().filter(|e| {
|
match self.kind {
|
||||||
match e.path.as_str().to_uppercase().as_str() {
|
Kind::Blob => todo!("need sasha to make a file page"),
|
||||||
"README" => true,
|
Kind::Tag => todo!("idk what this needs to look like"),
|
||||||
"README.MD" => true,
|
Kind::Commit => todo!("need sasha to make a commit page"),
|
||||||
_ => false,
|
Kind::Tree => {
|
||||||
}
|
let tree = self.clone().peel_to_tree()?;
|
||||||
});
|
let entries = get_entries(tree)?;
|
||||||
|
let repo = self.repo;
|
||||||
if let Some(readme) = readme_candidates.get(0) {
|
let dir = repo.common_dir();
|
||||||
/* unwrapping is ok because readme exists in Tree */
|
let name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
readme_content = tree.find_entry(readme).unwrap();
|
let branches = repo.clone().branch_names()
|
||||||
|
.iter()
|
||||||
todo!("convert Entry into BlobRef to get data")
|
.map(|x| x.to_owned().to_owned())
|
||||||
}
|
.collect::<Vec<_>>();
|
||||||
*/
|
|
||||||
|
|
||||||
let dir = r.common_dir();
|
/*
|
||||||
let name = dir.file_name().unwrap().to_str().unwrap();
|
let mut readme_content = String::new();
|
||||||
|
|
||||||
|
/* TODO: determine what file to use as README better */
|
||||||
|
let readme_candidates = entries.iter().filter(|e| {
|
||||||
|
match e.path.as_str().to_uppercase().as_str() {
|
||||||
|
"README" => true,
|
||||||
|
"README.MD" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mut ctx = Context::new();
|
if let Some(readme) = readme_candidates.get(0) {
|
||||||
|
/* unwrapping is ok because readme exists in Tree */
|
||||||
|
readme_content = tree.find_entry(readme).unwrap();
|
||||||
|
|
||||||
/* stubs til we have a real database */
|
todo!("convert Entry into BlobRef to get data")
|
||||||
ctx.insert("user", "anon");
|
}
|
||||||
ctx.insert("site", "TiB.");
|
*/
|
||||||
ctx.insert("notif_count", "");
|
|
||||||
ctx.insert("ticket_count", "(47)");
|
|
||||||
ctx.insert("directory", "");
|
|
||||||
|
|
||||||
ctx.insert("readme_content", "test readme");
|
/* stubs til we have a real database */
|
||||||
|
ctx.insert("user", "anon");
|
||||||
|
ctx.insert("site", "TiB.");
|
||||||
|
ctx.insert("notif_count", "");
|
||||||
|
ctx.insert("ticket_count", "(47)");
|
||||||
|
ctx.insert("directory", "");
|
||||||
|
|
||||||
ctx.insert("branches", &branches);
|
ctx.insert("readme_content", "test readme");
|
||||||
ctx.insert("entries", &entries);
|
|
||||||
ctx.insert("owner", "anon");
|
|
||||||
ctx.insert("branch", ¤t_branch);
|
|
||||||
ctx.insert("repo", name);
|
|
||||||
ctx.insert("entries", &entries);
|
|
||||||
|
|
||||||
Ok(ctx)
|
ctx.insert("branches", &branches);
|
||||||
|
ctx.insert("entries", &entries);
|
||||||
|
ctx.insert("owner", "anon");
|
||||||
|
ctx.insert("branch", ¤t_branch);
|
||||||
|
ctx.insert("repo", name);
|
||||||
|
ctx.insert("entries", &entries);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-30
@@ -21,27 +21,27 @@
|
|||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::{ self, Display, Formatter },
|
fmt::{ self, Display, Formatter },
|
||||||
path::Path,
|
io::Write,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tera::{ Context, Tera };
|
use gix::open;
|
||||||
|
use tera::Tera;
|
||||||
|
|
||||||
/* TODO: silt needs to export the HTTP error types */
|
use crate::backend::git::ToContext;
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum PageError {
|
|
||||||
NotFound,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum PageKind {
|
pub enum PageKind {
|
||||||
Code,
|
Code,
|
||||||
Dashboard,
|
Dashboard,
|
||||||
Tickets,
|
|
||||||
Project,
|
Project,
|
||||||
RawCode,
|
|
||||||
Repo,
|
Repo,
|
||||||
|
RepoSubDir,
|
||||||
|
Settings,
|
||||||
|
Tickets,
|
||||||
User,
|
User,
|
||||||
Invalid(PageError),
|
/* TODO: silt exports a generic frontend non-success status trait */
|
||||||
|
Invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PageKind {
|
impl Display for PageKind {
|
||||||
@@ -51,37 +51,56 @@ impl Display for PageKind {
|
|||||||
let path = match self {
|
let path = match self {
|
||||||
Code => "repo/code.html",
|
Code => "repo/code.html",
|
||||||
Dashboard => "dashboard.html",
|
Dashboard => "dashboard.html",
|
||||||
|
Project => "project.html",
|
||||||
|
Repo => "repo/repo.html",
|
||||||
|
RepoSubDir => "repo/repo.html",
|
||||||
|
Settings => "user/settings.html",
|
||||||
Tickets => "repo/tickets.html",
|
Tickets => "repo/tickets.html",
|
||||||
Repo => "repo/code.html",
|
|
||||||
User => "user.html",
|
User => "user.html",
|
||||||
_ => "",
|
Invalid => todo!("generate error pages based on error type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "./assets/templates/{}", path)
|
write!(f, "{}", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Page {
|
pub struct Page {
|
||||||
kind: PageKind,
|
pub kind: PageKind,
|
||||||
path: String,
|
pub path: String,
|
||||||
branch: Option<String>,
|
pub branch: Option<String>,
|
||||||
commit: Option<String>,
|
pub commit: Option<String>,
|
||||||
tag: Option<String>,
|
pub tag: Option<String>,
|
||||||
|
pub user: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
impl Page {
|
impl Page {
|
||||||
pub fn render(&self) -> Result<String, Box<dyn Error>> {
|
pub fn render(
|
||||||
let template_dir = self.kind.to_string();
|
&self, mut dest: Box<dyn Write>
|
||||||
let template = String::from_utf8(Path::new(&template_dir)
|
) -> Result<(), Box<dyn Error>> {
|
||||||
.to_path_buf()
|
/* TODO: replace ./assets/ with the actual templates directory,
|
||||||
.as_mut_os_string()
|
* i.e. /usr/local/share/mintee/ */
|
||||||
.as_encoded_bytes()
|
let tera = Tera::new("./assets/templates/**/*")?;
|
||||||
.to_vec()
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let tera = Tera::new(&page_dir)?;
|
use PageKind::*;
|
||||||
Ok(tera.render(&template, &ctx)?)
|
let ctx = match self.kind {
|
||||||
|
Code => todo!(),
|
||||||
|
Dashboard | Project | Settings | Tickets | User | Invalid => {
|
||||||
|
todo!()
|
||||||
|
},
|
||||||
|
Repo => {
|
||||||
|
open(&self.path)?
|
||||||
|
/*.rev_parse_single("@")?*/
|
||||||
|
.head_tree()?
|
||||||
|
.id()
|
||||||
|
.object()?
|
||||||
|
.to_context()?
|
||||||
|
},
|
||||||
|
RepoSubDir => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(dest.write_all(
|
||||||
|
tera.render(&self.kind.to_string(), &ctx)?.as_bytes()
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
+15
-62
@@ -19,73 +19,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env::{ args, current_dir },
|
env::current_dir,
|
||||||
error::Error,
|
error::Error,
|
||||||
|
io::stdout,
|
||||||
};
|
};
|
||||||
|
|
||||||
use gix::open;
|
use mintee::backend::render::{ Page, PageKind };
|
||||||
use tera::Tera;
|
|
||||||
|
|
||||||
use mintee::backend::git::repo_to_context;
|
|
||||||
|
|
||||||
/*
|
|
||||||
impl From<GitRepo> for Context {
|
|
||||||
fn from(repo: GitRepo) -> Self {
|
|
||||||
let mut ctx = Context::new();
|
|
||||||
|
|
||||||
let directory = format!("{}/{}", repo.owner, repo.name);
|
|
||||||
|
|
||||||
let main_branch = repo.branches
|
|
||||||
.iter()
|
|
||||||
.find(|b| b.name == "main")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let latest_commit = &main_branch.commits[0];
|
|
||||||
let hash = latest_commit.hash.clone();
|
|
||||||
|
|
||||||
let mut entries = Vec::new();
|
|
||||||
|
|
||||||
for e in latest_commit.entries.iter() {
|
|
||||||
let entry = SampleEntry {
|
|
||||||
class: e.kind.to_string(),
|
|
||||||
last_commit: hash.clone(),
|
|
||||||
last_commit_message: latest_commit.message.clone().unwrap(),
|
|
||||||
last_commit_time: latest_commit.time,
|
|
||||||
path: e.path.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
entries.push(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* stubs til we have a real database */
|
|
||||||
ctx.insert("user", "anon");
|
|
||||||
ctx.insert("site", "TiB.");
|
|
||||||
ctx.insert("notif_count", "");
|
|
||||||
ctx.insert("ticket_count", "(47)");
|
|
||||||
|
|
||||||
ctx.insert("readme_content", "this is a readme");
|
|
||||||
|
|
||||||
ctx.insert("owner", &repo.owner);
|
|
||||||
ctx.insert("branch", &main_branch.name);
|
|
||||||
ctx.insert("repo", &repo.name);
|
|
||||||
ctx.insert("directory", &directory);
|
|
||||||
ctx.insert("entries", &entries);
|
|
||||||
|
|
||||||
ctx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
if let Some(templates) = args().collect::<Vec<_>>().get(1) {
|
let path = String::from_utf8(
|
||||||
let tera = Tera::new(templates.as_str())?;
|
current_dir()?.into_os_string().into_encoded_bytes()
|
||||||
let ctx = repo_to_context(open(current_dir()?)?)?;
|
)?;
|
||||||
|
|
||||||
println!("{}", tera.render("repo.html", &ctx)?);
|
let page = Page {
|
||||||
|
kind: PageKind::Repo,
|
||||||
|
path,
|
||||||
|
branch: None,
|
||||||
|
commit: None,
|
||||||
|
tag: None,
|
||||||
|
user: None,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
page.render(Box::new(stdout()))
|
||||||
} else {
|
|
||||||
eprintln!("Usage: {} template_glob", args().collect::<Vec<_>>()[0]);
|
|
||||||
std::process::exit(64);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user