Publier une crate sur Crates.io
Nous avons utilisé des packages de crates.io comme dépendances de nos projets, mais vous pouvez aussi partager votre code avec d’autres personnes en publiant vos propres packages. Le registre des crates sur crates.io distribue le code source de vos packages, il héberge donc principalement le code qui est open source.
Rust et Cargo ont des fonctionnalités qui rendent votre paquet publié plus facile a trouver et à utiliser pour les autres. Nous allons parler de certaines de ces fonctionnalités puis expliquer comment publier un paquet.
Rédiger des commentaires de documentation utiles
Documenter précisément vos paquets aidera les autres utilisateurs a savoir comment et quand les utiliser, donc cela vaut la peine d’investir du temps pour écrire de la documentation. Dans le chapitre 3, nous avons vu comment commenter le code Rust en utilisant deux barres obliques, //. Rust possède également un type particulier de commentaire pour la documentation, connu de maniere pratique sous le nom de commentaire de documentation, qui generera une documentation HTML. Le HTML affiche le contenu des commentaires de documentation pour les éléments de l’API publique, destine aux programmeurs interesses par savoir comment utiliser votre crate par opposition a comment votre crate est implemente.
Les commentaires de documentation utilisent trois barres obliques, ///, au lieu de deux et supportent la notation Markdown pour le formatage du texte. Placez les commentaires de documentation juste avant l’élément qu’ils documentent. L’encart 14-1 montre des commentaires de documentation pour une fonction add_one dans un crate nomme my_crate.
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
Ici, nous donnons une description de ce que fait la fonction add_one, commencons une section avec le titre Examples, puis fournissons du code qui montre comment utiliser la fonction add_one. Nous pouvons générer la documentation HTML à partir de ce commentaire de documentation en exécutant cargo doc. Cette commande exécute l’outil rustdoc distribue avec Rust et place la documentation HTML générée dans le repertoire target/doc.
Par commodite, exécuter cargo doc --open construira le HTML de la documentation de votre crate actuel (ainsi que la documentation de toutes les dépendances de votre crate) et ouvrira le résultat dans un navigateur web. Naviguez vers la fonction add_one et vous verrez comment le texte des commentaires de documentation est rendu, comme montre dans la figure 14-1.
Figure 14-1 : La documentation HTML de la fonction add_one
Sections couramment utilisees
Nous avons utilise le titre Markdown # Examples dans l’encart 14-1 pour créer une section dans le HTML avec le titre “Examples”. Voici d’autres sections que les auteurs de crates utilisent couramment dans leur documentation :
- Panics : ce sont les scenarios dans lesquels la fonction documentee pourrait paniquer. Les appelants de la fonction qui ne veulent pas que leurs programmes paniquent doivent s’assurer de ne pas appeler la fonction dans ces situations.
- Errors : si la fonction retourné un
Result, décrire les types d’erreurs qui pourraient survenir et quelles conditions pourraient provoquer le retour de ces erreurs peut être utile aux appelants afin qu’ils puissent écrire du code pour gérer les différents types d’erreurs de différentes manieres. - Safety : si la fonction est
unsafea appeler (nous discutons de l’unsafety dans le chapitre 20), il devrait y avoir une section expliquant pourquoi la fonction est unsafe et couvrant les invariants que la fonction attend des appelants qu’ils respectent.
La plupart des commentaires de documentation n’ont pas besoin de toutes ces sections, mais c’est une bonne liste de vérification pour vous rappeler les aspects de votre code que les utilisateurs seront interesses a connaitre.
Les commentaires de documentation comme tests
Ajouter des blocs de code d’exemple dans vos commentaires de documentation peut aider a montrer comment utiliser votre bibliothèque et offre un avantage supplementaire : exécuter cargo test exécutera les exemples de code dans votre documentation comme des tests ! Rien n’est mieux que de la documentation avec des exemples. Mais rien n’est pire que des exemples qui ne fonctionnent pas parce que le code a change depuis que la documentation a été écrite. Si nous exécutons cargo test avec la documentation de la fonction add_one de l’encart 14-1, nous verrons une section dans les résultats de test qui ressemble a ceci :
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
Maintenant, si nous modifions soit la fonction soit l’exemple de sorte que le assert_eq! dans l’exemple panique, et exécutons cargo test à nouveau, nous verrons que les tests de documentation detectent que l’exemple et le code ne sont plus synchronises !
Les commentaires d’éléments conteneurs
Le style de commentaire de documentation //! ajouté de la documentation à l’élément qui contient les commentaires plutôt qu’aux éléments qui suivent les commentaires. Nous utilisons généralement ces commentaires de documentation à l’intérieur du fichier racine de la crate (src/lib.rs par convention) ou à l’intérieur d’un module pour documenter la crate ou le module dans son ensemble.
Par exemple, pour ajouter de la documentation qui décrit l’objectif du crate my_crate qui contient la fonction add_one, nous ajoutons des commentaires de documentation qui commencent par //! au début du fichier src/lib.rs, comme montre dans l’encart 14-2.
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
/// Adds one to the number given.
// --snip--
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
my_crate crate as a wholeRemarquez qu’il n’y à aucun code après la derniere ligne qui commence par //!. Parce que nous avons commence les commentaires avec //! au lieu de ///, nous documentons l’élément qui contient ce commentaire plutot qu’un élément qui suit ce commentaire. Dans ce cas, cet élément est le fichier src/lib.rs, qui est la racine du crate. Ces commentaires decrivent l’ensemble du crate.
Lorsque nous exécutons cargo doc --open, ces commentaires s’afficheront sur la page d’accueil de la documentation de my_crate au-dessus de la liste des éléments publics du crate, comme montre dans la figure 14-2.
Les commentaires de documentation à l’intérieur des éléments sont utiles pour décrire les crates et les modules en particulier. Utilisez-les pour expliquer l’objectif general du conteneur afin d’aider vos utilisateurs a comprendre l’organisation du crate.
Figure 14-2 : La documentation rendue pour my_crate, incluant le commentaire decrivant le crate dans son ensemble
Exporter une API publique pratique
La structure de votre API publique est une consideration majeure lors de la publication d’un crate. Les personnes qui utilisent votre crate sont moins familieres avec la structure que vous et pourraient avoir des difficultes a trouver les éléments qu’elles veulent utiliser si votre crate à une grande hierarchie de modules.
Dans le chapitre 7, nous avons vu comment rendre des éléments publics en utilisant le mot-clé pub, et comment amener des éléments dans une portée avec le mot-clé use. Cependant, la structure qui a du sens pour vous pendant que vous developpez un crate pourrait ne pas être très pratique pour vos utilisateurs. Vous pourriez vouloir organiser vos structs dans une hierarchie contenant plusieurs niveaux, mais alors les personnes qui veulent utiliser un type que vous avez défini en profondeur dans la hierarchie pourraient avoir du mal a découvrir que ce type existe. Elles pourraient aussi être agacees de devoir écrire use my_crate::some_module::another_module::UsefulType; plutot que use my_crate::UsefulType;.
La bonne nouvelle est que si la structure n’est pas pratique pour que d’autres l’utilisent depuis une autre bibliothèque, vous n’avez pas a reorganiser votre organisation interne : au lieu de cela, vous pouvez re-exporter des éléments pour créer une structure publique différente de votre structure privee en utilisant pub use. La re-exportation prend un élément public à un emplacement et le rend public à un autre emplacement, comme s’il était défini à l’autre emplacement.
Par exemple, supposons que nous ayons crée une bibliothèque nommee art pour modeliser des concepts artistiques. Dans cette bibliothèque se trouvent deux modules : un module kinds contenant deux enums nommes PrimaryColor et SecondaryColor et un module utils contenant une fonction nommee mix, comme montre dans l’encart 14-3.
//! # Art
//!
//! A library for modeling artistic concepts.
pub mod kinds {
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
unimplemented!();
}
}
art library with items organized into kinds and utils modulesLa figure 14-3 montre a quoi ressemblerait la page d’accueil de la documentation de ce crate générée par cargo doc.
Figure 14-3 : La page d’accueil de la documentation pour art qui liste les modules kinds et utils
Notez que les types PrimaryColor et SecondaryColor ne sont pas listes sur la page d’accueil, pas plus que la fonction mix. Nous devons cliquer sur kinds et utils pour les voir.
Un autre crate qui depend de cette bibliothèque aurait besoin d’instructions use qui amenent les éléments d’art dans la portée, en specifiant la structure de modules actuellement définie. L’encart 14-4 montre un exemple de crate qui utilise les éléments PrimaryColor et mix du crate art.
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
art crate’s items with its internal structure exportedL’auteur du code de l’encart 14-4, qui utilise le crate art, a du comprendre que PrimaryColor est dans le module kinds et que mix est dans le module utils. La structure de modules du crate art est plus pertinente pour les développeurs travaillant sur le crate art que pour ceux qui l’utilisent. La structure interne ne contient aucune information utile pour quelqu’un essayant de comprendre comment utiliser le crate art, mais cause plutot de la confusion car les développeurs qui l’utilisent doivent comprendre ou chercher et doivent spécifier les noms de modules dans les instructions use.
Pour retirer l’organisation interne de l’API publique, nous pouvons modifier le code du crate art de l’encart 14-3 pour ajouter des instructions pub use afin de re-exporter les éléments au niveau supérieur, comme montre dans l’encart 14-5.
//! # Art
//!
//! A library for modeling artistic concepts.
pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;
pub mod kinds {
// --snip--
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
// --snip--
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
SecondaryColor::Orange
}
}
pub use statements to re-export itemsLa documentation de l’API que cargo doc génère pour ce crate listera et liera desormais les re-exportations sur la page d’accueil, comme montre dans la figure 14-4, rendant les types PrimaryColor et SecondaryColor et la fonction mix plus faciles a trouver.
Figure 14-4 : La page d’accueil de la documentation pour art qui liste les re-exportations
Les utilisateurs du crate art peuvent toujours voir et utiliser la structure interne de l’encart 14-3 comme demontre dans l’encart 14-4, ou ils peuvent utiliser la structure plus pratique de l’encart 14-5, comme montre dans l’encart 14-6.
use art::PrimaryColor;
use art::mix;
fn main() {
// --snip--
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
art crateDans les cas où il y a de nombreux modules imbriques, re-exporter les types au niveau supérieur avec pub use peut faire une différence significative dans l’experience des personnes qui utilisent le crate. Une autre utilisation courante de pub use est de re-exporter les définitions d’une dépendance dans le crate actuel pour faire de ces définitions une partie de l’API publique de votre crate.
Créer une structure d’API publique utile est plus un art qu’une science, et vous pouvez iterer pour trouver l’API qui fonctionne le mieux pour vos utilisateurs. Choisir pub use vous donne de la flexibilite dans la façon dont vous structurez votre crate en interne et decouple cette structure interne de ce que vous presentez a vos utilisateurs. Examinez le code de certains crates que vous avez installés pour voir si leur structure interne diffère de leur API publique.
Configurer un compte Crates.io
Avant de pouvoir publier des crates, vous devez créer un compte sur crates.io et obtenir un jeton d’API. Pour ce faire, visitez la page d’accueil de crates.io et connectez-vous via un compte GitHub. (Le compte GitHub est actuellement une exigence, mais le site pourrait supporter d’autres moyens de créer un compte à l’avenir.) Une fois connecté, visitez les paramètres de votre compte à https://crates.io/me/ et récupérez votre clé d’API. Ensuite, exécutez la commande cargo login et collez votre clé d’API lorsqu’elle est demandée, comme ceci{N}:
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
Cette commande informera Cargo de votre jeton d’API et le stockera localement dans ~/.cargo/credentials.toml. Notez que ce jeton est un secret : ne le partagez avec personne. Si vous le partagez avec quelqu’un pour quelque raison que ce soit, vous devez le revoquer et générer un nouveau jeton sur crates.io.
Ajouter des metadonnees à un nouveau crate
Supposons que vous avez un crate que vous souhaitez publier. Avant de publier, vous devrez ajouter des metadonnees dans la section [package] du fichier Cargo.toml du crate.
Votre crate aura besoin d’un nom unique. Pendant que vous travaillez sur un crate localement, vous pouvez nommer le crate comme vous le souhaitez. Cependant, les noms de crates sur crates.io sont attribues selon le principe du premier arrive, premier servi. Une fois qu’un nom de crate est pris, personne d’autre ne peut publier un crate avec ce nom. Avant de tenter de publier un crate, recherchez le nom que vous souhaitez utiliser. Si le nom a déjà été utilise, vous devrez trouver un autre nom et modifier le champ name dans le fichier Cargo.toml sous la section [package] pour utiliser le nouveau nom pour la publication, comme ceci :
Fichier : Cargo.toml
[package]
name = "guessing_game"
Même si vous avez choisi un nom unique, lorsque vous exécutez cargo publish pour publier le crate à ce stade, vous obtiendrez un avertissement puis une erreur :
$ cargo publish
Updating crates.io index
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
--snip--
error: failed to publish to registry at https://crates.io
Caused by:
the remote server responded with an error (status 400 Bad Request): missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for more information on configuring these fields
Cela entraine une erreur car il vous manque des informations cruciales : une description et une licence sont requises pour que les gens sachent ce que fait votre crate et sous quelles conditions ils peuvent l’utiliser. Dans Cargo.toml, ajoutez une description d’une où deux phrases, car elle apparaîtra avec votre crate dans les résultats de recherche. Pour le champ license, vous devez donner une valeur d’identifiant de licence. Le [Software Package Data Exchange (SPDX) de la Linux Foundation][spdx] liste les identifiants que vous pouvez utiliser pour cette valeur. Par exemple, pour spécifier que vous avez licencie votre crate sous la licence MIT, ajoutez l’identifiant MIT :
Fichier : Cargo.toml
[package]
name = "guessing_game"
license = "MIT"
Si vous souhaitez utiliser une licence qui n’apparaît pas dans le SPDX, vous devez placer le texte de cette licence dans un fichier, inclure le fichier dans votre projet, puis utiliser license-file pour spécifier le nom de ce fichier au lieu d’utiliser la clé license.
Les conseils sur la licence appropriee pour votre projet depassent le cadre de ce livre. De nombreuses personnes dans la communauté Rust licencient leurs projets de la même maniere que Rust en utilisant une double licence MIT OR Apache-2.0. Cette pratique demontre que vous pouvez également spécifier plusieurs identifiants de licence séparés par OR pour avoir plusieurs licences pour votre projet.
Avec un nom unique, la version, votre description et une licence ajoutée, le fichier Cargo.toml d’un projet prêt a être publié pourrait ressembler a ceci :
Fichier : Cargo.toml
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2024"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
La documentation de Cargo décrit d’autres metadonnees que vous pouvez spécifier pour vous assurer que d’autres puissent découvrir et utiliser votre crate plus facilement.
Publier sur Crates.io
Maintenant que vous avez crée un compte, sauvegarde votre jeton d’API, choisi un nom pour votre crate et spécifié les metadonnees requises, vous etes prêt a publier ! Publier un crate televerse une version spécifique sur crates.io pour que d’autres puissent l’utiliser.
Soyez prudent, car une publication est permanente. La version ne peut jamais être ecrasee, et le code ne peut pas être supprime sauf dans certaines circonstances. Un objectif majeur de Crates.io est d’agir comme une archive permanente de code afin que les compilations de tous les projets qui dependent de crates de crates.io continuent de fonctionner. Permettre la suppression de versions rendrait impossible la realisation de cet objectif. Cependant, il n’y a pas de limite au nombre de versions de crate que vous pouvez publier.
Exécutez à nouveau la commande cargo publish. Elle devrait réussir maintenant :
$ cargo publish
Updating crates.io index
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Packaged 6 files, 1.2KiB (895.0B compressed)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
Uploaded guessing_game v0.1.0 to registry `crates-io`
note: waiting for `guessing_game v0.1.0` to be available at registry
`crates-io`.
You may press ctrl-c to skip waiting; the crate should be available shortly.
Published guessing_game v0.1.0 at registry `crates-io`
Felicitations ! Vous avez maintenant partage votre code avec la communauté Rust, et n’importe qui peut facilement ajouter votre crate comme dépendance de son projet.
Publier une nouvelle version d’un crate existant
Lorsque vous avez apporte des modifications à votre crate et que vous etes prêt a publier une nouvelle version, vous modifiez la valeur version spécifiée dans votre fichier Cargo.toml et republiez. Utilisez les [règles de versionnage sémantique][semver] pour decider quel est le numéro de version suivant approprie, en fonction des types de modifications que vous avez apportees. Ensuite, exécutez cargo publish pour televerser la nouvelle version.
Deprecier des versions de Crates.io
Bien que vous ne puissiez pas supprimer les versions précédentes d’un crate, vous pouvez empecher tout futur projet de les ajouter comme nouvelle dépendance. Cela est utile lorsqu’une version de crate est cassee pour une raison ou une autre. Dans de telles situations, Cargo supporté le retrait (yank) d’une version de crate.
Retirer (yank) une version empeche les nouveaux projets de dependre de cette version tout en permettant à tous les projets existants qui en dependent de continuer. Essentiellement, un yank signifie que tous les projets avec un Cargo.lock ne seront pas casses, et que tout futur fichier Cargo.lock génère n’utilisera pas la version retiree.
Pour retirer une version d’un crate, dans le repertoire du crate que vous avez precedemment publié, exécutez cargo yank et specifiez quelle version vous souhaitez retirer. Par exemple, si nous avons publié un crate nomme guessing_game version 1.0.1 et que nous voulons le retirer, nous executerions la commande suivante dans le repertoire du projet guessing_game :
$ cargo yank --vers 1.0.1
Updating crates.io index
Yank guessing_game@1.0.1
En ajoutant --undo à la commande, vous pouvez également annuler un retrait et permettre aux projets de dependre à nouveau d’une version :
$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank guessing_game@1.0.1
Un retrait ne supprime pas de code. Il ne peut pas, par exemple, supprimer des secrets accidentellement televerses. Si cela arrive, vous devez reinitialiser ces secrets immediatement.