feat: add templating to project

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2023-06-17 12:54:06 +02:00
parent 2f2fdb9631
commit 2241941f0e
3 changed files with 117 additions and 8 deletions

View File

@@ -11,7 +11,7 @@ path = "src/main.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.60"
anyhow = { version = "1.0.60", features = ["backtrace"] }
serde = { version = "1.0.143", features = ["derive"] }
serde_yaml = "0.9.4"
walkdir = "2.3.2"

View File

@@ -1,7 +1,11 @@
use std::collections::BTreeMap;
use std::fs::{create_dir_all, read, read_dir};
use std::io::Write;
use std::mem::replace;
use std::path::PathBuf;
use clap::{ArgMatches, Command};
use walkdir::WalkDir;
use crate::cli::CuddleCli;
@@ -105,7 +109,7 @@ pub fn execute_init(exe_submatch: &ArgMatches, _cli: CuddleCli) -> anyhow::Resul
}
};
let (_name, template_dir, _template) = template?;
let (_name, template_dir, mut template) = template?;
let path = match path {
Some(path) => path.clone(),
@@ -128,21 +132,61 @@ pub fn execute_init(exe_submatch: &ArgMatches, _cli: CuddleCli) -> anyhow::Resul
}
}
for entry in read_dir(template_dir)? {
{
if let Some(ref mut prompt) = template.prompt {
for (name, prompt) in prompt {
let value = inquire::Text::new(&name)
.with_help_message(&prompt.description)
.prompt()?;
prompt.value = value;
}
}
}
for entry in WalkDir::new(&template_dir).follow_links(false) {
let entry = entry?;
let entry_path = entry.path();
let name = entry.file_name();
if name == "cuddle-template.json" || name == "cuddle-templates.json" {
continue;
let new_path = PathBuf::from(&path).join(entry_path.strip_prefix(&template_dir)?);
let new_path = replace_with_variables(&new_path.to_string_lossy().to_string(), &template)?;
let new_path = PathBuf::from(new_path);
if entry_path.is_dir() {
create_dir_all(&new_path)?;
}
std::fs::rename(entry_path, std::path::PathBuf::from(&path).join(name))?;
if entry_path.is_file() {
let name = entry.file_name();
if let Some(parent) = entry_path.parent() {
create_dir_all(parent)?;
}
if name == "cuddle-template.json" || name == "cuddle-templates.json" {
continue;
}
tracing::info!("writing to: {}", new_path.display());
let new_content =
replace_with_variables(&std::fs::read_to_string(entry_path)?, &template)?;
std::fs::write(new_path, new_content.as_bytes())?;
}
}
Ok(())
}
fn replace_with_variables(content: &str, template: &CuddleTemplate) -> anyhow::Result<String> {
let mut content = content.to_string();
if let Some(prompt) = &template.prompt {
for (name, value) in prompt {
content = content.replace(&format!("%%{}%%", name), &value.value);
}
}
Ok(content)
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct CuddleTemplates {
pub templates: Vec<String>,
@@ -151,4 +195,12 @@ struct CuddleTemplates {
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct CuddleTemplate {
pub name: String,
pub prompt: Option<BTreeMap<String, CuddleTemplatePrompt>>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct CuddleTemplatePrompt {
pub description: String,
#[serde(skip)]
pub value: String,
}