What about features not in standard Rust Library ?
Our cli can manage many subcommands but usage is not documented
How to build a cli with nice usage help ?
- add external libraries from crates.io
- use Clap as command line argument parser
Rust provides many libraries out of the box but at a time, we need specifics features
Crates.io is the defaut public repository where to search modules
💡 Notes
What about playing chifoumi with computer as opponent ?
2 ways to add dependency
cargo add rand
Updating crates.io index
Adding rand v0.8.5 to dependencies.
Features:
+ alloc
+ getrandom
+ libc
+ rand_chacha
+ std
+ std_rng
- log
- min_const_gen
- nightly
- packed_simd
- serde
- serde1
- simd_support
- small_rng
📚 Additional resources
- cargo add documentation (ex: specify version, features,etc)
Add dependency in cargo.toml
[dependencies]
rand = "0.8.5"
Example of usage
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
let n1: u8 = rng.gen();
println!("Random u8: {}", n1);
println!("Integer de 0 to 3 included: {}", rng.gen_range(0..=3));
}
📚 Additional resources
Clap a commonly used crate for Cli application in Rust
With Derive feature, we can setup a Cli in few lines
// from clap doc.rs
use clap::Parser;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Name of the person to greet
#[clap(short, long, value_parser)]
name: String,
/// Number of times to greet
#[clap(short, long, value_parser, default_value_t = 1)]
count: u8,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Hello {}!", args.name)
}
}
$ demo --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
demo[EXE] [OPTIONS] --name <NAME>
OPTIONS:
-c, --count <COUNT> Number of times to greet [default: 1]
-h, --help Print help information
-n, --name <NAME> Name of the person to greet
-V, --version Print version information
$ demo --name Me
Hello Me!
💡 Notes
- You can describe commands without annotation if you want
📚 Additional resources
Cargo "features" provide a mechanism to express conditional compilation and optional dependencies.
cargo add clap
Updating crates.io index
Adding clap v3.2.22 to dependencies.
Features:
+ atty
+ color
+ std
+ strsim
+ suggestions
+ termcolor
- backtrace
- cargo
- clap_derive
- debug
- deprecated
- derive
- env
- once_cell
- regex
- terminal_size
- unicase
- unicode
- unstable-doc
- unstable-grouped
- unstable-replace
- unstable-v4
- wrap_help
- yaml
- yaml-rust
Note that Derive
Feature is no enabled
📚 Additonal resource
use cargo add option -F (or --features)
cargo add clap -F derive
Update dependencies
[dependencies]
clap = { version = "3.2.22", features = ["derive"] }
We want to have distinct options for each cli functionality (greets and chifoumi)
Clap provides functionality to create subcommand with struct and enum
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[clap(
author = "Julien Rollin",
version = "1.0.0",
about = "Crabby cli",
long_about = None
)]
#[clap(propagate_version = true)]
struct Cli {
#[clap(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Adds files to myapp
Add { name: Option<String> },
/// Doc about other command
Greets {
/// Name of the person to greet
#[clap(short, long, value_parser)]
name: String,
},
}
fn main() {
let cli = Cli::parse();
// You can check for the existence of subcommands, and if found use their
// matches just as you would the top level cmd
match &cli.command {
Commands::Add { name } => {
println!("'myapp add' was used, name is: {:?}", name)
}
Commands::Greets { name } => {
println!("Name: {:?}", name)
}
}
}
Try this command by yourself
cargo run
cargo run -- -V
cargo run -- greets --help
Refactor your app code with Clap and Subcommand
you shoud see beautiful cli usage when running your app
$ crabby --help
crabby 0.1.0
I am the crabby help usage.
USAGE:
crabby <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
chifoumi chifoumi with players
greets Greets with name
help Print this message or the help of the given subcommand(s)
If no player two is provided use a random game value for player 2
cargo run -- chifoumi -a paper
p1: Paper vs p2: Scissors => Lost
you can imagine building any cli now !
Check a solution with unit tests here
What you learned
- add crate with features
- parse and document usage of cli app with clap