Skip to content

Commit

Permalink
update original
Browse files Browse the repository at this point in the history
  • Loading branch information
funkill committed Jan 9, 2025
1 parent 8bcbea1 commit edbdef1
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 8 deletions.
2 changes: 2 additions & 0 deletions rust-cookbook/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[alias]
xtask = "run --manifest-path ./xtask/Cargo.toml --"
7 changes: 2 additions & 5 deletions rust-cookbook/.github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ No worries if anything in these lists is unclear. Just submit the PR and ask awa
--------------------------
### Things to check before submitting a PR

- [ ] the tests are passing locally with `cargo test`
- [ ] cookbook renders correctly in `mdbook serve -o`
- [ ] the tests are passing locally with `cargo xtask test all`
- [ ] commits are squashed into one and rebased to latest master
- [ ] PR contains correct "fixes #ISSUE_ID" clause to autoclose the issue on PR merge
- if issue does not exist consider creating it or remove the clause
- [ ] spell check runs without errors `./ci/spellcheck.sh`
- [ ] link check runs without errors `link-checker ./book`
- [ ] non rendered items are in sorted order (links, reference, identifiers, Cargo.toml)
- [ ] links to docs.rs have wildcard version `https://docs.rs/tar/*/tar/struct.Entry.html`
- [ ] example has standard [error handling](https://rust-lang-nursery.github.io/rust-cookbook/about.html#a-note-about-error-handling)
Expand All @@ -25,4 +22,4 @@ No worries if anything in these lists is unclear. Just submit the PR and ask awa
### Things to do after submitting PR
- [ ] check if CI is happy with your PR

Thank you for reading, you may now delete this text! Thank you! :smile:
Thank you for reading, you may now delete this text! Thank you! :smile:
26 changes: 25 additions & 1 deletion rust-cookbook/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ cd rust-cookbook
Cookbook is built with [mdBook], so install that first with Cargo:

```
cargo install --version 0.3.5 mdbook
cargo install --version 0.4.43 mdbook
```

To build and view the cookbook locally, run:
Expand All @@ -44,6 +44,30 @@ To run the cookbook test suite:
cargo test
```

### xtask

To simplify common tasks like testing, building the book, and running linters.

First, ensure you have the required tools installed:

```bash
cargo install [email protected] [email protected]
```

- To run all tests:

```bash
cargo xtask test all
```

- To build the book locally:

```bash
cargo xtask book
```

For more details on available tasks, please check the full [xtask README](./xtask/README.md).

## Linters

The Rust Cookbook comes with link checking and spell checking linters that
Expand Down
3 changes: 3 additions & 0 deletions rust-cookbook/ci/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,6 @@ XRateLimitReset
YAML
YYYY
zurich
enum
thiserror
tempfile
2 changes: 1 addition & 1 deletion rust-cookbook/src/database/postgres/aggregate_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ fn main() -> Result<(), Error> {
}
```

[`Museum of Modern Art`]: https://github.com/MuseumofModernArt/collection/blob/master/Artists.csv
[`Museum of Modern Art`]: https://github.com/MuseumofModernArt/collection/blob/main/Artists.csv
2 changes: 1 addition & 1 deletion rust-cookbook/src/web/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
| [POST a file to paste-rs][ex-file-post] | [![reqwest-badge]][reqwest] | [![cat-net-badge]][cat-net] |

[ex-url-basic]: clients/requests.html#make-a-http-get-request
[ex-url-header]: web/clients/requests.html#set-custom-headers-and-url-parameters-for-a-rest-request
[ex-url-header]: clients/requests.html#set-custom-headers-and-url-parameters-for-a-rest-request
[ex-rest-custom-params]: clients/requests.html#set-custom-headers-and-url-parameters-for-a-rest-request
[ex-rest-get]: clients/apis.html#query-the-github-api
[ex-rest-head]: clients/apis.html#check-if-an-api-resource-exists
Expand Down
6 changes: 6 additions & 0 deletions rust-cookbook/xtask/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"

[dependencies]
33 changes: 33 additions & 0 deletions rust-cookbook/xtask/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# xtask - (Rust Cookbook)

**Rust Dependencies**:
- Make sure you have the required tools installed:
```bash
cargo install [email protected] [email protected]
```

## Available Tasks

### `test`
Run various tests for the project. You can specify individual tests or run them all.

- `cargo`: Run the `cargo test` command for the Rust code.
- `spellcheck`: Run the spellcheck script.
- `link`: Verify links within the project.
- `all`: Run all the tests (default).

**Usage:**
```bash
cargo xtask test [all|cargo|spellcheck|link]
```

### `book`
Build or serve the project's documentation using `mdbook`.
- `build`: Build the book (default).
- `serve`: Serve the book locally and open it in a browser.
**Usage:**
```bash
cargo xtask book [build|serve]
```
57 changes: 57 additions & 0 deletions rust-cookbook/xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
mod tests;
mod mdbook;

use std::path::{Path, PathBuf};
use std::{env, error::Error};

fn main() {
if let Err(e) = try_main() {
eprintln!("{}", e);
std::process::exit(-1);
}
}

fn try_main() -> Result<(), Box<dyn Error>> {
let task = env::args().nth(1);
match task.as_deref() {
Some("test") => {
let sub_task = env::args().nth(2).unwrap_or_else(|| "all".to_string());
tests::run_test(&sub_task)?
}
Some("book") => {
let sub_task = env::args().nth(2).unwrap_or_else(|| "build".to_string());
mdbook::run_book(&sub_task)?
}
_ => print_help(),
}
Ok(())
}

fn project_root() -> PathBuf {
Path::new(&env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(1)
.unwrap()
.to_path_buf()
}

fn print_help() {
eprintln!("Available tasks:");
eprintln!(
" test [all|cargo|spellcheck|link] - Run the tests. Use 'all' to run all tests (default), or specify individual tests."
);
eprintln!(
" book [build] - Build the book using mdbook. Default if no subcommand is specified."
);
eprintln!(" book serve - Serve the book using mdbook and open it in a browser.");
eprintln!();
eprintln!("Usage:");
eprintln!(" cargo xtask <task> [subcommand]");
eprintln!();
eprintln!("Examples:");
eprintln!(" cargo xtask test");
eprintln!(" cargo xtask test all");
eprintln!(" cargo xtask test cargo");
eprintln!(" cargo xtask book");
eprintln!(" cargo xtask book serve");
}
62 changes: 62 additions & 0 deletions rust-cookbook/xtask/src/mdbook.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::project_root;
use std::{error::Error, process::Command};

pub fn run_book(task: &str) -> Result<(), Box<dyn Error>> {
let args: &[&str] = if task == "serve" { &["--open"] } else { &[] };

execute_mdbook_command(task, args)?;

Ok(())
}

fn execute_mdbook_command(command: &str, additional_args: &[&str]) -> Result<(), Box<dyn Error>> {
check_mdbook_version()?;

let book_dest = project_root().join("book").to_str().unwrap().to_string();

let mut args = vec![command, "--dest-dir", &book_dest];
args.extend_from_slice(additional_args);

let status = Command::new("mdbook")
.current_dir(project_root())
.args(&args)
.status()?;

if !status.success() {
return Err(format!("`mdbook {command}` failed to run successfully!").into());
}

Ok(())
}

fn check_mdbook_version() -> Result<(), Box<dyn Error>> {
let required_version = "0.4.43";

let output = Command::new("mdbook").arg("--version").output()?;

if !output.status.success() {
println!("Error: `mdbook` not found. Please ensure it is installed!");
println!("You can install it using:");
println!(" cargo install mdbook@{required_version}");
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::NotFound,
"`mdbook` is not installed",
)));
}

let version_output = String::from_utf8_lossy(&output.stdout);
let version_str = version_output.trim();

if !version_str.starts_with(&format!("mdbook {}", required_version)) {
println!(
"Warning: You are using version {version_str} of `mdbook`. Version {required_version} is required."
);
println!(
"Errors may occur if using a different version. Please install version {required_version}:"

);
println!(" cargo install mdbook@{required_version}");
}

Ok(())
}
104 changes: 104 additions & 0 deletions rust-cookbook/xtask/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use crate::project_root;
use std::error::Error;
use std::process::Command;

pub fn run_test(task: &str) -> Result<(), Box<dyn Error>> {
match task {
"all" => run_all_tests()?,
"cargo" => cargo_test()?,
"spellcheck" => spellcheck()?,
"link" => link_checker()?,
_ => run_all_tests()?,
}
Ok(())
}

fn run_all_tests() -> Result<(), Box<dyn Error>> {
let mut failures = Vec::new();

if cargo_test().is_err() {
failures.push("cargo_test".to_string());
}

if spellcheck().is_err() {
failures.push("spellcheck".to_string());
}

if link_checker().is_err() {
failures.push("link".to_string());
}

if !failures.is_empty() {
println!("\n--- Test Summary ---");
for name in failures {
println!("❌ {name} failed! Re-run with the command:");
println!(" cargo xtask test {name}");
}
} else {
println!("\n🎉 All tests passed!");
}

Ok(())
}

fn cargo_test() -> Result<(), Box<dyn Error>> {
let status = Command::new("cargo")
.current_dir(project_root())
.args(["test", "--package", "rust-cookbook"])
.status()?;

if !status.success() {
return Err("failed to run cargo test!".into());
}

Ok(())
}

fn spellcheck() -> Result<(), Box<dyn Error>> {
let status = Command::new("./ci/spellcheck.sh")
.current_dir(project_root())
.status()?;

if !status.success() {
return Err("failed to run spellcheck!".into());
}

Ok(())
}

fn link_checker() -> Result<(), Box<dyn Error>> {
if Command::new("lychee").arg("--version").status().is_err() {
return Err(
"The `lychee` tool is not installed. Please install it using:\n cargo install [email protected]".into(),
);
}

let book_dir = project_root().join("book");
if !book_dir.is_dir() {
return Err(format!(
"The book directory could not be found in the root directory: {:?}\n\
You can build it using:\n cargo xtask book build",
book_dir
)
.into());
}

let status = Command::new("lychee")
.current_dir(project_root())
.args([
"./book",
"--retry-wait-time",
"20",
"--max-retries",
"3",
"--accept",
"429", // accept 429 (ratelimit) errors as valid
])
.status()?;

if !status.success() {
return Err("Failed to run link checker!".into());
}

Ok(())
}

0 comments on commit edbdef1

Please sign in to comment.