add a files output template

This commit is contained in:
Trevor Bentley
2023-01-13 04:37:40 +01:00
parent 51007c68b8
commit 0966bb534f
5 changed files with 85 additions and 4 deletions
+23 -2
View File
@@ -3,7 +3,7 @@ use crate::{
git::{dir_listing, parse_repo, GitFile, GitRepo, GitsyMetadata},
loud, louder, loudest, normal, normal_noln,
settings::{GitsyCli, GitsyRepoDescriptions, GitsySettings, GitsySettingsRepo},
template::{DirFilter, FileFilter, Pagination, TsDateFn, TsTimestampFn},
template::{DirFilter, FileFilter, HexFilter, MaskFilter, OctFilter, Pagination, TsDateFn, TsTimestampFn},
util::GitsyError,
};
use git2::{Error, Repository};
@@ -169,6 +169,9 @@ impl GitsyGenerator {
let mut tera = Tera::new(&template_path.to_string_lossy().to_string())?;
tera.register_filter("only_files", FileFilter {});
tera.register_filter("only_dirs", DirFilter {});
tera.register_filter("hex", HexFilter {});
tera.register_filter("oct", OctFilter {});
tera.register_filter("mask", MaskFilter {});
tera.register_function("ts_to_date", TsDateFn {});
tera.register_function("ts_to_git_timestamp", TsTimestampFn {});
Ok(tera)
@@ -330,6 +333,8 @@ impl GitsyGenerator {
if let Some(site_description) = &self.settings.site_description {
local_ctx.insert("site_description", site_description);
}
local_ctx.insert("site_dir", &self.settings.outputs.output_dir());
local_ctx.insert("site_assets", &self.settings.outputs.global_assets(None, None));
local_ctx.insert("site_generated_ts", &generated_dt.timestamp());
local_ctx.insert("site_generated_offset", &generated_dt.offset().local_minus_utc());
@@ -488,7 +493,7 @@ impl GitsyGenerator {
repo_desc
.syntax_highlight_theme
.as_deref()
.unwrap_or("base16-ocean.light"),
.unwrap_or("base16-ocean.dark"),
)
.expect("Invalid syntax highlighting theme specified.");
let css: String = css_for_theme_with_class_style(theme, syntect::html::ClassStyle::Spaced)
@@ -549,6 +554,7 @@ impl GitsyGenerator {
continue;
}
let listing = dir_listing(&repo, &dir).expect("Failed to parse file.");
local_ctx.insert("dir", dir);
local_ctx
.try_insert("files", &listing)
.expect("Failed to add dir to template engine.");
@@ -564,6 +570,19 @@ impl GitsyGenerator {
}
}
local_ctx.remove("files");
local_ctx.remove("dir");
}
if let Some(templ_file) = self.settings.templates.files.as_deref() {
match tera.render(templ_file, &local_ctx) {
Ok(rendered) => {
repo_bytes +=
self.write_rendered(&self.settings.outputs.files(Some(&summary), None), &rendered);
}
Err(x) => match x.kind {
_ => error!("ERROR: {:?}", x),
},
}
}
if repo_desc.asset_files.is_some() {
@@ -625,6 +644,8 @@ impl GitsyGenerator {
if let Some(site_description) = &self.settings.site_description {
global_ctx.insert("site_description", site_description);
}
global_ctx.insert("site_dir", &self.settings.outputs.output_dir());
global_ctx.insert("site_assets", &self.settings.outputs.global_assets(None, None));
global_ctx.insert("site_generated_ts", &generated_dt.timestamp());
global_ctx.insert("site_generated_offset", &generated_dt.offset().local_minus_utc());
+1
View File
@@ -10,6 +10,7 @@ use settings::{GitsyCli, GitsySettings};
// TODO:
//
// * basic, light, dark, and fancy default themes
// * specify default branch, use instead of HEAD
// * better error propagation
// * automated tests
// * documentation + examples
+10
View File
@@ -76,6 +76,7 @@ pub struct GitsySettingsTemplates {
pub branch: Option<String>,
pub tags: Option<String>,
pub tag: Option<String>,
pub files: Option<String>,
pub file: Option<String>,
pub dir: Option<String>,
pub error: Option<String>,
@@ -93,6 +94,7 @@ pub struct GitsySettingsOutputs {
pub branch: Option<String>,
pub tags: Option<String>,
pub tag: Option<String>,
pub files: Option<String>,
pub file: Option<String>,
pub dir: Option<String>,
pub error: Option<String>,
@@ -159,12 +161,20 @@ impl GitsySettingsOutputs {
output_path_fn!(branch, GitObject, full_hash, false, "%REPO%/branch/%ID%.html");
output_path_fn!(tags, GitObject, full_hash, false, "%REPO%/tags%PAGE%.html");
output_path_fn!(tag, GitObject, full_hash, false, "%REPO%/tag/%ID%.html");
output_path_fn!(files, GitObject, full_hash, false, "%REPO%/files.html");
output_path_fn!(file, GitFile, id, false, "%REPO%/file/%ID%.html");
output_path_fn!(syntax_css, GitObject, full_hash, false, "%REPO%/file/syntax.css");
output_path_fn!(dir, GitFile, id, false, "%REPO%/dir/%ID%.html");
output_path_fn!(error, GitObject, full_hash, false, "404.html");
output_path_fn!(global_assets, GitObject, full_hash, true, "assets/");
output_path_fn!(repo_assets, GitObject, full_hash, true, "%REPO%/assets/");
pub fn output_dir(&self) -> String {
self.path.clone().canonicalize()
.expect(&format!("ERROR: unable to canonicalize output path: {}", self.path.display()))
.to_str().expect(&format!("ERROR: unable to parse output path: {}", self.path.display()))
.to_string()
}
}
#[derive(Clone, Deserialize, Default, Debug)]
+41 -1
View File
@@ -3,7 +3,7 @@ use chrono::{naive::NaiveDateTime, offset::FixedOffset, DateTime};
use serde::Serialize;
use std::collections::HashMap;
use std::path::PathBuf;
use tera::{to_value, try_get_value, Filter, Function, Value};
use tera::{from_value, to_value, try_get_value, Filter, Function, Value};
fn ts_to_date(ts: i64, offset: Option<i64>, format: Option<String>) -> String {
let offset = offset.unwrap_or(0);
@@ -54,6 +54,46 @@ impl Filter for DirFilter {
}
}
pub struct HexFilter;
impl Filter for HexFilter {
fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
let v: i64 = try_get_value!("hex", "value", i64, value);
Ok(to_value(format!("{:x}", v)).unwrap())
}
}
pub struct OctFilter;
impl Filter for OctFilter {
fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
let v: i64 = try_get_value!("oct", "value", i64, value);
Ok(to_value(format!("{:o}", v)).unwrap())
}
}
pub struct MaskFilter;
impl Filter for MaskFilter {
fn filter(&self, value: &Value, args: &HashMap<String, Value>) -> Result<Value, tera::Error> {
let v: u64 = try_get_value!("mask", "value", u64, value);
let mask: String = from_value(
args.get("mask")
.expect("ERROR: Tera mask filter called without `mask` parameter.")
.clone(),
)
.expect("ERROR: Tera `mask` parameter is not valid.");
let mask: u64 = match mask.starts_with("0x") {
true => {
let hexstr = mask.strip_prefix("0x").unwrap();
u64::from_str_radix(hexstr, 16)
.expect("ERROR: Tera `mask` parameter is invalid hex.")
},
false => {
str::parse::<u64>(&mask).expect("ERROR: Tera `mask` parameter is not valid.")
},
};
Ok(to_value(v & mask).unwrap())
}
}
pub struct TsDateFn;
impl Function for TsDateFn {
fn call(&self, args: &HashMap<String, Value>) -> Result<Value, tera::Error> {