use anyhow::Result;
use handlebars::Handlebars;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tokio::fs;
pub struct TemplateManager {
handlebars: Handlebars<'static>,
templates_dir: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CrateSpec {
pub name: String,
pub description: String,
pub version: String,
pub authors: Vec<String>,
pub license: String,
pub repository: String,
pub homepage: String,
pub features: Vec<String>,
pub dependencies: HashMap<String, String>,
}
impl TemplateManager {
pub fn new(templates_dir: &Path) -> Result<Self> {
let mut handlebars = Handlebars::new();
handlebars.set_strict_mode(true);
Ok(Self {
handlebars,
templates_dir: templates_dir.to_path_buf(),
})
}
pub fn render(&self, template_name: &str, data: &CrateSpec) -> Result<String> {
self.handlebars
.render(template_name, data)
.map_err(anyhow::Error::from)
}
pub async fn render_crate(
&self,
_template: &str,
context: &CrateSpec,
output_dir: &Path,
) -> Result<()> {
fs::create_dir_all(output_dir).await?;
fs::create_dir_all(output_dir.join("src")).await?;
let cargo_content = self.handlebars.render("cargo_toml", context)?;
fs::write(output_dir.join("Cargo.toml"), cargo_content).await?;
let lib_content = self.handlebars.render("lib_rs", context)?;
fs::write(output_dir.join("src/lib.rs"), lib_content).await?;
if context
.get("binary")
.and_then(|v| v.as_bool())
.unwrap_or(false)
{
let main_content = self.handlebars.render("main_rs", context)?;
fs::write(output_dir.join("src/main.rs"), main_content).await?;
}
let readme_content = self.handlebars.render("readme", context)?;
fs::write(output_dir.join("README.md"), readme_content).await?;
Ok(())
}
}