1use crate::config::{EspforgeConfiguration, PlatformConfig};
2use crate::template_utils::{copy_verbatim, find_template_path, get_templates, write_template};
3use anyhow::{Context, Result, anyhow};
4use std::path::Path;
5
6pub struct ExportOptions {
7 pub example_name: String,
8 pub override_project_name: Option<String>,
9 pub override_platform: Option<String>,
10}
11
12pub fn export_example(options: ExportOptions, target_dir: &Path) -> Result<String> {
13 let root = get_templates();
14
15 let template_path_str = find_template_path(&options.example_name)
16 .ok_or_else(|| anyhow!("Example '{}' not found", options.example_name))?;
17
18 let template_dir = root.get_dir(&template_path_str).ok_or_else(|| {
19 anyhow!(
20 "Template directory structure error for '{}'",
21 options.example_name
22 )
23 })?;
24
25 let example_file = template_dir.path().join("example.yaml");
26 let yaml_file = root
28 .get_file(&example_file)
29 .ok_or_else(|| anyhow!("Template is missing example.yaml"))?;
30
31 let raw_yaml = yaml_file
32 .contents_utf8()
33 .context("Invalid UTF-8 in example.yaml")?;
34
35 let mut config: EspforgeConfiguration = serde_yaml_ng::from_str(raw_yaml)
36 .context("Failed to parse example.yaml into configuration")?;
37
38 if let Some(name) = options.override_project_name {
39 config.espforge.name = name;
40 }
41
42 if let Some(platform_str) = options.override_platform {
43 let platform_enum: PlatformConfig = serde_yaml_ng::from_str(&platform_str)
44 .map_err(|_| anyhow!("Invalid platform: {}", platform_str))?;
45 config.espforge.platform = platform_enum;
46 }
47
48 let project_name = config.get_name().to_string();
49
50 let yaml_filename = format!("{}.yaml", project_name);
51 let yaml_dest = target_dir.join(&yaml_filename);
52
53 let modified_yaml = serde_yaml_ng::to_string(&config)?;
54 write_template(&yaml_dest, &modified_yaml)?;
55 println!("Created config: {}", yaml_filename);
56
57 let project_path_str = target_dir.to_string_lossy();
58 let template_root_path = template_dir.path();
59
60 for entry in template_dir.find("**/*")? {
61 if let Some(file) = entry.as_file() {
62 let file_path = file.path();
63 let file_name = file_path.file_name().and_then(|n| n.to_str()).unwrap_or("");
64 if file_name == "example.yaml" {
65 continue;
66 }
67
68 if file_path
69 .components()
70 .any(|c| c.as_os_str() == ".zig-cache" || c.as_os_str() == "zig-out")
71 {
72 continue;
73 }
74
75 copy_verbatim(file, template_root_path, &project_path_str)?;
77 let relative_path = file_path
78 .strip_prefix(template_root_path)
79 .unwrap_or(file_path);
80 println!("Created file: {}", relative_path.display());
81 }
82 }
83
84 let target_cargo_tera = target_dir.join("Cargo.toml.tera");
85 if !target_cargo_tera.exists() {
86 if let Some(dynamic_cargo) = root.get_file("_dynamic/Cargo.toml.tera") {
87 copy_verbatim(dynamic_cargo, Path::new("_dynamic"), &project_path_str)?;
88 println!("Created file: Cargo.toml.tera (from _dynamic)");
89 }
90 }
91
92 Ok(project_name)
93}