lmrc_cli/generator/
mod.rs

1mod apps;
2mod documentation;
3mod gitlab_ci;
4mod pipeline;
5mod workspace;
6
7use colored::Colorize;
8use lmrc_config_validator::LmrcConfig;
9use std::fs;
10use std::path::{Path, PathBuf};
11
12use crate::error::Result;
13
14pub struct ProjectGenerator {
15    config: LmrcConfig,
16    project_path: PathBuf,
17}
18
19impl ProjectGenerator {
20    pub fn new(config: LmrcConfig, project_path: PathBuf) -> Self {
21        Self {
22            config,
23            project_path,
24        }
25    }
26
27    pub fn project_path(&self) -> &Path {
28        &self.project_path
29    }
30
31    pub async fn generate(&self) -> Result<()> {
32        println!("{}", "Generating project structure...".yellow());
33
34        // Create root directory
35        fs::create_dir_all(&self.project_path)?;
36
37        // Create directory structure
38        self.create_directory_structure()?;
39
40        // Generate workspace Cargo.toml
41        workspace::generate_workspace_toml(&self.project_path, &self.config)?;
42
43        // Generate configuration file
44        self.generate_config_file()?;
45
46        // Generate applications
47        self.generate_applications()?;
48
49        // Generate libs directory with placeholders
50        self.generate_libs()?;
51
52        // Generate pipeline application
53        pipeline::generate_pipeline_app(&self.project_path, &self.config)?;
54
55        // Generate GitLab CI configuration
56        gitlab_ci::generate_gitlab_ci(&self.project_path, &self.config)?;
57
58        // Generate documentation
59        documentation::generate_docs(&self.project_path, &self.config)?;
60
61        // Generate Docker files
62        self.generate_docker_files()?;
63
64        // Generate .gitignore
65        self.generate_gitignore()?;
66
67        Ok(())
68    }
69
70    fn create_directory_structure(&self) -> Result<()> {
71        let dirs = vec!["apps", "libs", "docs", "docker", "infra"];
72
73        for dir in dirs {
74            let path = self.project_path.join(dir);
75            fs::create_dir_all(&path)?;
76            println!("  {} {}", "Created:".green(), path.display());
77        }
78
79        Ok(())
80    }
81
82    fn generate_config_file(&self) -> Result<()> {
83        let config_content = self.config.to_toml_string()?;
84        let config_path = self.project_path.join("lmrc.toml");
85        fs::write(&config_path, config_content)?;
86        println!("  {} {}", "Created:".green(), config_path.display());
87        Ok(())
88    }
89
90    fn generate_applications(&self) -> Result<()> {
91        // Use the new apps module to generate applications from templates
92        apps::generate_applications(&self.project_path, &self.config)?;
93        Ok(())
94    }
95
96    fn generate_libs(&self) -> Result<()> {
97        let libs_path = self.project_path.join("libs");
98        let readme = r#"# Shared Libraries
99
100This directory contains shared libraries used across multiple applications.
101
102Place reusable code, utilities, and shared logic here.
103"#;
104        fs::write(libs_path.join("README.md"), readme)?;
105        println!("  {} libs/README.md", "Created:".green());
106        Ok(())
107    }
108
109    fn generate_docker_files(&self) -> Result<()> {
110        let docker_path = self.project_path.join("docker");
111
112        // Generate Dockerfile template for applications
113        let dockerfile = r#"# Build stage
114FROM rust:1.75-slim as builder
115
116WORKDIR /app
117COPY . .
118
119RUN cargo build --release
120
121# Runtime stage
122FROM debian:bookworm-slim
123
124RUN apt-get update && \
125    apt-get install -y ca-certificates && \
126    rm -rf /var/lib/apt/lists/*
127
128WORKDIR /app
129
130COPY --from=builder /app/target/release/app /app/app
131
132ENTRYPOINT ["/app/app"]
133"#;
134
135        fs::write(docker_path.join("Dockerfile"), dockerfile)?;
136        println!("  {} docker/Dockerfile", "Created:".green());
137
138        // Generate docker-compose.yml for local development
139        let docker_compose = format!(
140            r#"version: '3.8'
141
142services:
143  postgres:
144    image: postgres:{}
145    environment:
146      POSTGRES_DB: {}
147      POSTGRES_USER: postgres
148      POSTGRES_PASSWORD: postgres
149    ports:
150      - "5432:5432"
151    volumes:
152      - postgres_data:/var/lib/postgresql/data
153
154volumes:
155  postgres_data:
156"#,
157            self.config
158                .infrastructure
159                .postgres
160                .as_ref()
161                .map(|p| p.version.as_str())
162                .unwrap_or("16"),
163            self.config
164                .infrastructure
165                .postgres
166                .as_ref()
167                .map(|p| p.database_name.as_str())
168                .unwrap_or("myapp")
169        );
170
171        fs::write(docker_path.join("docker-compose.yml"), docker_compose)?;
172        println!("  {} docker/docker-compose.yml", "Created:".green());
173
174        Ok(())
175    }
176
177    fn generate_gitignore(&self) -> Result<()> {
178        let gitignore = r#"# Rust
179/target/
180**/*.rs.bk
181*.pdb
182Cargo.lock
183
184# IDE
185.idea/
186.vscode/
187*.swp
188*.swo
189*~
190
191# OS
192.DS_Store
193Thumbs.db
194
195# Environment
196.env
197.env.local
198
199# Secrets
200secrets/
201*.pem
202*.key
203"#;
204
205        let gitignore_path = self.project_path.join(".gitignore");
206        fs::write(&gitignore_path, gitignore)?;
207        println!("  {} .gitignore", "Created:".green());
208
209        Ok(())
210    }
211}