Pas de répis (ou très peu, pour être plus exact, puisque les articles sont tout de même espacés de quelques jours), on termine aujourd’hui les dernières explications vis à vis de la sous-commande create de bsc !

Si vous vous souvenez, dans l’article précédent, je vous ai expliqué comment je générais les fichiers de méta build cmake du squelette du projet C.

Dorénavant, il ne nous reste plus qu’à voir ensemble la création du fichier depencencies.bsc qui gère les modules dont dépend le projet (sur le même principe que packages.json en NodeJS, ou tout simplement Cargo.toml en Rust, avec cargo); et la génération du dépôt git.

Après quoi, on en aura enfin fini avec la sous-commande create, et on va pouvoir attaquer les choses vraiment sérieuses avec la prochaine sous-commande !

Mais trêve de blabla, rentrons tout de suite dans le vif du sujet, si vous le voulez bien !

 

Création du fichier de gestion des dépendances : dependencies.bsc 

 

Cette partie va être extrêmement simple, puisqu’il s’agit simplement d’écrire du texte assez banal dans un fichier.

Pour rappel, le but de ce fichier est simplement de lister les modules dont le projet généré C dépend, en renseignant le nom du module, et son lien pour le récupérer (que ce soit un lien local, ou en ligne). Accessoirement, sa version pourra aussi être renseignée, mais cela implique beaucoup de problèmes à gérer, donc de code supplémentaire, ce que je vais volontairement omettre au début (en fixant la version à « 0.1.0 »).

Vous remarquerez peut-être que j’ai décidé de ne pas donner d’extension .json, .yaml, ou .xml à ce fichier, par exemple.

Effectivement, je vais tout simplement créer un fichier de texte classique, avec ma « propre » méthode pour parser et lire le contenu du fichier.

D’une part, je trouve ça plus simple que de devoir sérialiser des données (en json par exemple, cela oblige à dépendre d’un nouveau crate supplémentaire, ou à coder moi-même le parseur…), et d’autre part, je ne vais remplir ce fichier que de quelques informations très simples. Alors pourquoi s’embêter ?

Bref, voici la fonction permettant de créer ce fichier, que je place dans le fichier contenant le code spécifique à tout ce qui touche aux dépendances, dependencies_handler.rs :

pub fn update_dependencies_file(project_url: &str, project_path: &str, project_name: &str){
    let content_dependencies_file = format!(
        "BSC_PROJECT: \
        \n\t[{}]:^0.1.0\t|\t{} \
        \n\nBSC_DEPENDENCIES: \
        \n", &project_name, &project_url
    );

    // To complete

    common::create_file(&project_path, "dependencies.bsc", &content_dependencies_file);
}

 

Premier constat : la fonction ne s’appelle pas create_dependencies_file par exemple, mais bien update_dependencies_file. Pourquoi cela ?

En fait, lorsque je vais par la suite ajouter des sous-commande à bsc (par exemple l’ajout ou la suppression d’un module), je vais devoir mettre à jour les dépendances du projet… Donc mettre à jour ce fichier.

Et pour le mettre à jour et bien… il faut tout simplement réécrire tout son contenu. Cela revient donc à le remplacer par un nouveau fichier.

A chaque appel de cette fonction, j’écrase alors le fichier dependencies.bsc existant, et je le remplace grâce à la ligne :

// Appel de la fonction create_file présente dans le fichier common.rs
common::create_file(&project_path, "dependencies.bsc", &content_dependencies_file);

 

Venons-en maintenant à son contenu.

Comme vous pouvez le constater, la fonction prend peu de paramètres : l’url du projet, permettant de retrouver où il se situe (par défaut, il s’agit du chemin absolu sur le disque dur; dans le cas où le projet est initialisé avec git, et qu’il est bindé sur un dépôt en ligne, alors son url sera celui du dépôt en ligne, tout simplement); le chemin du dossier où il faut créé ce projet (pour nous, cela sera tout le temps le chemin courant : « ./ »); et enfin le nom du projet (renseigné par l’argument de la sous commande bsc create NOM_DU_PROJECT).

Dans la variable de type str  nommée content_dependencies_file, est stocké le contenu du fichier, dont voici le résultat final :

BSC_PROJECT: 
  [bsc_test]:^0.1.0	|	 

BSC_DEPENDENCIES:

 

Nous avons donc le nom du projet entre crochets, suivi de sa version (par défaut, il s’agit de la 0.1.0).

Il y a ensuite sur la même ligne une tabulation, et un caractère spécial : « | ». Cela me permet tout simplement de séparer le nom du projet et sa version, du chemin du projet.

Pour l’instant, ce dernier n’est pas renseigné, mais il sera ajouté après ce caractère spécial, suivi d’une autre tabulation.

Par la suite, il sera alors facile de retrouver ce chemin, puisque j’aurais tout simplement à ouvrir le fichier, lire la deuxième ligne, et récupérer ce qui se trouve derrière le caractère spécial « | » et la tabulation. Simple et efficace !

Enfin, en dessous de BSC_DEPENDENCIES: se trouvera la liste des modules dont dépend le projet, sur le même principe que la deuxième ligne. Par exemple, si le projet C dépend d’un module du nom de toto, disponible depuis un dépôt git distant (par exemple sur github : https://github.com/toto_example/toto), cela donnera :

BSC_PROJECT: 
    [bsc_test]:^0.1.0    |	 

BSC_DEPENDENCIES: 
    [toto]:^0.1.1    |    https://github.com/toto_example/toto

 

Le code nécessaire à l’ajout de lignes de ce type dans ce fichier (ou de leur suppression), sera renseigné par la suite à la place du commentaire « // To complete » de la fonction :

pub fn update_dependencies_file(project_url: &str, project_path: &str, project_name: &str){
    let content_dependencies_file = format!(
        "BSC_PROJECT: \
        \n\t[{}]:^0.1.0\t|\t{} \
        \n\nBSC_DEPENDENCIES: \
        \n", &project_name, &project_url
    );

    // Le code permettant de générer ou de supprimer des lignes 
    // concernant les modules dont dépend le projet 
    // sera ajouté juste ici !
    // To complete

    common::create_file(&project_path, "dependencies.bsc", &content_dependencies_file);
}

 

Voilà, rien de bien compliqué pour le moment donc, concernant ce fichier de gestion des dépendances du projet !

Passons maintenant enfin à la toute dernière étape de la sous-commande bsc create.

 

Initialisation du dépôt git

 

Pour initialiser un dépôt git, plusieurs solutions sont possibles.

Soit je peux appeler la commande git inittout simplement, à l’aide de la structure de la librairie standard std::process::Command, soit je peux utiliser un binding Rust des fonctions git.

Je me suis tourné vers cette dernière solution, puisque je trouve que c’est la plus pertinente. En effet, le problème avec l’appel de commandes, c’est que cela a tendance à ralentir le programme, et surtout, si la commande n’existe pas (ou qu’il n’y a pas le bon PATH pour la variable d’environnement par exemple, selon les choix de l’utilisateur…) cela peut ne pas fonctionner.

Bref, comme je me suis dit qu’en plus, ce binding devait déjà être utilisé dans plusieurs programme, il devait sûrement déjà exister un crate pour gérer les appels aux fonctions git.

Je me suis donc rendu sur crates.io, et quelques minutes plus tard, j’avais effectivement trouvé un crate génial et très simple : git2 (la première version, nommée tout simplement git est abandonnée).

Même principe que pour clap, j’ajoute donc simplement une ligne, en dessous de [dependencies] dans mon fichier Cargo.toml, à la racine de mon projet Rust, pour pouvoir utiliser ce crate :

[dependencies]
indicatif = "0.9.0"
console = "0.6.1"
clap = "2.32.0"
// Ajout de la ligne suivante pour
// utiliser le crate git2
git2 = "0.7.5"

 

Pour finir, je place également l’instruction extern crate git2 en haut de mon fichier create.rs, et tout est bon !

 // L'instruction nécessaire pour inclure
// le code du crate et pour pouvoir l'utiliser dans ce fichier
extern crate git2;
#[path = "common.rs"] mod common;
use std::error::Error;
...

 

Je peux maintenant directement utiliser le code du crate git2, et en me basant sur sa documentation, il m’a seulement fallu quelques minutes pour écrire la fonction initialize_git suivante :

pub fn initialize_git(path_repository: &str){
    match git2::Repository::init(&path_repository){
        Err(why) => panic!("Error: failed to create the git repository. {}", why.description()),
        Ok(_) => (),
    };

    println!("The git repository is correctly initialized.");
}

 

Je passe en paramètre le chemin du dépôt git (donc le dossier courant dans notre cas « ./ »), et j’appelle la fonction init de git2, en gérant le cas d’une erreur éventuelle.

Bref, c’est simple, propre, intuitif. Tout ce que j’aime !

Et voilà qui termine donc toute la partie de cette série concernant la sous-commande create permettant de générer un nouveau projet en C.

Dorénavant, si on effectue les commandes suivantes :

// je créé le dossier bsc_test
// dans le répertoire courant
$ mkdir bsc_test

// je me place dedans
$ cd bsc_test

// j'appelle la sous-commande
// toto de bsc 
// (j'ai ajouté le programme à la variable d'environement PATH)
$ bsc create toto

Project name: toto
The git repository is correctly initialized.
The project is correclty created.

// je liste les dossiers et fichiers du dossier courant,
// et j'obtiens tout ce que bsc create a généré
$ ls

bsc_modules  CMakeLists.txt  dependencies.bsc  include  src  test

 

On a bien tout ce dont on a besoin pour commencer un nouveau projet C !

On peut d’ailleurs tester que le code de base (Hello World) des configurations src (standard), et test (tests fonctionnels) compile correctement :

// je créé un dossier "build" qui contiendra
// les fichiers relatifs au build
$ mkdir build

// je me place dedans
$ cd build

// je génère les fichiers de build Ninja (un système de build parmi beaucoup d'autres)
// à l'aide de cmake, en précisant que je souhaite une version
// de release (et non de debug)
// Les ".." servent à indiquer que le fichier d'entrée pour cmake 
// (le CMakeLists.txt global) se situe dans le dossier parent
$ cmake .. -G NINJA -DCMAKE_BUILD_TYPE:String=Release

-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: C:/tools/mingw64/bin/gcc.exe
-- Check for working C compiler: C:/tools/mingw64/bin/gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/tools/mingw64/bin/c++.exe
-- Check for working CXX compiler: C:/tools/mingw64/bin/c++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Projects/bsc_test/build


// pour finir, je compile enfin mes deux configurations (src et test)
$ cmake --build . --config Release

[4/4] Linking C executable src\bin\Release\toto.exe

 

Tout s’est bien passé !

On peut donc maintenant retrouver nos deux programmes compilés, qui, pour l’instant devraient afficher exactement la même chose. Par rapport à notre dossier build, l’un est situé dans le dossier ./src/bin/Release/, et l’autre dans ./test/bin/Release/.

Et si on les lance, on a bien :

$ ./src/bin/Release/toto.exe

Hello World !


$ ./test/bin/Release/toto.exe

Hello World !

 

On en a donc maintenant vraiment terminé avec la sous-commande create, et cela clôture également cet article.

Comme d’habitude, j’espère que cet article vous a paru intéressant, et je vous remercie sincèrement d’avoir pris le temps de le lire jusqu’au bout.

Si vous avez des remarques, ou des objections à me partager, je serai encore une fois heureux de pouvoir les lire via les commentaires ci-dessous.

Enfin, pour conclure, puisqu’on en a terminé avec la création du squelette du projet, sachez que dans la prochaine partie de cette série, on s’attaquera à du lourd : une nouvelle sous-commande, l’ajout de dépendance !

 

 

Merci d’avoir pris le temps de lire cet article. Est-ce que cela vous a intéressé ? Est-ce que vous avez appris quelque chose ? N’hésitez pas à me partager votre opinion sur le sujet via les commentaires ci-dessous.

Et si vous aimez ce contenu, vous pouvez vous abonnez à ma newsletter (si le coeur vous en dit), afin de rester informé des dernières nouveautés du blog, et également pour recevoir (pas plus d’une fois par semaine), d’autres contenus que je juge intéressant sur tout ce qui touche la programmation ou le développement personnel.

Inscription à la newsletter :

[newsletter]
Victor Gallet

Victor Gallet

Étudiant programmeur jeu vidéo. J'aime par dessus tout apprendre, et je suis un éternel curieux de tout. Mon principal but dans la vie est d’être une meilleure personne, et de partager mes (faibles) connaissances avec les autres.

Leave a Reply

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.