From 738d5ad820a3008c85d6cc73d887f1b12561de04 Mon Sep 17 00:00:00 2001 From: Eric Githinji <51313777+egithinji@users.noreply.github.com> Date: Wed, 21 May 2025 09:58:52 +0300 Subject: [PATCH] Simplify project commands using `cargo xtask` (#2753) We are already using `cargo xtask install-tools` to install the project's tools, and `cargo xtask web-tests` to run the js tests. In this PR we provide support for the various `mdbook` commands (`test`,`serve`, and `build`) with `cargo xtask` commands. This provides a uniform interface for running tasks in the project. Additionally it allows these commands to work from within any dirrectory (previously you'd need to navigate to the workspace root in order to run say `mdbook build`). Additionally we're improving the xtask code by making use of `Clap` enums to handle validation of the possible tasks to run via xtask (this closes #2741 ). --------- Co-authored-by: Eric Githinji --- README.md | 33 +++++--------- xtask/src/main.rs | 107 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 1315de59..a091b24e 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Articles and blog posts from around the web which cover Comprehensive Rust: _[Rust Training at Scale | Rust Global @ RustConf 2024](https://youtu.be/7h5KyMqt2-Q?si=4M99HdWWxMaqN8Zr)_. What Google learnt from teaching Comprehensive Rust for more than two years. -## Building +## Setup The course is built using a few tools: @@ -55,10 +55,7 @@ The course is built using a few tools: - [mdbook-i18n-helpers and i18n-report](https://github.com/google/mdbook-i18n-helpers) - [mdbook-exerciser](mdbook-exerciser/) - [mdbook-course](mdbook-course/) - -In addition, -[mdbook-linkcheck](https://github.com/Michael-F-Bryan/mdbook-linkcheck) checks -the internal links. +- [mdbook-linkcheck](https://github.com/Michael-F-Bryan/mdbook-linkcheck) First install Rust by following the instructions on https://rustup.rs/. Then clone this repository: @@ -74,25 +71,17 @@ Then install these tools with: cargo xtask install-tools ``` -Run +## Commands -```shell -mdbook test -``` +Here is a summary of the various commands you can run in the project. -to test all included Rust snippets. Run - -```shell -mdbook serve -``` - -to start a web server with the course. You'll find the content on -. You can use `mdbook build` to create a static version -of the course in the `book/` directory. Note that you have to separately build -and zip exercises and add them to `book/html`. To build any of the translated -versions of the course, run `MDBOOK_BOOK__LANGUAGE=xx mdbook build -d book/xx` -where `xx` is the ISO 639 language code (e.g. `da` for the Danish translation). -[TRANSLATIONS.md](TRANSLATIONS.md) contains further instructions. +| Command | Description | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cargo xtask install-tools` | Install all the tools the project depends on. | +| `cargo xtask serve` | Start a web server with the course. You'll find the content on http://localhost:3000. | +| `cargo xtask rust-tests` | Test the included Rust snippets. | +| `cargo xtask web-tests` | Run the web driver tests in the tests directory. | +| `cargo xtask build` | Create a static version of the course in the `book/` directory. Note that you have to separately build and zip exercises and add them to book/html. To build any of the translated versions of the course, run MDBOOK_BOOK__LANGUAGE=xx mdbook build -d book/xx where xx is the ISO 639 language code (e.g. da for the Danish translation). [TRANSLATIONS.md](TRANSLATIONS.md) contains further instructions. | > **Note** On Windows, you need to enable symlinks > (`git config --global core.symlinks true`) and Developer Mode. diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 4b60045a..e355b6e0 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -20,7 +20,7 @@ //! the tools. use anyhow::{anyhow, Ok, Result}; -use clap::Parser; +use clap::{Parser, ValueEnum}; use std::path::Path; use std::{env, process::Command}; @@ -32,23 +32,38 @@ fn main() -> Result<()> { Ok(()) } -#[derive(Parser, Debug)] +#[derive(Parser)] #[command( about = "Binary for executing tasks within the Comprehensive Rust project" )] -struct Args { - #[arg(required = true, help = "The task to execute")] - task: String, +struct Cli { + /// The task to execute + #[arg(value_enum)] + task: Task, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +enum Task { + /// Installs the tools the project depends on. + InstallTools, + /// Runs the web driver tests in the tests directory. + WebTests, + /// Tests all included Rust snippets. + RustTests, + /// Starts a web server with the course. + Serve, + /// Create a static version of the course in the `book/` directory. + Build, } fn execute_task() -> Result<()> { - let task = Args::parse().task; - match task.as_str() { - "install-tools" => install_tools()?, - "web-tests" => run_web_tests()?, - _ => { - return Err(anyhow!(unrecognized_task_string(task.as_str()))); - } + let cli = Cli::parse(); + match cli.task { + Task::InstallTools => install_tools()?, + Task::WebTests => run_web_tests()?, + Task::RustTests => run_rust_tests()?, + Task::Serve => start_web_server()?, + Task::Build => build()?, } Ok(()) } @@ -109,7 +124,7 @@ fn run_web_tests() -> Result<()> { if !status.success() { let error_message = format!( - "Command 'cargo web-tests' exited with status code: {}", + "Command 'cargo xtask web-tests' exited with status code: {}", status.code().unwrap() ); return Err(anyhow!(error_message)); @@ -118,12 +133,64 @@ fn run_web_tests() -> Result<()> { Ok(()) } -// TODO - https://github.com/google/comprehensive-rust/issues/2741: Replace this with Clap -fn unrecognized_task_string(task: &str) -> String { - format!( - "Unrecognized task '{task}'. Available tasks: +fn run_rust_tests() -> Result<()> { + println!("Running rust tests..."); -install-tools Installs the tools the project depends on. -web-tests Runs the web driver tests in the tests directory." - ) + let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR")); + + let status = Command::new("mdbook") + .current_dir(path_to_workspace_root.to_str().unwrap()) + .arg("test") + .status() + .expect("Failed to execute mdbook test"); + + if !status.success() { + let error_message = format!( + "Command 'cargo xtask rust-tests' exited with status code: {}", + status.code().unwrap() + ); + return Err(anyhow!(error_message)); + } + + Ok(()) +} + +fn start_web_server() -> Result<()> { + println!("Starting web server ..."); + let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR")); + + let status = Command::new("mdbook") + .current_dir(path_to_workspace_root.to_str().unwrap()) + .arg("serve") + .status() + .expect("Failed to execute mdbook serve"); + + if !status.success() { + let error_message = format!( + "Command 'cargo xtask serve' exited with status code: {}", + status.code().unwrap() + ); + return Err(anyhow!(error_message)); + } + Ok(()) +} + +fn build() -> Result<()> { + println!("Building course..."); + let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR")); + + let status = Command::new("mdbook") + .current_dir(path_to_workspace_root.to_str().unwrap()) + .arg("build") + .status() + .expect("Failed to execute mdbook build"); + + if !status.success() { + let error_message = format!( + "Command 'cargo xtask build' exited with status code: {}", + status.code().unwrap() + ); + return Err(anyhow!(error_message)); + } + Ok(()) }