fluxor_cli/
lib.rs

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); // Debug print
52
53    // Use a regex to extract the version number
54    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); // Debug print
63
64    Ok(version.to_string())
65}
66
67// Fetch dependencies crate version if "latest" is specified
68pub 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    // Check if project directory already exists
81    if project_path.exists() {
82        eprintln!("Project directory already exists.");
83        return;
84    }
85
86    // Create project directory
87    fs::create_dir_all(&project_path).expect("Failed to create project directory");
88
89    // Fetch fluxor version if "latest" is specified
90    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    // create README.md
97    metadata::create_readme(project_path, &package_name);
98
99    // Create Cargo.toml specific for the example
100    let cargo_toml = match example {
101        // Hello World Examples
102        "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 Examples
106        "routes" => routes::routes_cargo_toml(&package_name, &fluxor_version),
107        "routes-project" => routes::routes_cargo_toml(&package_name, &fluxor_version),
108        // Assets Examples
109        "assets" => assets::assets_cargo_toml(&package_name, &fluxor_version),
110        // DotEnv Examples
111        "dotenv" => dotenv::dotenv_cargo_toml(&package_name, &fluxor_version),
112        "cans-template-engine" => cans::template_cargo_toml(&package_name, &fluxor_version),
113        // DB
114        "db-redis" => db::db_cargo_toml(&package_name, &fluxor_version),
115        // Fluxor Full Template Example
116        "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    // Create src directory under the project
131    let src_path = project_path.join("src");
132    fs::create_dir_all(&src_path).expect("Failed to create src directory");
133
134    // Create src folders and files based on the specified example
135    match example {
136        // Hello World Examples
137        "helloworld" => {
138            // metadata files
139            hello_world::config_metadata(&project_path);
140
141            // src/main.rs
142            hello_world::hello_world_main_rs(&src_path);
143        }
144        "helloworld-api" => {
145            // metadata files
146            hello_world::config_metadata(&project_path);
147
148            // src/main.rs
149            hello_world::hello_world_api_main_rs(&src_path);
150        }
151        "helloworld-api-server" => {
152            // metadata files
153            hello_world::config_metadata(&project_path);
154
155            // src/server.rs
156            hello_world::hello_world_api_server_rs(&src_path);
157        }
158        // Routes Examples
159        "routes" => {
160            // metadata files
161            routes::config_metadata(&project_path);
162
163            // src/main.rs
164            routes::routes_main_rs(&src_path);
165        }
166        "routes-project" => {
167            // metadata files
168            routes::config_metadata(&project_path);
169
170            // src
171            // src/main.rs
172            routes::routes_project_main_rs(&package_name, &src_path);
173            // src/lib.rs
174            routes::routes_project_lib_rs(&src_path);
175
176            // src/routes
177            // Create routes directory under the src folder
178            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            // src/routes/mod.rs
181            routes::routes_project_routes_mod_rs(&src_routes_path);
182            
183            // src/routes/api
184            // Create routes/api directory under the src folder
185            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            // src/routes/api/mod.rs
188            routes::routes_project_routes_api_mod_rs(&src_routes_api_path);
189            // src/routes/api/msg.rs
190            routes::routes_project_routes_api_msg_rs(&src_routes_api_path);
191            // src/routes/api/dynamic_route.rs
192            routes::routes_project_routes_api_dynamic_route_rs(&src_routes_api_path);
193
194            // src/routes/pages
195            // Create routes/pages directory under the src folder
196            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            // src/routes/pages/mod.rs
199            routes::routes_project_routes_pages_mod_rs(&src_routes_pages_path);
200            // src/routes/pages/home.rs
201            routes::routes_project_routes_pages_home_rs(&src_routes_pages_path);
202            // src/routes/pages/about.rs
203            routes::routes_project_routes_pages_about_rs(&src_routes_pages_path);
204        }
205        // Assets Examples
206        "assets" => {
207            // metadata files
208            assets::config_metadata(&project_path);
209
210            // main.rs
211            assets::assets_main_rs(&src_path);
212
213            // assets
214            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 Examples
227        "dotenv" => {
228            // metadata files
229            dotenv::config_metadata(&project_path);
230
231            // main.rs
232            dotenv::dotenv_main_rs(&src_path);
233        }
234        // Cans:
235        // Template Examples
236        "cans-template-engine" => {
237            // metadata files
238            cans::config_metadata(&project_path);
239
240            // main.rs
241            cans::template_main_rs(&src_path);
242        }
243        // DB
244        // REDIS DB
245        "db-redis" => {
246            // metadata files
247            db::config_redis_metadata(&project_path);
248
249            // main.rs
250            db::db_redis_main_rs(&src_path);
251        }
252        // Fluxor
253        // Full Fluxor Template Example
254        "fluxor-template" => {
255            // paths
256            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            // metadata files
272            fluxor::config_metadata(&project_path);
273
274            // src
275
276            // src/main.rs
277            fluxor::fluxor_template_main_rs(&package_name, &src_path);
278            // src/lib.rs
279            fluxor::fluxor_template_lib_rs(&src_path);
280
281            // src/assets
282
283            // src/assets/images
284            fs::create_dir_all(assets_path.join("images")).expect("Failed to create assets/images directory");
285            // src/assets/css
286            fs::create_dir_all(assets_path.join("css")).expect("Failed to create assets/css directory");
287            // src/assets/js
288            fs::create_dir_all(assets_path.join("js")).expect("Failed to create assets/js directory");
289
290            // src/assets/manifest.json
291            fluxor::assets_manifest_json(&assets_path);
292            // src/assets/service-worker.js
293            fluxor::assets_service_worker_js(&assets_path);
294            // src/assets/images/logo.svg
295            fluxor::assets_images_logo_svg(&assets_images_path);
296            // src/assets/css/styles.css
297            fluxor::assets_css_styles_css(&assets_css_path);
298            // src/assets/js/alpine.min.js
299            fluxor::assets_js_alpine_min_js(&assets_js_path);
300
301            // src/components
302
303            // src/components/scripts
304            fs::create_dir_all(components_path.join("scripts")).expect("Failed to create components/scripts directory");
305
306            // src/components/scripts/mod.rs
307            fluxor::components_scripts_mod_rs(&components_scripts_path);
308            // src/components/scripts/sw_register.rs
309            fluxor::components_scripts_sw_register_rs(&components_scripts_path);
310            // src/components/badge.rs
311            fluxor::components_badge_rs(&components_path);
312            // src/components/footer.rs
313            fluxor::components_footer_rs(&components_path);
314            // src/components/head.rs
315            fluxor::components_head_rs(&components_path);
316            // src/components/header.rs
317            fluxor::components_header_rs(&components_path);
318            // src/components/layout.rs
319            fluxor::components_layout_rs(&components_path);
320            // src/components/logo.rs
321            fluxor::components_logo_rs(&components_path);
322            // src/components/mod.rs
323            fluxor::components_mod_rs(&components_path);
324            // src/components/nav.rs
325            fluxor::components_nav_rs(&components_path);
326            // src/components/notfound.rs
327            fluxor::components_notfound_rs(&components_path);
328
329            // src/db
330
331            fs::create_dir_all(&db_path).expect("Failed to create src/db directory");
332
333            // src/db/mod.rs
334            fluxor::db_mod_rs(&db_path);
335
336            // src/ds
337
338            fs::create_dir_all(&ds_path).expect("Failed to create src/ds directory");
339
340            // src/ds/mod.rs
341            fluxor::ds_mod_rs(&ds_path);
342
343            // src/helpers
344
345            fs::create_dir_all(&helpers_path).expect("Failed to create src/helpers directory");
346
347            // src/helpers/mod.rs
348            fluxor::helpers_mod_rs(&helpers_path);
349
350            // src/routes
351
352            fs::create_dir_all(&routes_path).expect("Failed to create src/routes directory");
353            
354            // src/routes/pages
355            fs::create_dir_all(routes_path.join("pages")).expect("Failed to create routes/pages directory");
356            // src/routes/api
357            fs::create_dir_all(routes_path.join("api")).expect("Failed to create routes/api directory");
358            // src/routes/api/greeting
359            fs::create_dir_all(routes_path.join("api/greeting")).expect("Failed to create routes/api/greeting directory");
360
361            // src/routes/mod.rs
362            fluxor::routes_mod_rs(&routes_path);
363            // src/routes/api/mod.rs
364            fluxor::routes_api_mod_rs(&routes_api_path);
365            // src/routes/api/greeting/mod.rs
366            fluxor::routes_api_greeting_mod_rs(&routes_api_greeting_path);
367            // src/routes/pages/mod.rs
368            fluxor::routes_pages_mod_rs(&routes_pages_path);
369            // src/routes/pages/home.rs
370            fluxor::routes_pages_home_rs(&routes_pages_path);
371            // src/routes/pages/analytics.rs
372            fluxor::routes_pages_analytics_rs(&routes_pages_path);
373            
374            // src/validators
375
376            fs::create_dir_all(&validators_path).expect("Failed to create src/validators directory");
377
378            // src/validators/mod.rs
379            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}