1use pyo3::prelude::*;
2use pyo3::types::PyDict;
3use std::path::PathBuf;
4
5use crate::config::ProjectConfig;
6
7mod config;
8mod engine;
9
10macro_rules! extract_config {
12 ($dict:expr, $key:literal, required) => {{
14 if let Some(value) = $dict.get_item($key)? {
15 value.extract()?
16 } else {
17 return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(concat!(
18 $key,
19 " is required"
20 )));
21 }
22 }};
23
24 ($dict:expr, $key:literal, $default:expr) => {{
26 if let Some(value) = $dict.get_item($key)? {
27 value.extract()?
28 } else {
29 $default
30 }
31 }};
32}
33
34#[pyfunction]
45fn get_crate_version() -> String {
46 env!("CARGO_PKG_VERSION").to_string()
47}
48
49#[pyfunction]
52fn generate_project_from_static_branch(config_dict: &Bound<'_, PyDict>) -> PyResult<bool> {
53 let project_name: String = extract_config!(config_dict, "project_name", required);
55 let destination: String = extract_config!(config_dict, "destination", ".".to_string());
56 let destination_path = PathBuf::from(destination);
57
58 let author_name: String = extract_config!(config_dict, "author_name", "Test User".to_string());
60 let author_email: String =
61 extract_config!(config_dict, "author_email", "test@example.com".to_string());
62
63 let db_name: Option<String> = extract_config!(
64 config_dict,
65 "db_name",
66 Some(project_name.to_lowercase().replace('-', "_"))
67 );
68
69 let db_owner_admin: Option<String> = extract_config!(
70 config_dict,
71 "db_owner_admin",
72 Some(format!(
73 "{}_owner",
74 project_name.to_lowercase().replace('-', "_")
75 ))
76 );
77
78 let db_owner_pword: Option<String> =
79 extract_config!(config_dict, "db_owner_pword", Some("password".to_string()));
80
81 let include_server: bool = extract_config!(config_dict, "include_server", true);
82 let include_frontend: bool = extract_config!(config_dict, "include_frontend", true);
83 let include_tauri_desktop: bool = extract_config!(config_dict, "include_tauri_desktop", true);
84
85 let app_identifier: String = extract_config!(
86 config_dict,
87 "app_identifier",
88 format!(
89 "com.example.{}",
90 project_name.to_lowercase().replace('-', "")
91 )
92 );
93
94 let deno_package_name: String = extract_config!(
95 config_dict,
96 "deno_package_name",
97 "@test/gwa-project".to_string()
98 );
99
100 let project_config = ProjectConfig {
102 project_name: project_name.clone(),
103 author_name,
104 author_email,
105 app_identifier,
106 db_name,
107 db_owner_admin,
108 db_owner_pword,
109 include_server,
110 include_frontend,
111 include_tauri_desktop,
112 deno_package_name,
113 };
114
115 match engine::run(&project_config, &destination_path) {
117 Ok(_) => Ok(true),
118 Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
119 "Failed to generate project: {}",
120 e
121 ))),
122 }
123}
124
125#[pyfunction]
127fn run_engine(config_dict: &Bound<'_, PyDict>) -> PyResult<bool> {
128 let project_name: String = extract_config!(config_dict, "project_name", required);
130 let destination: String = extract_config!(config_dict, "destination", ".".to_string());
131 let destination_path = PathBuf::from(destination);
132
133 let author_name: String = extract_config!(config_dict, "author_name", "Test User".to_string());
135 let author_email: String =
136 extract_config!(config_dict, "author_email", "test@example.com".to_string());
137
138 let db_name: Option<String> = extract_config!(
139 config_dict,
140 "db_name",
141 Some(project_name.to_lowercase().replace('-', "_"))
142 );
143
144 let db_owner_admin: Option<String> = extract_config!(
145 config_dict,
146 "db_owner_admin",
147 Some(format!(
148 "{}_owner",
149 project_name.to_lowercase().replace('-', "_")
150 ))
151 );
152
153 let db_owner_pword: Option<String> =
154 extract_config!(config_dict, "db_owner_pword", Some("password".to_string()));
155
156 let include_server: bool = extract_config!(config_dict, "include_server", true);
157 let include_frontend: bool = extract_config!(config_dict, "include_frontend", true);
158 let include_tauri_desktop: bool = extract_config!(config_dict, "include_tauri_desktop", true);
159
160 let app_identifier: String = extract_config!(
161 config_dict,
162 "app_identifier",
163 format!(
164 "com.example.{}",
165 project_name.to_lowercase().replace('-', "")
166 )
167 );
168
169 let deno_package_name: String = extract_config!(
170 config_dict,
171 "deno_package_name",
172 "@test/gwa-project".to_string()
173 );
174
175 let project_config = ProjectConfig {
177 project_name: project_name.clone(),
178 author_name,
179 author_email,
180 app_identifier,
181 db_name,
182 db_owner_admin,
183 db_owner_pword,
184 include_server,
185 include_frontend,
186 include_tauri_desktop,
187 deno_package_name,
188 };
189
190 match engine::run(&project_config, &destination_path) {
192 Ok(_) => Ok(true),
193 Err(e) => Err(PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(format!(
194 "Failed to generate project with engine: {}",
195 e
196 ))),
197 }
198}
199
200#[pymodule]
204fn _core(m: &Bound<PyModule>) -> PyResult<()> {
205 m.add_function(wrap_pyfunction!(get_crate_version, m)?)?;
208 m.add_function(wrap_pyfunction!(generate_project_from_static_branch, m)?)?;
209 m.add_function(wrap_pyfunction!(run_engine, m)?)?;
210 Ok(())
211}