espforge_lib/generate/
operations.rs

1// generate/file_operations.rs - File and directory operations
2
3use super::manifest;
4use anyhow::{Context, Result};
5use include_dir::Dir;
6use log::{debug, info};
7use std::fs;
8use std::path::Path;
9
10pub fn copy_components(src_path: &Path) -> Result<()> {
11    let components_path = src_path.join("components");
12    copy_dir_files(
13        manifest::components_dir(), 
14        &components_path, 
15        |path| path.ends_with(".rs")
16    ).context("Failed to copy components")?;
17    info!("Copied component files");
18    Ok(())
19}
20
21pub fn copy_devices(src_path: &Path) -> Result<()> {
22    let devices_path = src_path.join("devices");
23    fs::create_dir_all(&devices_path)
24        .with_context(|| format!("Failed to create directory: {}", devices_path.display()))?;
25
26    let mut modules = Vec::new();
27
28    for subdir in manifest::devices_dir().dirs() {
29        let device_name = subdir.path().file_name().unwrap().to_str().unwrap();
30        
31        // Find device.rs in the device subdirectory (e.g. devices/ili9341/device.rs)
32        if let Some(file) = subdir.files().find(|f| f.path().file_name().and_then(|n| n.to_str()) == Some("device.rs")) {
33            // Copy it to src/devices/<device_name>.rs
34            let dest_file = devices_path.join(format!("{}.rs", device_name));
35            fs::write(&dest_file, file.contents())
36                .with_context(|| format!("Failed to write device file: {}", dest_file.display()))?;
37            modules.push(device_name.to_string());
38            debug!("Copied device: {}", device_name);
39        }
40    }
41    
42    // Sort modules for deterministic output
43    modules.sort();
44
45    // Generate src/devices/mod.rs
46    generate_mod_file(&devices_path, &modules, true)?;
47    info!("Copied device files");
48    Ok(())
49}
50
51pub fn copy_platform_files(src_path: &Path) -> Result<()> {
52    let platform_path = src_path.join("platform");
53    copy_dir_files(manifest::platform_dir(), &platform_path, |_| true)
54        .context("Failed to copy platform files")?;
55    info!("Copied platform files");
56    Ok(())
57}
58
59pub fn copy_dir_files<F>(dir: &Dir<'_>, dest_path: &Path, filter: F) -> Result<()>
60where
61    F: Fn(&str) -> bool,
62{
63    fs::create_dir_all(dest_path)
64        .with_context(|| format!("Failed to create directory: {}", dest_path.display()))?;
65
66    for file in dir.files() {
67        let file_path_str = file.path().to_str().context("Invalid UTF-8 in file path")?;
68        
69        if filter(file_path_str) {
70            let dest_file = dest_path.join(file.path());
71            fs::write(&dest_file, file.contents())
72                .with_context(|| format!("Failed to write file: {}", dest_file.display()))?;
73            debug!("Copied: {}", file_path_str);
74        }
75    }
76    
77    Ok(())
78}
79
80pub fn copy_globals_files(src_path: &Path) -> Result<()> {
81    let globals_path = src_path.join("globals");
82    copy_dir_files(
83        manifest::globals_dir(), 
84        &globals_path, 
85        |path| path.ends_with(".rs")
86    ).context("Failed to copy global files")?;
87    info!("Copied global files");
88    Ok(())
89}
90
91
92pub fn generate_mod_file(dir_path: &Path, modules: &[String], use_pub_use: bool) -> Result<()> {
93    let mut content = String::from("#![allow(unused_imports)]\n");
94    
95    for module in modules {
96        content.push_str(&format!("pub mod {};\n", module));
97        if use_pub_use {
98            content.push_str(&format!("pub use {}::*;\n", module));
99        } else {
100            content.push_str(&format!("pub use {}::*;\n", module));
101        }
102    }
103    
104    let mod_file = dir_path.join("mod.rs");
105    fs::write(&mod_file, content)
106        .with_context(|| format!("Failed to write mod file: {}", mod_file.display()))?;
107    
108    debug!("Generated mod.rs with {} modules", modules.len());
109    Ok(())
110}