rapid_cli/commands/
init.rs1use super::RapidCommand;
2use crate::{
3 cli::{current_directory, Config},
4 constants::BOLT_EMOJI,
5 tui::logo,
6};
7use clap::{arg, value_parser, ArgAction, ArgMatches, Command};
8use colorful::{Color, Colorful};
9use rust_embed::RustEmbed;
10use log::{error, info};
11use std::{
12 fs::{write, File},
13 path::PathBuf,
14};
15
16#[derive(RustEmbed)]
17#[folder = "templates/rapidUI/reactVite/"]
18struct Asset;
19
20#[derive(RustEmbed)]
21#[folder = "templates/rapidUI/remix/"]
22struct RemixAssets;
23
24#[derive(RustEmbed)]
25#[folder = "templates/rapidUI/nextjs/"]
26struct NextJsAssets;
27
28#[derive(RustEmbed)]
29#[folder = "templates/dockerfiles/"]
30struct Dockerfiles;
31
32pub struct Init {}
33
34impl RapidCommand for Init {
35 fn cmd() -> clap::Command {
36 Command::new("init")
37 .about("A command for initializing Rapid libraries in your projects!")
38 .subcommand(Command::new("fullstack").about("A command for initializing a fullstack rapid application in your react projects!"))
39 .subcommand(
40 Command::new("server")
41 .about("A command for initializing functionality inside of a rapid server")
42 .arg(
43 arg!(
44 -deploy --deploy "Initializes functionality inside of an existing rapid server application"
45 )
46 .required(false)
47 .action(ArgAction::SetTrue)
48 .value_parser(value_parser!(PathBuf)),
49 ),
50 )
51 .subcommand(
52 Command::new("ui")
53 .about("A command for initializing Rapid-UI in your react projects!")
54 .arg(
55 arg!(
56 -vite --vite "Initializes rapid-ui in your React + Vitejs project!"
57 )
58 .required(false)
59 .action(ArgAction::SetTrue)
60 .value_parser(value_parser!(PathBuf)),
61 )
62 .arg(
63 arg!(
64 -remix --remix "Initializes rapid-ui in your Remix.run application!"
65 )
66 .required(false)
67 .action(ArgAction::SetTrue)
68 .value_parser(value_parser!(PathBuf)),
69 )
70 .arg(
71 arg!(
72 -nextjs --nextjs "Initializes rapid-ui in your Nextjs application!"
73 )
74 .required(false)
75 .action(ArgAction::SetTrue)
76 .value_parser(value_parser!(PathBuf)),
77 ),
78 )
79 }
80
81 fn execute(_: &Config, args: &ArgMatches) -> Result<(), crate::cli::CliError<'static>> {
82 println!("{}", logo());
83 parse_init_args(args);
84 Ok(())
85 }
86}
87
88pub fn ui_subcommand_handler(init_args: [&str; 3], subcommand_args: &ArgMatches, current_working_directory: PathBuf) {
89 for ui_arg in init_args {
90 match subcommand_args.get_one::<PathBuf>(ui_arg) {
91 Some(val) => {
92 if val == &PathBuf::from("true") {
93 match ui_arg {
94 "vite" => {
95 init_vite_template(current_working_directory, ui_arg);
96 break;
97 }
98 "remix" => {
99 init_remix_template(current_working_directory, ui_arg);
100 break;
101 }
102 "nextjs" => {
103 init_nextjs_template(current_working_directory, ui_arg);
104 break;
105 }
106 _ => {
107 error!("{}", "no template found. Please try '--vite' or '--remix'".color(Color::Red));
108 break;
109 }
110 }
111 }
112 }
113 None => {
114 error!("{}", "no template found. Please try '--vite' or '--remix'".color(Color::Red));
115 }
116 }
117 }
118}
119
120pub fn server_subcommand_handler(init_args: [&str; 1], subcommand_args: &ArgMatches, current_working_directory: PathBuf) {
121 for server_arg in init_args {
122 match subcommand_args.get_one::<PathBuf>(server_arg) {
123 Some(val) => {
124 if val == &PathBuf::from("true") {
125 match server_arg {
126 "deploy" => {
127 init_deployments_dockerfile(current_working_directory);
128 return;
129 }
130 _ => {
131 error!("{}", "no command found. Please try '--deploy'".color(Color::Red));
132 return;
133 }
134 }
135 }
136 }
137 None => {
138 error!("{}", "no command found. Please try '--deploy'".color(Color::Red));
139 }
140 }
141 }
142
143 error!("{}", "no init commands found! Please try using '--deploy'".color(Color::Red));
144}
145
146fn parse_init_args(args: &ArgMatches) {
147 const UI_INIT_ARGS: [&str; 3] = ["vite", "remix", "nextjs"];
149 const SERVER_INIT_ARGS: [&str; 1] = ["deploy"];
150 const INIT_COMMANDS: [&str; 3] = ["ui", "fullstack", "server"];
151 let current_working_directory = current_directory();
153 for arg in INIT_COMMANDS {
154 match args.subcommand() {
155 Some((name, subcommand_args)) => {
156 match name {
157 "ui" => {
158 ui_subcommand_handler(UI_INIT_ARGS, subcommand_args, current_working_directory);
159 return;
160 }
161 "server" => {
162 server_subcommand_handler(SERVER_INIT_ARGS, subcommand_args, current_working_directory);
163 return;
164 }
165 "fullstack" => {
166 error!("coming soon...");
168 return;
169 }
170 _ => {
171 error!("no init scripts found for `{}`", arg);
172 break;
173 }
174 }
175 }
176 None => {} }
178 }
179
180 error!("no init scripts found");
181}
182
183pub fn init_vite_template(current_working_directory: PathBuf, arg: &str) {
184 info!("Initializing rapid-ui with the template: {:?}...", arg);
185 let tailwind_config_contents = Asset::get("tailwind.config.js").unwrap();
186 let postcss_config_contents = Asset::get("postcss.config.js").unwrap();
187 let index_css_contents = Asset::get("index.css").unwrap();
188 File::create(current_working_directory.join("tailwind.config.js")).expect("Failed to create a tailwind config file. Please try again!");
190 File::create(current_working_directory.join("postcss.config.js")).expect("Failed to create a postcss config file. Please try again!");
191 File::create(current_working_directory.join("src/index.css")).expect("Failed to create the css entrypoint file. Please try again!");
192 write("tailwind.config.js", std::str::from_utf8(tailwind_config_contents.data.as_ref()).unwrap())
194 .expect("Could not write to tailwind config file!");
195 write("postcss.config.js", std::str::from_utf8(postcss_config_contents.data.as_ref()).unwrap()).expect("Could not write to postcss config file!");
196 write("src/index.css", std::str::from_utf8(index_css_contents.data.as_ref()).unwrap()).expect("Could not write to index.css file!");
197
198 info!(
199 "{} rapid-ui has been initialized in your Vite project!",
200 BOLT_EMOJI,
201 );
202}
203
204pub fn init_remix_template(current_working_directory: PathBuf, arg: &str) {
205 info!("initializing rapid-ui with the template {:?}...", arg);
206 let tailwind_config_contents = RemixAssets::get("tailwind.config.ts").unwrap();
207 let index_css_contents = RemixAssets::get("index.css").unwrap();
208 File::create(current_working_directory.join("tailwind.config.ts")).expect("Failed to create a tailwind config file. Please try again!");
210 File::create(current_working_directory.join("app/index.css")).expect("Failed to create the css entrypoint file. Please try again!");
211 write("tailwind.config.ts", std::str::from_utf8(tailwind_config_contents.data.as_ref()).unwrap())
213 .expect("Could not write to tailwind config file!");
214 write("app/index.css", std::str::from_utf8(index_css_contents.data.as_ref()).unwrap()).expect("Could not write to index.css file!");
215
216 info!(
217 "{} rapid-ui has been initialized in your Remix project!",
218 BOLT_EMOJI,
219 );
220}
221
222pub fn init_nextjs_template(current_working_directory: PathBuf, arg: &str) {
223 info!("initializing rapid-ui with the template {:?}...", arg);
224 let tailwind_config_contents = NextJsAssets::get("tailwind.config.ts").unwrap();
225 let postcss_config_contents = NextJsAssets::get("postcss.config.js").unwrap();
226
227 File::create(current_working_directory.join("tailwind.config.ts")).expect("Failed to create a tailwind config file. Please try again!");
229 write("postcss.config.js", std::str::from_utf8(postcss_config_contents.data.as_ref()).unwrap()).expect("Could not write to postcss config file!");
231 write("tailwind.config.ts", std::str::from_utf8(tailwind_config_contents.data.as_ref()).unwrap())
233 .expect("Could not write to tailwind config file!");
234
235 info!(
236 "{} rapid-ui has been initialized in your NextJS project!",
237 BOLT_EMOJI,
238 );
239}
240
241pub fn init_deployments_dockerfile(current_working_directory: PathBuf) {
242 info!("Initializing rapid deployments...");
243 let dockerfile_conents = Dockerfiles::get("rapidServer.Dockerfile").unwrap();
244
245 File::create(current_working_directory.join("rapid.Dockerfile"))
247 .expect("Failed to create the depoyment Dockerfile. Is there already a dockerfile created with the name 'rapid.Dockerfile'?");
248
249 write("rapid.Dockerfile", std::str::from_utf8(dockerfile_conents.data.as_ref()).unwrap()).expect("Could not write to postcss config file!");
251
252 info!(
253 "{}\n{}{}\n{}{}",
254 BOLT_EMOJI,
255 "Build: ".bold(),
256 "docker build -t rapid-server -f ./rapid.Dockerfile .".color(Color::LightCyan),
257 "Run: ".bold(),
258 "docker run -p 8080:8080 rapid-server".color(Color::LightCyan),
259 );
260}