Introduction
Dans cet article, nous allons construire ensemble une application en ligne de commande toute simple avec Rust. Le but du programme sera très basique. L'utilisateur nous donnera un nom de dossier et nous créerons un nouveau dossier avec ce nom. Plutôt facile non? Allons-y!
Setup
Si vous n'avez pas encore installé Rust, vous pouvez consulter la documentation officielle, il ya beaucoup d'infos utile!
Commençons par créer notre nouveau projet Rust. Pour ça, on peut lancer la commande suivante:
cargo new new_dir_cmd
Ceci va créer un nouveau dossier appelé new_dir_cmd. Bien sûr, vous pouvez remplacer ce nom par ce que vous voulez.
Si on jette un oeil à l'intérieur de notre nouveau dossier, on peut voir ceci:
Si on lance direct cargo run
à l'intérieur de ce dossier, on va se retrouver avec notre bon vieux "Hello World!".
Génial, on est prêt à coder!
Créer un nouveau dossier
Première étape, on va créer un nouveau dossier. On améliorera notre programme petit à petit.
Mettons le code suivant dans notre main.rs:
use std::fs;
fn main() -> std::io::Result<()> {
fs::create_dir_all("/Users/damiencosset/Desktop/rust/new_dir_cmd/awesome_new_dir")?;
Ok(())
}
On utilise le module fs qui vient du crate std. Crates ( caisses en Français ), dans le contexte de Rust, sont similaires aux packages dans d'autres languages. Si vous voulez plus d'informations sur les crates, vous pouvez consulter la documentation
On utilise la fonction create_dir_all exportée par le module. Elle prend un chemin (path) comme argument. Pour l'instant, je lui donne un nom de chemin en dur.
Enfin, cette fonction retourne un type std::io::Result. Donc, notre fonction main doit retourner ce type. On ajoute donc -> std::io::Result<()>. Après avoir créer un nouveau dossier, on renvoie simplement le Ok variant qui indique que tout est ok et qu'aucune erreur n'a été rencontré.
Note: Le caractère ? est utilisé dans Rust pour la propagation d'erreur. Si nous rencontrons une erreur pendant la création de notre dossier, nous retournerons un Err(error), Err étant le deuxième variant que peut prendre Result après Ok.
Lançons ce code et voyons ce que ça donne:
Ca marche! On vient de créer notre premier nouveau dossier avec Rust!
Ajouter des arguments à notre ligne de commande
Eviddemment, ce programme n'est pas très utile. Le but est que l'utilisateur puisse donner un nom de dossier via la ligne de commande. Mettons cela en place.
Ajout du crate clap
Pour lire des arguments de notre ligne de commande, on va utiliser le crate clap. Pour consulter les crates qui ont été ajoutés à notre projet, on peut ouvrir le fichier Cargo.toml et voir ce qui se trouve après:
[dependencies]
Tout les crates qui auront été rajoutés se trouveront ici.
Ajoutons clap avec la commande suivante:
cargo add clap --features derive
Le flag features nous permet d'utiliser des fonctionnalités optionnel du crate. Ici, on veut utilise la feature appelé derive. Pour avoir plus d'informations sur ce crate, vous pouvez consulter sa documentation. Et si nous jettons un oeil à notre Cargo.toml, nous avons à présent une nouvelle ligne:
[dependencies]
clap = { version = "4.5.4", features = ["derive"] }
Définir nos arguments
Remplaçons notre code existant avec ceci:
use clap::Parser;
//use std::fs;
#[derive(Parser)]
struct Cli {
directory_name: String,
}
fn main() -> std::io::Result<()> {
let args = Cli::parse();
println!("{}", args.directory_name);
// fs::create_dir_all("/Users/damiencosset/Desktop/rust/new_dir_cmd/awesome_new_dir")?;
Ok(())
}
J'ai mis en commentaire la création de dossier pour le moment
#[derive(Parser)]
indique que nous utilisons une macro personnalisée qui implémente le trait Parser. Plus simplement, un trait définit un ensemble de méthodes (ou fonctions). Ici, nous implémentons un ensemble de méthodes (ou fonctions) définit dans Parser dans notre Cli structure. Donc, notre structure Cli est capable d'appeler les méthodes implémentées, comme parse().
Avec ce code, et le pouvoir de clap, nous pouvons lire les arguments de notre ligne de commande. Lançons à nouveau notre application et donnons lui un argument:
Parfait! Nous avons réussi à afficher notre argument. On peut à présent lire notre nom de dossier depuis la ligne de commande.
Récupérer le dossier actuel
Maintenant, nous avons un léger soucis. On ne va pas donner le chemin entier du dossier dans notre ligne de commande. On ne va donner que le nom du dossier que l'on souhaite créer.Donc, notre programme a besoin de savoir ou créer notre dossier. Pour garder les choses simples, nous allons prendre le dossier dans lequel nous sommes actuellement, puis y ajouter le nom du dossier que l'on vient de récupérer de la ligne de commande.
On a besoin de:
- récupérer le chemin du dossier actuel
- ajouter le nom du dossier à ce chemin
Pour récupérer le chemin du dossoer actuel, on peut ajouter ces 2 lignes de code:
// Import
use std::env;
// Inside the main function
let mut path = env::current_dir()?;
Notez que l'on utilise le mot clé mut. Cela signifie que la variable que nous venons de définir est mutable. Les variables de Rust sont par défaut immuable. En ajoutant le mot clé mut, on peut modifier notre variable pour y ajouter le nom du dossier que l'on veut créer.
En combinant tout cela, notre programme complet ressemble à ça:
use clap::Parser;
use std::env;
use std::fs;
#[derive(Parser)]
struct Cli {
directory_name: String,
}
fn main() -> std::io::Result<()> {
let args = Cli::parse();
let mut path = env::current_dir()?;
path.push(args.directory_name);
fs::create_dir_all(path)?;
Ok(())
}
En utilisant push(), on peut ajouter notre nom de dossier au chemin du dossir actuel. Voyons si tout fonctionne!
Wooo! Ca marche!
Et just comme ça, nous avons créé un programme très simple avec Rust qui nous permet de créer des nouveaux dossiers.
En espérant que vous avez trouvé cela intéressant!
Have fun ❤