Gestion de la ligne de commande
Jusqu'ici nous avons géré les arguments donnés sur la ligne de commande à la main grâce à l'itérateur std::env::args()
. Il existe des crates permettant de gérer de manière plus complète la ligne de commande. Le plus connu d'entre eux est clap.
clap est capable de parser les arguments, sous-commandes et les options fournis sur la ligne de commande et de vérifier qu'ils correspondent à la spécification.
Nous allons configurer clap pour ajouter une sous-commande group
qui affichera les logins ayant le même mot de passe comme nous faisions précédemment.
-
Ajoutez le crate
clap
(version 3.x) à votre projet grâce àcargo add clap@3 --features derive
. Cette sous-commande decargo
, venant du cratecargo-edit
que vous avez installé précedemment, ajoute la dernière version du crate à votre projet avec les optionsderive
de ce crate qui permet d'utiliserParser
. -
Après avoir importé les entités nécessaires du crate
clap
, créez la description de votre application :
use clap::{Args, Parser, Subcommand};
#[derive(Parser)]
#[clap(version, author, about)]
struct AppArgs {
#[clap(subcommand)]
command: Command,
}
#[derive(Subcommand)]
enum Command {
/// Check duplicate passwords from command line
Group(GroupArgs),
}
#[derive(Args)]
struct GroupArgs {
#[clap(required = true)]
/// Account to check
account: Vec<Account>,
}
fn main() {
// Check command line
let args = AppArgs::parse();
…
}
Décortiquons ce qu'on a décrit :
- Nous avons une application dont le nom, la version, les auteurs et la description proviennent respectivement des champs
name
,version
,authors
etdescription
deCargo.toml
lorsqu'ils sont définis. - Une sous-commande existe qui a comme nom
group
. Les arguments de cette sous-commande sont décrits dans la structureGroupArgs
. - Cette sous-commande a un argument
ACCOUNT
dont l'aide est "Account to check", dont la présence est obligatoire, et qui peut être répété puisque nous utilisonsVec<Account>
. - Étant donné que nous avons implémenté le trait
FromStr
pourAccount
, le parseur nous générera automatiquement un vecteur du bon type. - Une sous-commande doit être obligatoirement précisée, sinon le message d'aide sera produit et le programme s'arrêtera. Nous n'avons qu'une seule sous-commande, il faudra donc systématiquement préciser "group" sur la ligne de commande.
Exploration des messages d'aide
Rien qu'en insérant cela dans main()
, nous pouvons vérifier les messages d'aide générés avant même de modifier notre programme pour en tenir compte :
$ cargo run
pwdchk 0.1.0
USAGE:
pwdchk <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
group Check duplicate passwords from command line
help Print this message or the help of the given subcommand(s)
Une sous-commande help
a été insérée automatiquement. Utilisons la pour voir la documentation de notre sous-commande group
:
$ cargo run -- help group
pwdchk-group
Check duplicate passwords from command line
USAGE:
pwdchk group [OPTIONS] <ACCOUNT>...
ARGS:
<ACCOUNT>... Account to check
OPTIONS:
-h, --help Print help information
On remarquera que ces messages d'aide ont été générés à partir de nos commentaires sur les arguments. Comme on l'a expliqué précédemment, le séparateur --
permet à cargo run
de comprendre que les arguments sont destinés à l'application lancée et pas à cargo run
lui-même. Ici ce n'est pas obligatoire, mais si on avait passé des arguments comme -h
cela aurait été nécessaire :
$ cargo run -h
cargo-run
Run a binary or example of the local package
USAGE:
cargo run [OPTIONS] [--] [args]...
OPTIONS:
-q, --quiet Do not print cargo log messages
--bin <NAME>... Name of the bin target to run
--example <NAME>... Name of the example target to run
[…]
$ cargo run -- -h
pwdchk 0.1.0
USAGE:
pwdchk <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
group Check duplicate passwords from command line
help Print this message or the help of the given subcommand(s)
Adaptation de notre code
En cas d'utilisation correcte de la ligne de commande, la variable args
contient une structure AppArgs
. En cas d'erreur, le programme termine avec un message d'aide.
Nous pouvons extraire la sous-commande utilisée ainsi que ses arguments.
fn main() {
let args = AppArgs::parse();
match args.command {
Command::Group(args) => { // args is of type GroupArgs here
// Grouper les comptes collectés dans args.account, les filtrer, afficher
// ceux ayant plus d'un login en réutilisant le code écrit précédemment.
todo!()
}
}
}
- En utilisant le modèle ci-dessus comme exemple, modifiez votre application pour qu'elle fasse ce qui est demandé.
Maintenant qu'on dispose d'un traitement de la ligne de commande adéquat, il sera facile d'ajouter de nouvelles fonctionnalités tout en conservant les précédentes. N'hésitez pas à parcourir la documentation de clap pour en découvrir toutes les possibilités.