1#![doc(html_logo_url = "https://github.com/dr-montasir/fluxor_cli/raw/HEAD/fluxor-icon-64x64.svg")]
2#![doc = r"<div align='center'><a href='https://github.com/dr-montasir/fluxor_cli' target='_blank'><img src='https://github.com/dr-montasir/fluxor_cli/raw/HEAD/fluxor-icon-64x64.svg' alt='Fluxor CLI' width='80' height='auto' /></a><br><br><a href='https://github.com/dr-montasir/fluxor_cli' target='_blank'>FLUXOR</a><br><br>Fluxor_cli is the command-line interface for the Fluxor web framework, enabling rapid project scaffolding and management for Rust applications focused on data science and computing.</div>"]
3
4pub mod utils;
5pub mod metadata;
6mod examples;
7
8pub use clap::Parser;
9use regex::Regex;
10use std::fs;
11use std::path::Path;
12use std::process::Command as ProcessCommand;
13
14use utils::*;
15use examples::*;
16
17#[derive(Parser, Debug)]
18#[clap(author, version, about, long_about = None)]
19pub struct Args {
20 #[clap(subcommand)]
21 pub command: Commands,
22}
23
24#[derive(Parser, Debug)]
25pub enum Commands {
26 New {
27 name: String,
28 #[clap(short, long, default_value = "latest")]
29 version: String,
30 #[clap(short, long, default_value = "helloworld")]
31 example: String,
32 },
33}
34
35pub fn fetch_latest_version(crate_name: &str) -> Result<String, Box<dyn std::error::Error>> {
36 let output = ProcessCommand::new("cargo")
37 .arg("search")
38 .arg(crate_name)
39 .output()?;
40
41 if !output.status.success() {
42 return Err(format!(
43 "Failed to fetch latest version of {}: {}",
44 crate_name,
45 String::from_utf8_lossy(&output.stderr)
46 )
47 .into());
48 }
49
50 let stdout = String::from_utf8_lossy(&output.stdout);
51 println!("Cargo search output: {}", stdout); let re = Regex::new(r#"(\d+\.\d+\.\d+)"#).unwrap();
55 let version = stdout
56 .lines()
57 .find(|line| line.contains(crate_name))
58 .and_then(|line| re.find(line))
59 .map(|version| version.as_str())
60 .ok_or_else(|| format!("Crate '{}' not found", crate_name))?;
61
62 println!("Parsed version: {}", version); Ok(version.to_string())
65}
66
67pub fn get_crate_version(version: &str, dep_crate_name: &str) -> String {
69 if version == "latest" {
70 fetch_latest_version(dep_crate_name).expect(&format!("Failed to fetch latest version of {}", dep_crate_name))
71 } else {
72 version.to_string()
73 }
74}
75
76pub fn create_fluxor_web_project(name: &str, version: &str, example: &str) {
77 let package_name = to_crate_name(name);
78 let project_path = Path::new(&package_name);
79
80 if project_path.exists() {
82 eprintln!("Project directory already exists.");
83 return;
84 }
85
86 fs::create_dir_all(&project_path).expect("Failed to create project directory");
88
89 let fluxor_version = if version == "latest" {
91 fetch_latest_version("fluxor").expect("Failed to fetch latest version of fluxor")
92 } else {
93 version.to_string()
94 };
95
96 metadata::create_readme(project_path, &package_name);
98
99 let cargo_toml = match example {
101 "helloworld" => hello_world::hello_world_cargo_toml(&package_name, &fluxor_version),
103 "helloworld-api" => hello_world::hello_world_cargo_toml(&package_name, &fluxor_version),
104 "helloworld-api-server" => hello_world::hello_world_api_server_cargo_toml(&package_name, &fluxor_version),
105 "routes" => routes::routes_cargo_toml(&package_name, &fluxor_version),
107 "routes-project" => routes::routes_cargo_toml(&package_name, &fluxor_version),
108 "assets" => assets::assets_cargo_toml(&package_name, &fluxor_version),
110 "dotenv" => dotenv::dotenv_cargo_toml(&package_name, &fluxor_version),
112 "cans-template-engine" => cans::template_cargo_toml(&package_name, &fluxor_version),
113 "db-redis" => db::db_cargo_toml(&package_name, &fluxor_version),
115 "fluxor-template" => fluxor::fluxor_template_cargo_toml(
117 &package_name,
118 &get_crate_version("latest", "crator"),
119 &get_crate_version("latest", "fluxor")
120 ),
121 _ => {
122 eprintln!("Unknown example specified: {}", example);
123 return;
124 }
125 };
126
127 fs::write(project_path.join("Cargo.toml"), cargo_toml)
128 .expect("Failed to create Cargo.toml");
129
130 let src_path = project_path.join("src");
132 fs::create_dir_all(&src_path).expect("Failed to create src directory");
133
134 match example {
136 "helloworld" => {
138 hello_world::config_metadata(&project_path);
140
141 hello_world::hello_world_main_rs(&src_path);
143 }
144 "helloworld-api" => {
145 hello_world::config_metadata(&project_path);
147
148 hello_world::hello_world_api_main_rs(&src_path);
150 }
151 "helloworld-api-server" => {
152 hello_world::config_metadata(&project_path);
154
155 hello_world::hello_world_api_server_rs(&src_path);
157 }
158 "routes" => {
160 routes::config_metadata(&project_path);
162
163 routes::routes_main_rs(&src_path);
165 }
166 "routes-project" => {
167 routes::config_metadata(&project_path);
169
170 routes::routes_project_main_rs(&package_name, &src_path);
173 routes::routes_project_lib_rs(&src_path);
175
176 let src_routes_path = project_path.join("src/routes");
179 fs::create_dir_all(&src_routes_path).expect("Failed to create src/routes directory");
180 routes::routes_project_routes_mod_rs(&src_routes_path);
182
183 let src_routes_api_path = project_path.join("src/routes/api");
186 fs::create_dir_all(&src_routes_api_path).expect("Failed to create src/routes/api directory");
187 routes::routes_project_routes_api_mod_rs(&src_routes_api_path);
189 routes::routes_project_routes_api_msg_rs(&src_routes_api_path);
191 routes::routes_project_routes_api_dynamic_route_rs(&src_routes_api_path);
193
194 let src_routes_pages_path = project_path.join("src/routes/pages");
197 fs::create_dir_all(&src_routes_pages_path).expect("Failed to create src/routes/pages directory");
198 routes::routes_project_routes_pages_mod_rs(&src_routes_pages_path);
200 routes::routes_project_routes_pages_home_rs(&src_routes_pages_path);
202 routes::routes_project_routes_pages_about_rs(&src_routes_pages_path);
204 }
205 "assets" => {
207 assets::config_metadata(&project_path);
209
210 assets::assets_main_rs(&src_path);
212
213 let assets_img_path = project_path.join("assets/img");
215 let assets_css_path = project_path.join("assets/css");
216 let assets_js_path = project_path.join("assets/js");
217
218 fs::create_dir_all(&assets_img_path).expect("Failed to create sassets/img directory");
219 fs::create_dir_all(&assets_css_path).expect("Failed to create sassets/css directory");
220 fs::create_dir_all(&assets_js_path).expect("Failed to create sassets/js directory");
221
222 assets::assets_img_fluxor_svg(&assets_img_path);
223 assets::assets_css_styels_css(&assets_css_path);
224 assets::assets_js_script_js(&assets_js_path);
225 }
226 "dotenv" => {
228 dotenv::config_metadata(&project_path);
230
231 dotenv::dotenv_main_rs(&src_path);
233 }
234 "cans-template-engine" => {
237 cans::config_metadata(&project_path);
239
240 cans::template_main_rs(&src_path);
242 }
243 "db-redis" => {
246 db::config_redis_metadata(&project_path);
248
249 db::db_redis_main_rs(&src_path);
251 }
252 "fluxor-template" => {
255 let assets_path = project_path.join("src/assets");
257 let assets_images_path = project_path.join("src/assets/images");
258 let assets_css_path = project_path.join("src/assets/css");
259 let assets_js_path = project_path.join("src/assets/js");
260 let components_path = project_path.join("src/components");
261 let components_scripts_path = project_path.join("src/components/scripts");
262 let db_path = project_path.join("src/db");
263 let ds_path = project_path.join("src/ds");
264 let helpers_path = project_path.join("src/helpers");
265 let routes_path = project_path.join("src/routes");
266 let routes_api_path = project_path.join("src/routes/api");
267 let routes_api_greeting_path = project_path.join("src/routes/api/greeting");
268 let routes_pages_path = project_path.join("src/routes/pages");
269 let validators_path = project_path.join("src/validators");
270
271 fluxor::config_metadata(&project_path);
273
274 fluxor::fluxor_template_main_rs(&package_name, &src_path);
278 fluxor::fluxor_template_lib_rs(&src_path);
280
281 fs::create_dir_all(assets_path.join("images")).expect("Failed to create assets/images directory");
285 fs::create_dir_all(assets_path.join("css")).expect("Failed to create assets/css directory");
287 fs::create_dir_all(assets_path.join("js")).expect("Failed to create assets/js directory");
289
290 fluxor::assets_manifest_json(&assets_path);
292 fluxor::assets_service_worker_js(&assets_path);
294 fluxor::assets_images_logo_svg(&assets_images_path);
296 fluxor::assets_css_styles_css(&assets_css_path);
298 fluxor::assets_js_alpine_min_js(&assets_js_path);
300
301 fs::create_dir_all(components_path.join("scripts")).expect("Failed to create components/scripts directory");
305
306 fluxor::components_scripts_mod_rs(&components_scripts_path);
308 fluxor::components_scripts_sw_register_rs(&components_scripts_path);
310 fluxor::components_badge_rs(&components_path);
312 fluxor::components_footer_rs(&components_path);
314 fluxor::components_head_rs(&components_path);
316 fluxor::components_header_rs(&components_path);
318 fluxor::components_layout_rs(&components_path);
320 fluxor::components_logo_rs(&components_path);
322 fluxor::components_mod_rs(&components_path);
324 fluxor::components_nav_rs(&components_path);
326 fluxor::components_notfound_rs(&components_path);
328
329 fs::create_dir_all(&db_path).expect("Failed to create src/db directory");
332
333 fluxor::db_mod_rs(&db_path);
335
336 fs::create_dir_all(&ds_path).expect("Failed to create src/ds directory");
339
340 fluxor::ds_mod_rs(&ds_path);
342
343 fs::create_dir_all(&helpers_path).expect("Failed to create src/helpers directory");
346
347 fluxor::helpers_mod_rs(&helpers_path);
349
350 fs::create_dir_all(&routes_path).expect("Failed to create src/routes directory");
353
354 fs::create_dir_all(routes_path.join("pages")).expect("Failed to create routes/pages directory");
356 fs::create_dir_all(routes_path.join("api")).expect("Failed to create routes/api directory");
358 fs::create_dir_all(routes_path.join("api/greeting")).expect("Failed to create routes/api/greeting directory");
360
361 fluxor::routes_mod_rs(&routes_path);
363 fluxor::routes_api_mod_rs(&routes_api_path);
365 fluxor::routes_api_greeting_mod_rs(&routes_api_greeting_path);
367 fluxor::routes_pages_mod_rs(&routes_pages_path);
369 fluxor::routes_pages_home_rs(&routes_pages_path);
371 fluxor::routes_pages_analytics_rs(&routes_pages_path);
373
374 fs::create_dir_all(&validators_path).expect("Failed to create src/validators directory");
377
378 fluxor::validators_mod_rs(&validators_path);
380 }
381 _ => {
382 eprintln!("Unknown example specified: {}", example);
383 return;
384 }
385 }
386
387 println!("Fluxor project '{}' created successfully using the '{}' example.", package_name, example);
388}