Skip to main content

actr_cli/commands/initialize/
mod.rs

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