mecha10-templates 0.8.2

Mecha10 project templates — code generation, init, and template services
Documentation
//! Meta project file template generation
//!
//! Handles generation of project metadata files (README.md, .gitignore, package.json,

use crate::paths;
use anyhow::{Context, Result};
use std::path::Path;

async fn read_project_template(assets_root: &Path, name: &str) -> Result<String> {
    let template_path = assets_root.join("project").join(name);
    tokio::fs::read_to_string(&template_path)
        .await
        .with_context(|| format!("Failed to read {:?} from downloaded mecha10-assets", template_path))
}

pub struct MetaTemplates;

impl MetaTemplates {
    /// Create a new MetaTemplates instance
    pub fn new() -> Self {
        Self
    }

    /// Create README.md for the project, reading the template from the freshly-fetched
    /// `mecha10-assets` extraction at `assets_root`.
    pub async fn create_readme(&self, path: &Path, project_name: &str, assets_root: &Path) -> Result<()> {
        let template = read_project_template(assets_root, "README.md.template").await?;
        let content = template.replace("{{project_name}}", project_name);
        tokio::fs::write(path.join(paths::meta::README), content).await?;
        Ok(())
    }

    /// Create .gitignore for the project, reading the template from the freshly-fetched
    /// `mecha10-assets` extraction at `assets_root`.
    pub async fn create_gitignore(&self, path: &Path, assets_root: &Path) -> Result<()> {
        let content = read_project_template(assets_root, ".gitignore.template").await?;
        tokio::fs::write(path.join(paths::meta::GITIGNORE), content).await?;
        Ok(())
    }

    /// Create package.json for the project, reading the template from the freshly-fetched
    /// `mecha10-assets` extraction at `assets_root`.
    pub async fn create_package_json(&self, path: &Path, project_name: &str, assets_root: &Path) -> Result<()> {
        let template = read_project_template(assets_root, "package.json.template").await?;
        let content = template.replace("{{project_name}}", project_name);
        tokio::fs::write(path.join(paths::meta::PACKAGE_JSON), content).await?;
        Ok(())
    }

    /// Create requirements.txt for Python dependencies, reading the template from the
    /// freshly-fetched `mecha10-assets` extraction at `assets_root`.
    pub async fn create_requirements_txt(&self, path: &Path, assets_root: &Path) -> Result<()> {
        let content = read_project_template(assets_root, "requirements.txt.template").await?;
        tokio::fs::write(path.join(paths::meta::REQUIREMENTS_TXT), content).await?;
        Ok(())
    }

    /// Create `.python-version` pinning the exact Python version `mecha10 setup`
    /// should target for the RL/simulation venv, reading the template from the freshly-fetched
    /// `mecha10-assets` extraction at `assets_root`.
    pub async fn create_python_version(&self, path: &Path, assets_root: &Path) -> Result<()> {
        let content = read_project_template(assets_root, ".python-version.template").await?;
        tokio::fs::write(path.join(paths::meta::PYTHON_VERSION), content).await?;
        Ok(())
    }
}

impl Default for MetaTemplates {
    fn default() -> Self {
        Self::new()
    }
}