actr_cli/commands/initialize/
mod.rs1mod kotlin;
2mod python;
3mod rust;
4mod swift;
5pub mod traits;
6mod typescript;
7
8use crate::commands::SupportedLanguage;
9use crate::error::{ActrCliError, Result};
10use crate::template::{DEFAULT_MANUFACTURER, EchoRole, ProjectTemplateName, TemplateContext};
11use crate::utils::read_fixture_text;
12use handlebars::Handlebars;
13use kotlin::KotlinInitializer;
14use python::PythonInitializer;
15use rust::RustInitializer;
16use std::path::Path;
17use std::process::Command;
18use swift::SwiftInitializer;
19use typescript::TypeScriptInitializer;
20
21pub use traits::{InitContext, ProjectInitializer};
22
23pub fn create_protoc_plugin_config(project_dir: &Path) -> Result<()> {
25 const DEFAULT_PLUGIN_MIN_VERSION: &str = "0.1.10";
26
27 let config_path = project_dir.join(".protoc-plugin.toml");
28 if config_path.exists() {
29 return Ok(());
30 }
31
32 if let Some(parent) = config_path.parent() {
33 std::fs::create_dir_all(parent)?;
34 }
35
36 let content = format!(
37 "version = 1\n\n[plugins]\nprotoc-gen-actrframework = \"{DEFAULT_PLUGIN_MIN_VERSION}\"\nprotoc-gen-actrframework-swift = \"{DEFAULT_PLUGIN_MIN_VERSION}\"\nprotoc-gen-actrframework-typescript = \"{DEFAULT_PLUGIN_MIN_VERSION}\"\n"
38 );
39
40 std::fs::write(&config_path, content)?;
41 tracing::info!("📄 Created .protoc-plugin.toml");
42 Ok(())
43}
44
45pub fn init_git_repo(project_dir: &Path) -> Result<()> {
46 let output = Command::new("git")
47 .args(["init"])
48 .current_dir(project_dir)
49 .output()
50 .map_err(|error| ActrCliError::Command(format!("Failed to run git init: {error}")))?;
51
52 if !output.status.success() {
53 let stderr = String::from_utf8_lossy(&output.stderr);
54 return Err(ActrCliError::Command(format!("git init failed: {stderr}")));
55 }
56
57 tracing::info!("🔧 Initialized git repository");
58 Ok(())
59}
60
61pub fn create_local_proto(
67 project_dir: &Path,
68 project_name: &str,
69 proto_dir: &str,
70 template: ProjectTemplateName,
71 echo_role: Option<EchoRole>,
72) -> Result<()> {
73 let proto_path = project_dir.join(proto_dir);
74 std::fs::create_dir_all(&proto_path)?;
75
76 let fixtures_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("fixtures");
78 let template_file_name = match (template, echo_role) {
79 (ProjectTemplateName::Echo, Some(EchoRole::Service)) => "echo_service.hbs",
80 (ProjectTemplateName::Echo, _) => "local.echo.hbs",
81 (ProjectTemplateName::Empty, _) => "local.empty.hbs",
82 (ProjectTemplateName::DataStream, _) => "local.empty.hbs",
83 };
84 let template_path = fixtures_root.join("protos").join(template_file_name);
85
86 let template_content = read_fixture_text(&template_path)?;
87
88 let template_context = TemplateContext::new(project_name, "", DEFAULT_MANUFACTURER, "", false);
90 let handlebars = Handlebars::new();
91
92 let local_proto_content = handlebars
94 .render_template(&template_content, &template_context)
95 .map_err(|e| {
96 ActrCliError::Io(std::io::Error::new(
97 std::io::ErrorKind::InvalidData,
98 format!("Failed to render proto template: {}", e),
99 ))
100 })?;
101
102 let proto_output_name = match (template, echo_role) {
103 (ProjectTemplateName::Echo, Some(EchoRole::Service)) => "echo.proto",
104 _ => "local.proto",
105 };
106 let proto_output_path = proto_path.join(proto_output_name);
107 std::fs::write(&proto_output_path, local_proto_content)?;
108
109 tracing::info!("📄 Created {}", proto_output_path.display());
110 Ok(())
111}
112
113pub struct InitializerFactory;
114
115impl InitializerFactory {
116 pub fn get_initializer(language: SupportedLanguage) -> Result<Box<dyn ProjectInitializer>> {
117 match language {
118 SupportedLanguage::Rust => Ok(Box::new(RustInitializer)),
119 SupportedLanguage::Python => Ok(Box::new(PythonInitializer)),
120 SupportedLanguage::Swift => Ok(Box::new(SwiftInitializer)),
121 SupportedLanguage::Kotlin => Ok(Box::new(KotlinInitializer)),
122 SupportedLanguage::TypeScript => Ok(Box::new(TypeScriptInitializer)),
123 }
124 }
125}
126
127pub async fn execute_initialize(language: SupportedLanguage, context: &InitContext) -> Result<()> {
128 let initializer = InitializerFactory::get_initializer(language)?;
129 initializer.generate_project_structure(context).await?;
130 initializer.print_next_steps(context);
131 Ok(())
132}