use std::{env::current_dir, path::Path, fs::create_dir_all, fmt};
use cnctd_dialogue::Dialog;
use colored::Colorize;
use serde::{Deserialize, Serialize};
use strum_macros::EnumIter;
use super::apps::{App, server::ServerApp, web::WebApp, desktop::DesktopApp};
#[derive(Debug, Deserialize, Serialize, Clone, EnumIter, Default, PartialEq)]
pub enum DirectoryFix {
#[default]
ChangeDirectory,
ChangeProjectName,
StartOver,
}
impl fmt::Display for DirectoryFix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let display_str = match self {
Self::ChangeDirectory => "Change directory",
Self::ChangeProjectName => "Change project name",
Self::StartOver => "Start over",
};
write!(f, "{}", display_str)
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ProjectScaffold {
pub name: String,
pub directory: String,
pub apps: Vec<App>,
}
impl ProjectScaffold {
pub fn new() -> Self {
Self {
name: String::new(),
directory: current_dir().unwrap().to_string_lossy().to_string(),
apps: Vec::new(),
}
}
pub fn set_name(&mut self) -> &mut Self {
let prompt = "Enter the project name";
let project_name = Dialog::input(prompt, Some("new_project".to_string()), None, None);
self.name = project_name;
self
}
pub fn set_project_dir(&mut self) -> &mut Self {
let prompt = "Enter the directory where you would like to build the project";
let dir = Dialog::input(prompt, Some(self.directory.clone()), None, None);
self.directory = dir;
self
}
pub fn get_app_settings(&mut self) -> &mut Self {
let prompt = "Which apps would you like to include?";
let app_selections = Dialog::multi_select::<App>(prompt, None, None, None);
let mut new_apps: Vec<App> = app_selections.iter().map(|app| {
match app {
App::Server(_) => App::Server(ServerApp::choose_server_options()),
App::Web(_) => App::Web(WebApp::choose_webapp_options()),
App::Desktop(_) => App::Desktop(DesktopApp::choose_desktop_options()),
}
}).collect();
if new_apps.iter().any(|app| matches!(app, App::Web(_) | App::Desktop(_))) {
new_apps.push(App::Web(WebApp::choose_webapp_options()));
}
self.apps.extend(new_apps);
self
}
pub async fn build(&mut self) -> anyhow::Result<()> {
println!("{}", "Starting build process".green());
println!("{}", "Creating project directory if it does not exist");
let dir = format!("{}/{}", &self.directory, &self.name.to_lowercase().replace(" ", "_").replace("-", "_"));
let path = Path::new(&dir);
if !path.exists() { create_dir_all(&path)? } else { self.fix_directory_issue().await }
let apps = self.apps.clone();
for app in apps {
match app {
App::Server(server_app) => {
server_app.build(self).await?;
},
App::Web(_web_app) => {
},
App::Desktop(_desktop_app) => {
},
}
}
Ok(())
}
#[async_recursion::async_recursion]
pub async fn fix_directory_issue(&mut self) {
println!("{}","Directory already exists".yellow());
let prompt = "How would you like to proceed?";
let selection = Dialog::select::<DirectoryFix>(prompt, None, None, None);
match selection {
DirectoryFix::ChangeDirectory => {
self
.set_project_dir()
.build()
.await
.unwrap();
},
DirectoryFix::ChangeProjectName => {
self
.set_name()
.build()
.await
.unwrap();
},
_ => {},
}
}
}