use super::RapidCommand;
use crate::{
cli::{current_directory, logo, rapid_logo, Config},
constants::BOLT_EMOJI,
tui::{clean_console, indent},
};
use clap::{arg, value_parser, ArgAction, ArgMatches, Command};
use colorful::{Color, Colorful};
use include_dir::{include_dir, Dir};
use requestty::{prompt_one, Question};
use std::{
fs::remove_dir_all,
path::PathBuf,
process::{exit, Command as StdCommand},
thread, time,
};
use spinach::Spinach;
static PROJECT_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates/server");
static REMIX_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates/remix");
pub struct New {}
impl RapidCommand for New {
fn cmd() -> clap::Command {
Command::new("new")
.about("Creates a new Rapid project at the current working directory!")
.arg(
arg!(
-remix --remix "Scaffolds a Remix Rapid project!"
)
.required(false)
.action(ArgAction::SetTrue)
.value_parser(value_parser!(PathBuf)),
)
.arg(
arg!(
-server --server "Scaffolds a server-side only Rapid project!"
)
.required(false)
.action(ArgAction::SetTrue)
.value_parser(value_parser!(PathBuf)),
)
}
fn execute(_: &Config, args: &ArgMatches) -> Result<(), crate::cli::CliError<'static>> {
println!("{}", logo());
parse_new_args(args);
Ok(())
}
}
pub fn parse_new_args(args: &ArgMatches) {
const NEW_ARGS: [&str; 2] = ["remix", "server"];
let current_working_directory = current_directory();
let mut did_find_match = false;
for arg in NEW_ARGS {
match args.get_one::<PathBuf>(arg) {
Some(val) => {
if val == &PathBuf::from("true") {
match arg {
"remix" => {
init_remix_template(current_working_directory);
did_find_match = true;
break;
}
"server" => {
init_server_template(current_working_directory, arg);
did_find_match = true;
break;
}
_ => {
println!(
"{}",
"No application type detected. Please use either --server or --remix".color(Color::Red)
);
break;
}
}
}
}
None => {
println!(
"{}",
"No application type detected. Please use either --server or --remix".color(Color::Red)
);
break;
}
}
}
if !did_find_match {
println!(
"{}",
"No application type detected. Please use either --server or --remix".color(Color::Red)
);
}
}
pub fn init_remix_template(current_working_directory: PathBuf) {
let project_name = prompt_one(
Question::input("project_name")
.message("What will your project be called?")
.default("my-app")
.build(),
)
.expect("Error: Could not scaffold project. Please try again!");
let project_name = project_name.as_string().unwrap();
if !project_name.chars().all(|x| x.is_alphanumeric() || x == '-' || x == '_') {
println!("Aborting...your project name may only contain alphanumeric characters along with '-' and '_'...");
exit(64);
}
let path = current_working_directory.join(project_name);
if path.exists() {
let force = prompt_one(
Question::confirm("force_delete")
.message("Your specified directory is not empty and has files currently in it, do you want to overwrite?")
.default(false)
.build(),
)
.expect("Error: Could not scaffold project. Please try again!");
match !force.as_bool().unwrap() {
true => {
exit(64);
}
false => {
remove_dir_all(&path).expect("Error: Could not scaffold project. The specified directory must be empty. Please try again!");
}
}
}
println!("{}", indent(1));
let loading = Spinach::new(format!("{}", "Initializing a new Rapid Remix application..".color(Color::LightCyan)));
StdCommand::new("sh")
.current_dir(current_directory())
.arg("-c")
.arg(format!("mkdir {}", project_name))
.spawn()
.unwrap()
.wait()
.expect("Error: Could not scaffold project. Please try again!");
StdCommand::new("sh")
.current_dir(current_directory().join(project_name))
.arg("-c")
.arg(format!("git init --quiet"))
.spawn()
.unwrap()
.wait()
.expect("Error: Could not scaffold project. Please try again!");
REMIX_DIR.extract(current_working_directory.join(project_name).clone()).unwrap();
StdCommand::new("sh")
.current_dir(current_directory().join(project_name))
.arg("-c")
.arg(format!("mv Cargo__toml Cargo.toml"))
.spawn()
.unwrap()
.wait()
.expect("Error: Could not scaffold project. Please try again!");
let timeout = time::Duration::from_millis(675);
thread::sleep(timeout);
loading.stop();
clean_console();
println!(
"\n\n{} {} {} {}",
format!("{}", rapid_logo()).bold(),
"Success".bg_blue().color(Color::White).bold(),
BOLT_EMOJI,
"Welcome to your new Rapid application with Remix!"
);
println!(
"{} {} {} {} {}",
"\n\n🚀".bold(),
"Next Steps".bg_blue().color(Color::White).bold(),
BOLT_EMOJI,
format!("\n\ncd {}", project_name).bold(),
"\nrapid run".bold()
);
}
pub fn init_server_template(current_working_directory: PathBuf, _: &str) {
let project_name = prompt_one(
Question::input("project_name")
.message("What will your project be called?")
.default("my-app")
.build(),
)
.expect("Error: Could not scaffold project. Please try again!");
let project_name = project_name.as_string().unwrap();
if !project_name.chars().all(|x| x.is_alphanumeric() || x == '-' || x == '_') {
println!("Aborting...your project name may only contain alphanumeric characters along with '-' and '_'...");
exit(64);
}
let path = current_working_directory.join(project_name);
if path.exists() {
let force = prompt_one(
Question::confirm("force_delete")
.message("Your specified directory is not empty and has files currently in it, do you want to overwrite?")
.default(false)
.build(),
)
.expect("Error: Could not scaffold project. Please try again!");
match !force.as_bool().unwrap() {
true => {
exit(64);
}
false => {
remove_dir_all(&path).expect("Error: Could not scaffold project. The specified directory must be empty. Please try again!");
}
}
}
println!("{}", indent(1));
let loading = Spinach::new(format!("{}", "Initializing a new Rapid Remix application..".color(Color::LightCyan)));
StdCommand::new("sh")
.current_dir(current_directory())
.arg("-c")
.arg(format!("cargo new {} --quiet", project_name))
.spawn()
.unwrap()
.wait()
.expect("Error: Could not scaffold project. Please try again!");
StdCommand::new("sh")
.current_dir(current_directory().join(project_name))
.arg("-c")
.arg("cargo add rapid-web rapid-web-codegen futures-util include_dir --quiet")
.spawn()
.unwrap()
.wait()
.expect("Error: Could not scaffold project. Please try again!");
remove_dir_all(current_working_directory.join(format!("{}/src", project_name))).unwrap();
PROJECT_DIR.extract(current_working_directory.join(project_name).clone()).unwrap();
let timeout = time::Duration::from_millis(675);
thread::sleep(timeout);
loading.stop();
clean_console();
println!(
"\n\n{} {} {} {}",
format!("{}", rapid_logo()).bold(),
"Success".bg_blue().color(Color::White).bold(),
BOLT_EMOJI,
"Welcome to your new rapid-web server application!"
);
println!(
"{} {} {} {} {}",
"\n\n🚀".bold(),
"Next Steps".bg_blue().color(Color::White).bold(),
BOLT_EMOJI,
format!("\n\ncd {}", project_name).bold(),
"\nrapid run".bold()
);
}