1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-08-08 08:22:52 +02:00

Support setting language and output directory in cargo xtask (#2776)

In addition to simplifying building locally (no need to set an
environment variable), this makes it possible to use the `cargo xtask
build` command in the CI and specify any output location, rather than
relying on the build.sh script.

---------

Co-authored-by: Eric Githinji <egithinji@google.com>
This commit is contained in:
Eric Githinji
2025-07-31 12:54:26 +03:00
committed by GitHub
parent 16d25dbed7
commit 5fc5893fbf
2 changed files with 73 additions and 30 deletions

View File

@ -76,12 +76,12 @@ cargo xtask install-tools
Here is a summary of the various commands you can run in the project. Here is a summary of the various commands you can run in the project.
| Command | Description | | Command | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cargo install-tools` | Install all the tools the project depends on. | | `cargo install-tools` | Install all the tools the project depends on. |
| `cargo serve` | Start a web server with the course. You'll find the content on http://localhost:3000. | | `cargo serve` | Start a web server with the course. You'll find the content on http://localhost:3000. To serve any of the translated versions of the course, add the language flag (`--language` or `-l`) followed by xx, where xx is the ISO 639 language code (e.g. `cargo xtask serve -l da` for the Danish translation). |
| `cargo rust-tests` | Test the included Rust snippets. | | `cargo rust-tests` | Test the included Rust snippets. |
| `cargo web-tests` | Run the web driver tests in the tests directory. | | `cargo web-tests` | Run the web driver tests in the tests directory. |
| `cargo build-book` | 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. | | `cargo build-book` | 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, add the language flag (`--language` or `-l`) followed by xx, where xx is the ISO 639 language code (e.g. `cargo xtask build -l da` for the Danish translation). [TRANSLATIONS.md](TRANSLATIONS.md) contains further instructions. |
> **Note** On Windows, you need to enable symlinks > **Note** On Windows, you need to enable symlinks
> (`git config --global core.symlinks true`) and Developer Mode. > (`git config --global core.symlinks true`) and Developer Mode.

View File

@ -20,8 +20,8 @@
//! the tools. //! the tools.
use anyhow::{Ok, Result, anyhow}; use anyhow::{Ok, Result, anyhow};
use clap::{Parser, ValueEnum}; use clap::{Parser, Subcommand};
use std::path::Path; use std::path::{Path, PathBuf};
use std::{env, process::Command}; use std::{env, process::Command};
fn main() -> Result<()> { fn main() -> Result<()> {
@ -38,11 +38,11 @@ fn main() -> Result<()> {
)] )]
struct Cli { struct Cli {
/// The task to execute /// The task to execute
#[arg(value_enum)] #[command(subcommand)]
task: Task, task: Task,
} }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] #[derive(Subcommand)]
enum Task { enum Task {
/// Installs the tools the project depends on. /// Installs the tools the project depends on.
InstallTools, InstallTools,
@ -51,9 +51,25 @@ enum Task {
/// Tests all included Rust snippets. /// Tests all included Rust snippets.
RustTests, RustTests,
/// Starts a web server with the course. /// Starts a web server with the course.
Serve, Serve {
/// Create a static version of the course in the `book/` directory. /// ISO 639 language code (e.g. da for the Danish translation).
Build, #[arg(short, long)]
language: Option<String>,
/// Directory to place the build. If not provided, defaults to the book/ directory (or the book/xx directory if a language is provided).
#[arg(short, long)]
output: Option<PathBuf>,
},
/// Create a static version of the course.
Build {
/// ISO 639 language code (e.g. da for the Danish translation).
#[arg(short, long)]
language: Option<String>,
/// Directory to place the build. If not provided, defaults to the book/ directory (or the book/xx directory if a language is provided).
#[arg(short, long)]
output: Option<PathBuf>,
},
} }
fn execute_task() -> Result<()> { fn execute_task() -> Result<()> {
@ -62,15 +78,14 @@ fn execute_task() -> Result<()> {
Task::InstallTools => install_tools()?, Task::InstallTools => install_tools()?,
Task::WebTests => run_web_tests()?, Task::WebTests => run_web_tests()?,
Task::RustTests => run_rust_tests()?, Task::RustTests => run_rust_tests()?,
Task::Serve => start_web_server()?, Task::Serve { language, output } => start_web_server(language, output)?,
Task::Build => build()?, Task::Build { language, output } => build(language, output)?,
} }
Ok(()) Ok(())
} }
fn install_tools() -> Result<()> { fn install_tools() -> Result<()> {
println!("Installing project tools..."); println!("Installing project tools...");
let path_to_mdbook_exerciser = let path_to_mdbook_exerciser =
Path::new(env!("CARGO_WORKSPACE_DIR")).join("mdbook-exerciser"); Path::new(env!("CARGO_WORKSPACE_DIR")).join("mdbook-exerciser");
let path_to_mdbook_course = let path_to_mdbook_course =
@ -136,7 +151,6 @@ fn run_web_tests() -> Result<()> {
fn run_rust_tests() -> Result<()> { fn run_rust_tests() -> Result<()> {
println!("Running rust tests..."); println!("Running rust tests...");
let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR")); let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR"));
let status = Command::new("mdbook") let status = Command::new("mdbook")
@ -156,15 +170,26 @@ fn run_rust_tests() -> Result<()> {
Ok(()) Ok(())
} }
fn start_web_server() -> Result<()> { fn start_web_server(
language: Option<String>,
output_arg: Option<PathBuf>,
) -> Result<()> {
println!("Starting web server ..."); println!("Starting web server ...");
let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR")); let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR"));
let status = Command::new("mdbook") let mut command = Command::new("mdbook");
.current_dir(path_to_workspace_root.to_str().unwrap()) command.current_dir(path_to_workspace_root.to_str().unwrap());
.arg("serve") command.arg("serve");
.status()
.expect("Failed to execute mdbook serve"); if let Some(language) = &language {
println!("Language: {}", &language);
command.env("MDBOOK_BOOK__LANGUAGE", &language);
}
command.arg("-d");
command.arg(get_output_dir(language, output_arg));
let status = command.status().expect("Failed to execute mdbook serve");
if !status.success() { if !status.success() {
let error_message = format!( let error_message = format!(
@ -176,15 +201,23 @@ fn start_web_server() -> Result<()> {
Ok(()) Ok(())
} }
fn build() -> Result<()> { fn build(language: Option<String>, output_arg: Option<PathBuf>) -> Result<()> {
println!("Building course..."); println!("Building course...");
let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR")); let path_to_workspace_root = Path::new(env!("CARGO_WORKSPACE_DIR"));
let status = Command::new("mdbook") let mut command = Command::new("mdbook");
.current_dir(path_to_workspace_root.to_str().unwrap()) command.current_dir(path_to_workspace_root.to_str().unwrap());
.arg("build") command.arg("build");
.status()
.expect("Failed to execute mdbook build"); if let Some(language) = &language {
println!("Language: {}", &language);
command.env("MDBOOK_BOOK__LANGUAGE", language);
}
command.arg("-d");
command.arg(get_output_dir(language, output_arg));
let status = command.status().expect("Failed to execute mdbook build");
if !status.success() { if !status.success() {
let error_message = format!( let error_message = format!(
@ -195,3 +228,13 @@ fn build() -> Result<()> {
} }
Ok(()) Ok(())
} }
fn get_output_dir(language: Option<String>, output_arg: Option<PathBuf>) -> PathBuf {
// If the 'output' arg is specified by the caller, use that, otherwise output to the 'book/' directory
// (or the 'book/xx' directory if a language was specified).
if let Some(d) = output_arg {
d
} else {
Path::new("book").join(language.unwrap_or("".to_string()))
}
}