espforge_lib/examples/
template.rs

1use super::config::ConfigFile;
2use super::fs::OutputDirectory;
3use crate::cli::model::{ExampleConfig, ExportResult};
4use anyhow::{Context, Result, anyhow};
5use espforge_examples::EXAMPLES_DIR;
6use std::fs;
7use std::path::Path;
8
9pub struct ExampleExporter;
10
11impl ExampleExporter {
12    pub fn new() -> Self {
13        Self
14    }
15
16    pub fn export(&self, config: &ExampleConfig, output: &OutputDirectory) -> Result<ExportResult> {
17        let template = ExampleTemplate::find(&config.template_name)?;
18        template.extract_to(output.path())?;
19
20        let config_file = ConfigFile::locate(output.path())?;
21        config_file.update(config)?;
22
23        let final_name = config_file.rename_to(&config.project_name)?;
24
25        Ok(ExportResult {
26            project_name: config.project_name.clone(),
27            output_file: format!("{}.yaml", final_name),
28        })
29    }
30}
31
32struct ExampleTemplate {
33    dir: &'static include_dir::Dir<'static>,
34}
35
36impl ExampleTemplate {
37    fn find(name: &str) -> Result<Self> {
38        let dir = Self::search_in_catalog(name)
39            .ok_or_else(|| anyhow!("Example template '{}' not found", name))?;
40
41        Ok(Self { dir })
42    }
43
44    fn search_in_catalog(name: &str) -> Option<&'static include_dir::Dir<'static>> {
45        EXAMPLES_DIR
46            .dirs()
47            .flat_map(|category| category.dirs())
48            .find(|example| example.path().file_name().and_then(|n| n.to_str()) == Some(name))
49    }
50
51    fn extract_to(&self, target: &Path) -> Result<()> {
52        extract_recursive(self.dir, target, self.dir.path())
53            .context("Failed to extract example files to disk")
54    }
55}
56
57fn extract_recursive(
58    dir: &include_dir::Dir,
59    base_path: &Path,
60    root_prefix: &Path,
61) -> std::io::Result<()> {
62    // Logic to strip prefix and write files/directories recursively
63    let dir_path = dir.path();
64    let relative_dir_path = dir_path
65        .strip_prefix(root_prefix)
66        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
67
68    let dest_dir = base_path.join(relative_dir_path);
69    if !dest_dir.exists() {
70        fs::create_dir_all(&dest_dir)?;
71    }
72
73    for file in dir.files() {
74        let path = file.path();
75        let relative_path = path
76            .strip_prefix(root_prefix)
77            .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
78
79        let dest_path = base_path.join(relative_path);
80
81        if let Some(parent) = dest_path.parent() {
82            fs::create_dir_all(parent)?;
83        }
84
85        fs::write(dest_path, file.contents())?;
86    }
87
88    for subdir in dir.dirs() {
89        extract_recursive(subdir, base_path, root_prefix)?;
90    }
91
92    Ok(())
93}