diff --git a/crates/tuono/src/lib.rs b/crates/tuono/src/lib.rs index cb259da4..ad0b9b3c 100644 --- a/crates/tuono/src/lib.rs +++ b/crates/tuono/src/lib.rs @@ -15,7 +15,14 @@ enum Actions { /// Build the production assets Build, /// Scaffold a new project - New { folder_name: Option }, + New { + /// The folder in which load the project. Default is the current directory. + folder_name: Option, + /// The template to use to scaffold the project. The template should match one of the tuono + /// examples + #[arg(short, long)] + template: Option, + }, } #[derive(Parser, Debug)] @@ -46,8 +53,11 @@ pub fn cli() -> std::io::Result<()> { let mut vite_build = Command::new("./node_modules/.bin/tuono-build-prod"); let _ = &vite_build.output()?; } - Actions::New { folder_name } => { - scaffold_project::create_new_project(folder_name); + Actions::New { + folder_name, + template, + } => { + scaffold_project::create_new_project(folder_name, template); } } diff --git a/crates/tuono/src/scaffold_project.rs b/crates/tuono/src/scaffold_project.rs index 2f72d92b..18e8537e 100644 --- a/crates/tuono/src/scaffold_project.rs +++ b/crates/tuono/src/scaffold_project.rs @@ -38,12 +38,11 @@ fn create_file(path: PathBuf, content: String) -> std::io::Result<()> { Ok(()) } -pub fn create_new_project(folder_name: Option) { +pub fn create_new_project(folder_name: Option, template: Option) { let folder = folder_name.unwrap_or(".".to_string()); - if folder != "." { - create_dir(&folder).unwrap(); - } + // In case of missing select the tuono example + let template = template.unwrap_or("tuono".to_string()); let client = blocking::Client::builder() .user_agent("") @@ -60,21 +59,25 @@ pub fn create_new_project(folder_name: Option) { let new_project_files = res .tree .iter() - .filter(|GithubFile { path, .. }| { - // TODO: Handle custom example download by CLI argument --template - if path.starts_with("examples/tuono/") { - return true; - } - false - }) + .filter(|GithubFile { path, .. }| path.starts_with(&format!("examples/{template}/"))) .collect::>(); + if new_project_files.is_empty() { + println!("Template not found: {template}"); + return; + } + + if folder != "." { + create_dir(&folder).unwrap(); + } + let folder_name = PathBuf::from(&folder); let current_dir = env::current_dir().expect("Failed to get current working directory"); let folder_path = current_dir.join(folder_name); - create_directories(&new_project_files, &folder_path).expect("Failed to create directories"); + create_directories(&new_project_files, &folder_path, &template) + .expect("Failed to create directories"); for GithubFile { element_type, path, .. @@ -88,7 +91,7 @@ pub fn create_new_project(folder_name: Option) { .text() .expect("Failed to parse the repo structure"); - let path = PathBuf::from(&path.replace("examples/tuono/", "")); + let path = PathBuf::from(&path.replace(&format!("examples/{template}/"), "")); let file_path = folder_path.join(&path); @@ -101,13 +104,17 @@ pub fn create_new_project(folder_name: Option) { outro(folder); } -fn create_directories(new_project_files: &Vec<&GithubFile>, folder_path: &Path) -> io::Result<()> { +fn create_directories( + new_project_files: &[&GithubFile], + folder_path: &Path, + template: &String, +) -> io::Result<()> { for GithubFile { element_type, path, .. } in new_project_files.iter() { if let GithubFileType::Tree = element_type { - let path = PathBuf::from(&path.replace("examples/tuono/", "")); + let path = PathBuf::from(&path.replace(&format!("examples/{template}/"), "")); let dir_path = folder_path.join(&path); create_dir(&dir_path).unwrap(); diff --git a/crates/tuono/src/source_builder.rs b/crates/tuono/src/source_builder.rs index 90b9ef37..fb5a43bb 100644 --- a/crates/tuono/src/source_builder.rs +++ b/crates/tuono/src/source_builder.rs @@ -54,6 +54,8 @@ async fn main() { .with_state(fetch); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); + + println!("\nDevelopment app ready at http://localhost:3000/"); axum::serve(listener, app).await.unwrap(); } @@ -240,7 +242,6 @@ pub fn bundle_axum_source() -> io::Result<()> { pub fn check_tuono_folder() -> io::Result<()> { let dev_folder = Path::new(DEV_FOLDER); if !&dev_folder.is_dir() { - println!("exists"); fs::create_dir(dev_folder)?; } diff --git a/crates/tuono/src/watch.rs b/crates/tuono/src/watch.rs index f3152fb8..72d3cfe0 100644 --- a/crates/tuono/src/watch.rs +++ b/crates/tuono/src/watch.rs @@ -54,7 +54,7 @@ pub async fn watch() -> Result<()> { run_server.start().await; - println!("\nDevelopment app ready at http://localhost:3000/"); + build_ssr_bundle.to_wait().await; let wx = Watchexec::new(move |mut action| { let mut should_reload = false; diff --git a/docs/tutorial.md b/docs/tutorial.md index ed951849..3b195b8e 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -4,23 +4,22 @@ This tutorial is meant for giving you a sneak peek of the framework and is inten The first part is about the project setup and the base knowledge needed to work with tuono. The actual tutorial starts at [Tutorial introduction](#tutorial-introduction). -> If you prefer to see directly the final outcome check out the [tutorial source](https://github.com/Valerioageno/tuono/tree/main/examples/tutorial). +> If you have already installed the tuono CLI you can download the tutorial source with `tuono new tuono-tutorial --template tutorial` ## Table of Content -* [Tuono tutorial](#tuono-tutorial) - * [Installation](#installation) - * [Project scaffold](#project-scaffold) - * [Start the dev environment](#start-the-dev-environment) - * [The “/” route](#the--route) - * [Tutorial introduction](#tutorial-introduction) - * [Fetch all the pokemons](#fetch-all-the-pokemons) - * [Create a stand-alone component](#create-a-stand-alone-component) - * [Create the /pokemons/[pokemon] route](#create-the-pokemonspokemon-route) - * [Error handling](#error-handling) - * [Conclusion](#conclusion) +* [CLI Installation](#cli-installation) +* [Project scaffold](#project-scaffold) +* [Start the dev environment](#start-the-dev-environment) +* [The “/” route](#the--route) +* [Tutorial introduction](#tutorial-introduction) +* [Fetch all the pokemons](#fetch-all-the-pokemons) +* [Create a stand-alone component](#create-a-stand-alone-component) +* [Create the /pokemons/[pokemon] route](#create-the-pokemonspokemon-route) +* [Error handling](#error-handling) +* [Conclusion](#conclusion) -## Installation +## CLI Installation The tuono CLI is hosted on [crates.io](https://crates.io/crates/tuono); to download and install it just run on a terminal: @@ -34,9 +33,11 @@ To check that is correctly installed run: $ tuono --version ``` +Run `tuono -h` to see all the available commands. + ## Project scaffold -To setup a new project you just need to run the following command: +To setup a new fresh project you just need to run the following command: ```bash $ tuono new tuono-tutorial diff --git a/examples/README.md b/examples/README.md index 47df30d4..94feec77 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,3 +7,13 @@ To simply scaffold the base project run in your terminal: ```shell $ tuono new [NAME] ``` + +You can install any example included in this folder by just using the `--template` flag: + +```shell +$ tuono new [NAME] --template [TEMPLATE] +``` + +`[TEMPLATE]` is the folder name. + + diff --git a/examples/tutorial/README.md b/examples/tutorial/README.md index 75fd2c7e..fdccceff 100644 --- a/examples/tutorial/README.md +++ b/examples/tutorial/README.md @@ -1,3 +1,9 @@ # Tuono tutorial This project is the outcome of the [tuono tutorial](https://github.com/Valerioageno/tuono/blob/main/docs/tutorial.md) + +If you want to directly install it you can run: + +```bash +$ tuono new my-project -t tutorial +```