Clap, Rust CLI

Reidar Sollid

About CLAP

Clap står for Comand Line Argument Parser og er ett crate for å parse og validere strenger fra kommandolinjeargumenter.

Hvorfor gjør jeg dette ?

Jeg er veldig glad i Go-lang sine Cobra og Viper moduler og CLI verktøyet som følger med, genialt for å lage CLI verktøy. Mitt problem er, at jeg skriver all annen software i Rust og den context switchen for å kode Go-lang igjen, stjeler for mye tid.

Cargo integrasjon

Jeg kan bruke cargo my-command --args slik at jeg integerer med cargo.

Komme i gang med CLAP

Jeg tar utgangspunkt i at du allerede har skapt ett cargo prosjekt for CLI applikasjonen din.

Legg til clap til Cargo.toml cargo add clap -F derive hvor -F flagget står for feature.

Din cargo.toml fil bør da inneholde noe som dette:

[dependencies]
clap = { version = "4.1.10", features = ["derive"] }

Nå er vi klare for litt koding

Først så lager jeg mine kommando argumenter i structen Arguments (lite orginalt navn, men funker her).

use clap::Parser;

#[derive(Default, Debug, Parser)]
struct Arguments {
    name: String,
    age: usize,
}

I main funksjonen skriver jeg bare ut argumentene.

fn main() {
    let args = Arguments::parse();
    println!(":?", args)
}

Jeg installerer appen i stedet for å kjøre cargo run -- arg1 arg2 --flagg da jeg synes det gir ett mer riktig intrykk av hvordan CLI-apppen blir, det gjøres enkelt med :

cargo install --path .

Så teste CLI-appen, med det geniale navnet clap-cli

✹)──> clap-cli
error: the following required arguments were not provided:
    <NAME>
    <AGE>
Usage: clap-cli <NAME> <AGE>

For more information, try '--help'.

Så allerede en fungerende CLI-applikasjon, så la oss teste med -h flagget.

✹)──> clap-cli -h
Usage: clap-cli <NAME> <AGE>

Arguments:
    <NAME>
    <AGE>

Options:
    -h, --help     Print help

Happy path.

✹)──> clap-cli Reidar 52
Arguments { name: "Reidar", age: 52 }

Mer makromagi

Vi kan legge på clap traitet, for å gi mer info for help, her legger jeg på version som den henter fra Cargo.toml fila og about som den henter fra kommentarene over funksjonen

#[derive(Default, Debug, Parser)]
#[clap(author = "Amedia Utvikling", version, about)]
/// Demo app for Jotter blog
struct Arguments {
    ...
}

Som gir oss dette i konsollet.

✹)──> clap-cli -h
Demo app for Jotter blog

Usage: clap-cli <NAME> <AGE>

Arguments:
    <NAME>
    <AGE>

Options:
    -h, --help     Print help
    -V, --version  Print version

Legge på flagg

Her også får vi hjelp fra makroen clap , legger denne inn i Arguments structen:

#[clap(short, long)]
/// For test run
test_run: bool,

Short og long, står for kort og langt flagg, det vil si -t for short og --test-run for long.

✹)──> clap-cli -h
Demo app for Jotter blog

Usage: clap-cli [OPTIONS] <NAME> <AGE>

Arguments:
    <NAME>
    <AGE>

Options:
    -t, --test-run  For test run
    -h, --help      Print help
    -V, --version   Print version

Jeg kan også gruppere flaggene, ved å legge på help_heading

#[clap(short, long, help_heading = "Test")]
/// For test run
test_run: bool,

Som vil gi oss dette resultatet:

✹)──> clap-cli -h
Demo app for Jotter blog

Usage: clap-cli [OPTIONS] <NAME> <AGE>

Arguments:
    <NAME>
    <AGE>

Options:
    -h, --help     Print help
    -V, --version  Print version

Test:
    -t, --test-run  For test run

I sin helhet, blir da Arguments structen som dette :

#[derive(Default, Debug, Parser)]
#[clap(author = "Amedia Utvikling", version, about)]
/// Demo app for Jotter blog
struct Arguments {
    name: String,
    age: usize,
    #[clap(short, long, help_heading = "Test")]
    /// For test run
    test_run: bool,
}

Konklusjon

Makroer gir mye kraft i parsing av kommandolinje argumenter, så helt klart mye boilerplate kode som blir borte her. Jeg savner litt strukturen til Cobra CMD, men trenger den kanskje ikke her.

Det er ingen tvil hos meg, jeg går over på clap og Rust for mine CLI-verktøy.