feat: can recursively load files

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
Kasper Juul Hermansen 2024-05-21 21:46:22 +02:00
parent 06ad4515c2
commit 461f8acb73
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
16 changed files with 83 additions and 18 deletions

View File

@ -1,3 +1,5 @@
#![feature(map_try_insert)]
pub mod components;
pub use components::*;

View File

@ -5,6 +5,7 @@ use std::{
};
use anyhow::Context;
use futures::{future::BoxFuture, FutureExt};
use minijinja::context;
use tokio::io::AsyncWriteExt;
use tokio_stream::{wrappers::ReadDirStream, StreamExt};
@ -32,6 +33,9 @@ impl Default for ProcessOpts {
}
}
const TEMPLATES_PATH_PREFIX: &str = "templates/clusters";
const CUDDLE_PLAN_PATH_PREFIX: &str = ".cuddle/plan";
pub async fn process_opts(
components: impl IntoIterator<Item = impl IntoComponent>,
opts: ProcessOpts,
@ -44,18 +48,17 @@ pub async fn process_opts(
let path = opts.path.canonicalize().context("failed to find folder")?;
let cuddle_path = path.join("cuddle.yaml");
let template = path.join("templates").join("clusters");
tracing::debug!(
"searching for templates in: {} with cuddle: {}",
template.display(),
path.display(),
cuddle_path.display()
);
let clusters = read_cuddle_section(&cuddle_path).await?;
tracing::debug!("found clusters: {:?}", clusters);
let template_files = load_template_files(&template).await?;
let template_files = load_template_files(&path).await?;
tracing::debug!("found files: {:?}", template_files);
tokio::fs::remove_dir_all(&opts.output).await?;
@ -100,31 +103,70 @@ async fn read_cuddle_section(path: &Path) -> anyhow::Result<CuddleClusters> {
#[derive(Debug, Clone)]
struct TemplateFiles {
templates: Vec<PathBuf>,
raw: Vec<PathBuf>,
templates: HashMap<String, PathBuf>,
raw: HashMap<String, PathBuf>,
}
async fn load_template_files(path: &Path) -> anyhow::Result<TemplateFiles> {
Ok(TemplateFiles {
templates: read_dir(path)
impl TemplateFiles {
fn merge(&mut self, template_files: TemplateFiles) {
for (name, path) in template_files.templates {
// Ignored if the key is already present
let _ = self.templates.try_insert(name, path);
}
for (name, path) in template_files.raw {
// Ignored if the key is already present
let _ = self.raw.try_insert(name, path);
}
}
}
fn load_template_files(path: &Path) -> BoxFuture<'static, anyhow::Result<TemplateFiles>> {
let template_path = path.join(TEMPLATES_PATH_PREFIX);
let path = path.to_path_buf();
tracing::info!("reading folder: {}", path.display());
async move {
let templates = read_dir(&template_path)
.await?
.into_iter()
.filter(|i| i.extension().and_then(|e| e.to_str()) == Some("jinja2"))
.collect(),
raw: read_dir(&path.join("raw")).await.unwrap_or_default(),
})
.filter(|(_, i)| i.extension().and_then(|e| e.to_str()) == Some("jinja2"))
.collect();
let raw = read_dir(&template_path.join("raw"))
.await
.unwrap_or_default();
let mut template_files = TemplateFiles { templates, raw };
let nested_path = path.join(CUDDLE_PLAN_PATH_PREFIX);
tracing::info!("trying to read: {}", nested_path.display());
if nested_path.exists() {
let nested = load_template_files(&nested_path).await?;
template_files.merge(nested);
}
Ok(template_files)
}
.boxed()
}
async fn read_dir(path: &Path) -> anyhow::Result<Vec<PathBuf>> {
async fn read_dir(path: &Path) -> anyhow::Result<HashMap<String, PathBuf>> {
let template_dir = tokio::fs::read_dir(path).await?;
let mut template_dir_stream = ReadDirStream::new(template_dir);
let mut paths = Vec::new();
let mut paths = HashMap::new();
while let Some(entry) = template_dir_stream.next().await {
let entry = entry?;
if entry.metadata().await?.is_file() {
paths.push(entry.path());
paths.insert(
entry
.path()
.file_name()
.expect("the file to have a filename")
.to_string_lossy()
.to_string(),
entry.path(),
);
}
}
@ -139,7 +181,7 @@ async fn process_templates(
) -> anyhow::Result<()> {
for (environment, value) in clusters.iter() {
process_cluster(
&components,
components,
value,
environment,
template_files,
@ -158,11 +200,11 @@ async fn process_cluster(
template_files: &TemplateFiles,
dest: &Path,
) -> anyhow::Result<()> {
for template_file in &template_files.templates {
for (_, template_file) in &template_files.templates {
process_template_file(components, value, environment, template_file, dest).await?;
}
for raw_file in &template_files.raw {
for (_, raw_file) in &template_files.raw {
process_raw_file(environment, raw_file, dest).await?;
}

View File

@ -0,0 +1,2 @@
cuddle/clusters:
dev:

View File

@ -0,0 +1 @@
nested

View File

@ -0,0 +1 @@
nested

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
service

View File

@ -27,6 +27,13 @@ async fn both() -> anyhow::Result<()> {
Ok(())
}
#[tokio::test]
async fn nested() -> anyhow::Result<()> {
run_test("nested").await?;
Ok(())
}
#[tokio::test]
async fn jinja() -> anyhow::Result<()> {
run_test("jinja").await?;