actr_cli/commands/initialize/
mod.rs

1mod kotlin;
2mod python;
3mod swift;
4pub mod traits;
5
6use crate::commands::SupportedLanguage;
7use crate::error::{ActrCliError, Result};
8use crate::template::{ProjectTemplateName, TemplateContext};
9use handlebars::Handlebars;
10use kotlin::KotlinInitializer;
11use python::PythonInitializer;
12use std::path::Path;
13use swift::SwiftInitializer;
14
15pub use traits::{InitContext, ProjectInitializer};
16
17/// Create .protoc-plugin.toml with default minimum versions.
18pub fn create_protoc_plugin_config(project_dir: &Path) -> Result<()> {
19    const DEFAULT_PLUGIN_MIN_VERSION: &str = "0.1.10";
20
21    let config_path = project_dir.join(".protoc-plugin.toml");
22    if config_path.exists() {
23        return Ok(());
24    }
25
26    if let Some(parent) = config_path.parent() {
27        std::fs::create_dir_all(parent)?;
28    }
29
30    let content = format!(
31        "version = 1\n\n[plugins]\nprotoc-gen-actrframework = \"{DEFAULT_PLUGIN_MIN_VERSION}\"\nprotoc-gen-actrframework-swift = \"{DEFAULT_PLUGIN_MIN_VERSION}\"\n"
32    );
33
34    std::fs::write(&config_path, content)?;
35    tracing::info!("📄 Created .protoc-plugin.toml");
36    Ok(())
37}
38
39/// Generate a local.proto file with the given package name
40pub fn create_local_proto(
41    project_dir: &Path,
42    project_name: &str,
43    proto_dir: &str,
44    template: ProjectTemplateName,
45) -> Result<()> {
46    let proto_path = project_dir.join(proto_dir);
47    std::fs::create_dir_all(&proto_path)?;
48
49    // Load template file
50    let fixtures_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("fixtures");
51    let template_file_name = match template {
52        ProjectTemplateName::Echo => "local.echo.hbs",
53        ProjectTemplateName::DataStream => "local.data-stream.hbs",
54    };
55    let template_path = fixtures_root.join("protos").join(template_file_name);
56
57    let template_content = std::fs::read_to_string(&template_path).map_err(|e| {
58        ActrCliError::Io(std::io::Error::new(
59            std::io::ErrorKind::NotFound,
60            format!(
61                "Failed to read proto template {}: {}",
62                template_path.display(),
63                e
64            ),
65        ))
66    })?;
67
68    // Create template context
69    let template_context = TemplateContext::new(project_name, "", "");
70    let handlebars = Handlebars::new();
71
72    // Render template
73    let local_proto_content = handlebars
74        .render_template(&template_content, &template_context)
75        .map_err(|e| {
76            ActrCliError::Io(std::io::Error::new(
77                std::io::ErrorKind::InvalidData,
78                format!("Failed to render proto template: {}", e),
79            ))
80        })?;
81
82    let local_proto_path = proto_path.join("local.proto");
83    std::fs::write(&local_proto_path, local_proto_content)?;
84
85    tracing::info!("📄 Created {}", local_proto_path.display());
86    Ok(())
87}
88
89pub struct InitializerFactory;
90
91impl InitializerFactory {
92    pub fn get_initializer(language: SupportedLanguage) -> Result<Box<dyn ProjectInitializer>> {
93        match language {
94            SupportedLanguage::Rust => Err(ActrCliError::Unsupported(
95                "Rust initialization is handled by InitCommand".to_string(),
96            )),
97            SupportedLanguage::Python => Ok(Box::new(PythonInitializer)),
98            SupportedLanguage::Swift => Ok(Box::new(SwiftInitializer)),
99            SupportedLanguage::Kotlin => Ok(Box::new(KotlinInitializer)),
100        }
101    }
102}
103
104pub async fn execute_initialize(language: SupportedLanguage, context: &InitContext) -> Result<()> {
105    let initializer = InitializerFactory::get_initializer(language)?;
106    initializer.generate_project_structure(context).await?;
107    initializer.print_next_steps(context);
108    Ok(())
109}