diff --git a/Cargo.lock b/Cargo.lock index 87b1dbe..6e31451 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -488,6 +488,8 @@ dependencies = [ "convert_case", "dialoguer", "exitcode", + "include_dir", + "lazy_static", "ramhorns", "serde", "tracing", @@ -1300,6 +1302,25 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "1.9.3" diff --git a/crates/Cargo.lock b/crates/Cargo.lock index 476c6c2..0bedd55 100644 --- a/crates/Cargo.lock +++ b/crates/Cargo.lock @@ -472,6 +472,8 @@ dependencies = [ "convert_case", "dialoguer", "exitcode", + "include_dir", + "lazy_static", "ramhorns", "serde", "tracing", @@ -1196,6 +1198,25 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "1.9.3" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 35082cc..31ff200 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -46,11 +46,13 @@ dialoguer = "0.10" serde = "1.0" anyhow = "1" console = "^0.15.0" +lazy_static = "1" ramhorns = "1" exitcode = "^1.1.2" tracing = "^0.1.34" tracing-tree = { version = "0.2.1" } tracing-subscriber = { version = "0.3.1", features = ["env-filter"] } +include_dir = "0.7.4" [features] diff --git a/crates/cli/src/bin/cmd/new.rs b/crates/cli/src/bin/cmd/new.rs index a16c6ff..d77a9f2 100644 --- a/crates/cli/src/bin/cmd/new.rs +++ b/crates/cli/src/bin/cmd/new.rs @@ -1,5 +1,17 @@ use anyhow::Result; use clap::{Arg, ArgMatches, Command}; +use convert_case::Casing; +use include_dir::Dir; +use lazy_static::lazy_static; + +lazy_static! { + static ref TEMPLATES: Vec<&'static str> = vec!["basic", "ramhorns", "vercel"]; + static ref TEMPLATES_DIR: Vec> = vec![ + include_dir::include_dir!("./starter-templates/with-basic"), + include_dir::include_dir!("./starter-templates/with-ramhorns"), + include_dir::include_dir!("./starter-templates/with-vercel") + ]; +} /// `ngyn new` command /// @@ -38,21 +50,56 @@ pub fn command() -> Command { ) } -pub fn run(matches: &ArgMatches, subcommand_matches: &ArgMatches) -> Result { +pub fn run(_matches: &ArgMatches, subcommand_matches: &ArgMatches) -> Result { if let Some(name) = subcommand_matches.get_one::("name") { println!("Creating new project: {}", name); } else { let name = dialoguer::Input::::new() .with_prompt("Name of the project to create") .interact()?; - let force = dialoguer::Confirm::new() - .with_prompt("Force the creation of the project") - .default(false) - .interact()?; + let name = name.to_case(convert_case::Case::Snake); + let template = dialoguer::Select::new() - .with_prompt("Use a template to create the project") - .default(0) - .interact()?; + .with_prompt("Use a template to create the project") + .items(&TEMPLATES) + .default(0) + .interact()?; + + let cwd = std::env::current_dir()?; + let project_dir = cwd.join(&name); + + let force = if project_dir.exists() { + dialoguer::Confirm::new() + .with_prompt("Project directory already exists. Overwrite?") + .interact()? + } else { + true + }; + + if !force { + return Ok(cargo_ngyn::CmdExit { + code: exitcode::OK, + message: Some("Project directory already exists. Exiting...".to_string()), + }); + } + + // safely remove current project directory and create a new one + if project_dir.exists() { + std::fs::remove_dir_all(&project_dir)?; + } else { + std::fs::create_dir_all(&project_dir)?; + } + + let template_dir = &TEMPLATES_DIR[template]; + let template_files = template_dir.files(); + + for file in template_files { + let file_path = project_dir.join(file.path()); + let file_content = file.contents_utf8().unwrap(); + + std::fs::create_dir_all(file_path.parent().unwrap())?; + std::fs::write(file_path, file_content)?; + } } Ok(cargo_ngyn::CmdExit {