feat: Initial rewrite of python render tool
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use minijinja::{AutoEscape, Environment, path_loader};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::{get_repo_path, get_talos_config_path};
|
||||
|
||||
/// Transparent wrapper around minijinja::Environment that loads templates from a path and
|
||||
/// configures better defaults. It also implements IntoIter, making it possible to iterate over all
|
||||
/// the templates.
|
||||
pub struct PathEnvironment<'a> {
|
||||
env: Environment<'a>,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl<'a> PathEnvironment<'a> {
|
||||
pub fn new(path: &Path) -> Self {
|
||||
let mut env = Environment::new();
|
||||
|
||||
// Configure jinja
|
||||
env.set_trim_blocks(true);
|
||||
env.set_lstrip_blocks(true);
|
||||
env.set_undefined_behavior(minijinja::UndefinedBehavior::Strict);
|
||||
env.set_auto_escape_callback(|_| AutoEscape::None);
|
||||
|
||||
// Add filters
|
||||
env.add_filter("to_prefix", |netmask: String| {
|
||||
let netmask = Ipv4Addr::from_str(&netmask).map_err(|err| {
|
||||
minijinja::Error::new(minijinja::ErrorKind::InvalidOperation, err.to_string())
|
||||
})?;
|
||||
let mask = netmask.to_bits();
|
||||
let prefix = mask.leading_ones();
|
||||
|
||||
if mask.checked_shl(prefix).unwrap_or(0) == 0 {
|
||||
Ok(prefix as u8)
|
||||
} else {
|
||||
Err(minijinja::Error::new(
|
||||
minijinja::ErrorKind::InvalidOperation,
|
||||
"invalid IP prefix length",
|
||||
))
|
||||
}
|
||||
});
|
||||
|
||||
// Add path loader
|
||||
env.set_loader(path_loader(&path));
|
||||
|
||||
Self {
|
||||
path: path.into(),
|
||||
env,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_patches() -> Self {
|
||||
Self::new(&get_talos_config_path().join("patches"))
|
||||
}
|
||||
|
||||
pub fn new_templates(repo: &Path) -> Self {
|
||||
let mut env = Self::new(&get_repo_path().join("templates"));
|
||||
|
||||
let path = repo.absolute().unwrap();
|
||||
env.env.add_filter("kubeconfig", move |names: Vec<String>| {
|
||||
names
|
||||
.iter()
|
||||
.map(|name| {
|
||||
path.join("configs")
|
||||
.join(name)
|
||||
.join("kubeconfig")
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
env
|
||||
}
|
||||
}
|
||||
|
||||
// Make PathEnvironment act like a normal Environment transparently
|
||||
impl<'a> Deref for PathEnvironment<'a> {
|
||||
type Target = Environment<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.env
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all the files in the path
|
||||
impl<'a, 'b> IntoIterator for &'b PathEnvironment<'a> {
|
||||
type Item = String;
|
||||
|
||||
type IntoIter = impl Iterator<Item = Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
// Find all templates in path
|
||||
WalkDir::new(&self.path)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| e.metadata().unwrap().is_file())
|
||||
.map(|e| {
|
||||
e.path()
|
||||
.strip_prefix(&self.path)
|
||||
.expect("All paths should have prefix")
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user