use super::RapidCommand;
use crate::{
cli::{current_directory, logo, rapid_logo, Config},
rapid_config::config::{find_rapid_config, is_rapid, AppType, RapidConfig},
};
use clap::{arg, value_parser, ArgAction, ArgMatches, Command};
use spinach::Spinach;
use std::{path::PathBuf, process::Command as StdCommand, str::FromStr};
pub struct Run {}
impl RapidCommand for Run {
fn cmd() -> clap::Command {
Command::new("run")
.about("A command for running various rapid applications")
.arg(
arg!(
-server --server "Runs a rapid server application"
)
.required(false)
.action(ArgAction::SetTrue)
.value_parser(value_parser!(PathBuf)),
)
.arg(
arg!(
-app --app "Runs a rapid fullstack application"
)
.required(false)
.action(ArgAction::SetTrue)
.value_parser(value_parser!(PathBuf)),
)
}
fn execute(_: &Config, args: &ArgMatches) -> Result<(), crate::cli::CliError<'static>> {
ctrlc::set_handler(move || {
std::process::exit(0);
})
.expect("Error: Could not stop process");
println!("{}", logo());
parse_run_args(args).unwrap();
Ok(())
}
}
pub fn get_server_port(config: &RapidConfig, fallback_port: u16) -> u16 {
let app_type = &config.app_type;
match app_type.as_str() {
"server" => match &config.server {
Some(val) => match val.port {
Some(p) => p,
None => fallback_port
},
_ => fallback_port
}
"remix" => match &config.remix {
Some(val) => match val.server_port {
Some(s_port) => s_port,
None => fallback_port
},
_ => fallback_port
}
_ => fallback_port
}
}
fn parse_run_args(args: &ArgMatches) -> Result<(), ()> {
let rapid_config = find_rapid_config();
let server_port = get_server_port(&rapid_config, 8080);
if !is_rapid() {
eprintln!("Could not find a valid config file in the current working directory. Please make sure you are in a official rapid project before running this command.");
std::process::exit(64);
}
const RUN_ARGS: [&str; 3] = ["server", "remix", "app"];
for arg in RUN_ARGS {
match args.get_one::<PathBuf>(arg) {
Some(val) => {
if val == &PathBuf::from("true") {
match arg {
"server" => {
handle_run_server(server_port, rapid_config.app_type);
return Ok(());
},
"remix" => {
handle_run_server(server_port, rapid_config.app_type);
return Ok(());
}
"app" => {
println!("Coming soon!");
return Ok(());
}
_ => {
println!("{} {}", "No application found for the type: ", arg);
return Ok(());
}
}
}
}
None => break
}
}
let application_type = AppType::from_str(&rapid_config.app_type).expect("Error: invalid rapid application type!");
match application_type {
AppType::App => {
println!("Coming soon...");
}
AppType::Server => {
handle_run_server(server_port, rapid_config.app_type);
return Ok(());
}
AppType::Remix => {
handle_run_server(server_port, rapid_config.app_type);
return Ok(());
}
}
Ok(())
}
fn handle_run_server(server_port: u16, app_type: String) {
let install_list = StdCommand::new("sh")
.arg("-c")
.arg("cargo install --list")
.output()
.expect("Could not complete pre-run checks.");
let mut hot_reload_command = format!(
"systemfd --no-pid --quiet -s http::{} -- cargo watch -x run -q --ignore 'bindings.ts'",
server_port
);
if app_type == String::from("remix") {
hot_reload_command = String::from("systemfd --no-pid --quiet -s http::8080 -- cargo watch -x run -w app/api -q --ignore 'bindings.ts'");
}
if !std::str::from_utf8(&install_list.stdout).unwrap().contains("cargo-watch")
|| !std::str::from_utf8(&install_list.stdout).unwrap().contains("systemfd")
{
let s = Spinach::new("Installing build scripts...");
StdCommand::new("sh")
.arg("-c")
.arg("cargo install cargo-watch")
.output()
.expect("Could not install rapid dev server binaries. Please try again.");
StdCommand::new("sh")
.arg("-c")
.arg("cargo install systemfd")
.output()
.expect("Could not install rapid dev server binaries. Please try again.");
s.succeed("Rapid build scripts installed!");
}
println!("{} Building rapid application...", rapid_logo());
StdCommand::new("sh")
.current_dir(current_directory())
.arg("-c")
.arg(hot_reload_command)
.spawn()
.unwrap()
.wait()
.expect("Error: Could not run development server. Please try again!");
}