1pub mod hello_world;
2
3pub use clap::Parser;
4use regex::Regex;
5use std::fs;
6use std::path::Path;
7use std::process::Command as ProcessCommand;
8
9#[derive(Parser, Debug)]
10#[clap(author, version, about, long_about = None)]
11pub struct Args {
12 #[clap(subcommand)]
13 pub command: Commands,
14}
15
16#[derive(Parser, Debug)]
17pub enum Commands {
18 New {
19 name: String,
20 #[clap(short, long, default_value = "latest")]
21 version: String,
22 #[clap(short, long, default_value = "helloworld")]
23 example: String,
24 },
25}
26
27pub fn fetch_latest_version(crate_name: &str) -> Result<String, Box<dyn std::error::Error>> {
28 let output = ProcessCommand::new("cargo")
29 .arg("search")
30 .arg(crate_name)
31 .output()?;
32
33 if !output.status.success() {
34 return Err(format!(
35 "Failed to fetch latest version of {}: {}",
36 crate_name,
37 String::from_utf8_lossy(&output.stderr)
38 )
39 .into());
40 }
41
42 let stdout = String::from_utf8_lossy(&output.stdout);
43 println!("Cargo search output: {}", stdout); let re = Regex::new(r#"(\d+\.\d+\.\d+)"#).unwrap();
47 let version = stdout
48 .lines()
49 .find(|line| line.contains(crate_name))
50 .and_then(|line| re.find(line))
51 .map(|version| version.as_str())
52 .ok_or_else(|| format!("Crate '{}' not found", crate_name))?;
53
54 println!("Parsed version: {}", version); Ok(version.to_string())
57}
58
59pub fn create_fluxor_web_project(name: &str, version: &str, example: &str) {
60 let project_path = Path::new(name);
61
62 if project_path.exists() {
64 eprintln!("Project directory already exists.");
65 return;
66 }
67
68 fs::create_dir_all(&project_path).expect("Failed to create project directory");
70
71 let fluxor_version = if version == "latest" {
73 fetch_latest_version("fluxor").expect("Failed to fetch latest version of fluxor")
74 } else {
75 version.to_string()
76 };
77
78 let gitignore = r#"/target
80 "#;
81
82 fs::write(project_path.join(".gitignore"), gitignore)
83 .expect("Failed to create .gitignore");
84
85 let readme = format!(r#"# {}
87
88This project has been initialized with the assistance of the [Fluxor CLI](https://crates.io/crates/fluxor_cli), a command-line tool that allows developers to quickly and efficiently create project starters for the [Fluxor web framework](https://crates.io/crates/fluxor)."
89"#, name);
90
91 fs::write(project_path.join("README.md"), readme)
92 .expect("Failed to create readme file");
93
94 let cargo_toml = match example {
96 "helloworld" => hello_world::hello_world_cargo_toml(name, &fluxor_version),
98 "helloworld-api" => hello_world::hello_world_cargo_toml(name, &fluxor_version),
99 "helloworld-api-server" => hello_world::hello_world_api_server_cargo_toml(name, &fluxor_version),
100 _ => {
101 eprintln!("Unknown example specified: {}", example);
102 return;
103 }
104 };
105
106 fs::write(project_path.join("Cargo.toml"), cargo_toml)
107 .expect("Failed to create Cargo.toml");
108
109 let src_path = project_path.join("src");
111 fs::create_dir_all(&src_path).expect("Failed to create src directory");
112
113 match example {
115 "helloworld" => {
116 hello_world::hello_world_template(&src_path);
117 }
118 "helloworld-api" => {
119 hello_world::hello_world_api_template(&src_path);
120 }
121 "helloworld-api-server" => {
122 hello_world::hello_world_api_server_template(&src_path);
123 }
124 _ => {
125 eprintln!("Unknown example specified: {}", example);
126 return;
127 }
128 }
129
130 println!("Fluxor project '{}' created successfully using the '{}' example.", name, example);
131}