Publicar una caja en Crates.io

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Bienvenido a Publicar un Caja a Crates.io. Esta práctica es parte del Libro de Rust. Puedes practicar tus habilidades de Rust en LabEx.

En esta práctica, discutiremos cómo publicar una caja a crates.io, el registro de cajas que distribuye código fuente abierto, lo que facilita la búsqueda y el uso de tu paquete por parte de otras personas.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-100428{{"Publicar una caja en Crates.io"}} rust/integer_types -.-> lab-100428{{"Publicar una caja en Crates.io"}} rust/function_syntax -.-> lab-100428{{"Publicar una caja en Crates.io"}} rust/expressions_statements -.-> lab-100428{{"Publicar una caja en Crates.io"}} rust/operator_overloading -.-> lab-100428{{"Publicar una caja en Crates.io"}} end

Publicar un Caja a Crates.io

Hemos utilizado paquetes de https://crates.io como dependencias de nuestro proyecto, pero también puedes compartir tu código con otras personas publicando tus propios paquetes. El registro de cajas en https://crates.io distribuye el código fuente de tus paquetes, por lo que alberga principalmente código que es de código abierto.

Rust y Cargo tienen características que facilitan la búsqueda y el uso de tu paquete publicado por otras personas. Hablaremos sobre algunas de estas características a continuación y luego explicaremos cómo publicar un paquete.

Escribir Comentarios de Documentación Útiles

Documentar con precisión tus paquetes ayudará a otros usuarios a saber cómo y cuándo utilizarlos, por lo que vale la pena invertir el tiempo en escribir documentación. En el Capítulo 3, discutimos cómo comentar el código de Rust utilizando dos barras, //. Rust también tiene un tipo particular de comentario para la documentación, conocido convenientemente como comentario de documentación, que generará documentación HTML. La documentación HTML muestra el contenido de los comentarios de documentación para los elementos de la API pública destinados a los programadores interesados en saber cómo utilizar tu caja en lugar de cómo tu caja está implementada.

Los comentarios de documentación utilizan tres barras, ///, en lugar de dos y admiten la notación Markdown para formatear el texto. Coloca los comentarios de documentación justo antes del elemento que estás documentando. La Lista 14-1 muestra comentarios de documentación para una función add_one en una caja llamada my_crate.

Nombre del archivo: src/lib.rs

/// Suma uno al número dado.
///
/// ## Ejemplos
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```rust
pub fn add_one(x: i32) -> i32 {
    x + 1
}

Lista 14-1: Un comentario de documentación para una función

Aquí, damos una descripción de lo que hace la función add_one, comenzamos una sección con el título Ejemplos y luego proporcionamos código que demuestra cómo utilizar la función add_one. Podemos generar la documentación HTML a partir de este comentario de documentación ejecutando cargo doc. Este comando ejecuta la herramienta rustdoc distribuida con Rust y coloca la documentación HTML generada en el directorio target/doc.

Para mayor comodidad, ejecutar cargo doc --open construirá el HTML para la documentación de tu caja actual (además de la documentación de todas las dependencias de tu caja) y abrirá el resultado en un navegador web. Navega hasta la función add_one y verás cómo se muestra el texto de los comentarios de documentación, como se muestra en la Figura 14-1.

Figura 14-1: Documentación HTML para la función add_one

Secciones Comúnmente Utilizadas

Usamos el encabezado de Markdown ## Ejemplos en la Lista 14-1 para crear una sección en el HTML con el título "Ejemplos". Aquí hay algunas otras secciones que los autores de cajas suelen utilizar en su documentación:

  • Panics: Los escenarios en los que la función que se está documentando podría causar un panic. Los llamantes de la función que no quieren que su programa se detenga con un panic deben asegurarse de no llamar a la función en estas situaciones.
  • Errores: Si la función devuelve un Result, describir los tipos de errores que pueden ocurrir y las condiciones que pueden causar que se devuelvan esos errores puede ser útil para los llamantes, para que puedan escribir código para manejar los diferentes tipos de errores de diferentes maneras.
  • Seguridad: Si la función es unsafe para llamar (discutiremos la inseguridad en el Capítulo 19), debe haber una sección que explique por qué la función es insegura y cubra las invariantes que la función espera que los llamantes mantengan.

La mayoría de los comentarios de documentación no necesitan todas estas secciones, pero esta es una buena lista de verificación para recordarte los aspectos de tu código en los que los usuarios estarán interesados en saber.

Comentarios de Documentación como Pruebas

Agregar bloques de código de ejemplo en tus comentarios de documentación puede ayudar a demostrar cómo utilizar tu biblioteca, y hacer eso tiene un bono adicional: ejecutar cargo test ejecutará los ejemplos de código en tu documentación como pruebas. Nada es mejor que documentación con ejemplos. Pero nada es peor que ejemplos que no funcionan porque el código ha cambiado desde que se escribió la documentación. Si ejecutamos cargo test con la documentación de la función add_one de la Lista 14-1, veremos una sección en los resultados de las pruebas que se ve así:

   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

Ahora, si cambiamos ya sea la función o el ejemplo para que el assert_eq! en el ejemplo lance un panic y ejecutamos cargo test nuevamente, veremos que las pruebas de documentación detectan que el ejemplo y el código están desincronizados entre sí.

Comentando Elementos Contenidos

El comentario de documentación //! agrega documentación al elemento que contiene los comentarios en lugar de a los elementos que siguen a los comentarios. Por lo general, usamos estos comentarios de documentación dentro del archivo raíz de la caja (src/lib.rs por convención) o dentro de un módulo para documentar la caja o el módulo en su conjunto.

Por ejemplo, para agregar documentación que describa el propósito de la caja my_crate que contiene la función add_one, agregamos comentarios de documentación que empiecen con //! al principio del archivo src/lib.rs, como se muestra en la Lista 14-2.

Nombre del archivo: src/lib.rs

//! ## Mi Caja
//!
//! `my_crate` es una colección de utilidades para hacer más
//! conveniente la realización de ciertos cálculos.

/// Suma uno al número dado.
--snip--

Lista 14-2: Documentación para la caja my_crate en su conjunto

Observa que no hay ningún código después de la última línea que comienza con //!. Debido a que comenzamos los comentarios con //! en lugar de ///, estamos documentando el elemento que contiene este comentario en lugar de un elemento que sigue a este comentario. En este caso, ese elemento es el archivo src/lib.rs, que es la raíz de la caja. Estos comentarios describen toda la caja.

Cuando ejecutamos cargo doc --open, estos comentarios se mostrarán en la página principal de la documentación de my_crate encima de la lista de elementos públicos de la caja, como se muestra en la Figura 14-2.

Figura 14-2: Documentación renderizada de my_crate, incluyendo el comentario que describe la caja en su conjunto

Los comentarios de documentación dentro de los elementos son útiles especialmente para describir cajas y módulos. úsalos para explicar el propósito general del contenedor y ayudar a tus usuarios a entender la organización de la caja.

Exportando una API Pública Conveniente con pub use

La estructura de tu API pública es una consideración importante al publicar una caja. Las personas que usan tu caja son menos familiarizadas con la estructura que tú y pueden tener dificultades para encontrar los componentes que desean usar si tu caja tiene una gran jerarquía de módulos.

En el Capítulo 7, cubrimos cómo hacer que los elementos sean públicos utilizando la palabra clave pub y cómo traer elementos a un ámbito con la palabra clave use. Sin embargo, la estructura que tiene sentido para ti mientras desarrollas una caja puede no ser muy conveniente para tus usuarios. Puedes querer organizar tus structs en una jerarquía que contenga varios niveles, pero luego las personas que quieran usar un tipo que has definido profundamente en la jerarquía pueden tener problemas para descubrir que existe ese tipo. También pueden molestarles tener que escribir use my_crate::algún_módulo::otro_módulo::TipoÚtil; en lugar de use my_crate::TipoÚtil;.

La buena noticia es que si la estructura no es conveniente para que otros la usen desde otra biblioteca, no tienes que reorganizar tu organización interna: en cambio, puedes re-exportar elementos para crear una estructura pública diferente a tu estructura privada utilizando pub use. Re-exportar toma un elemento público en un lugar y lo hace público en otro lugar, como si estuviera definido en el otro lugar en lugar de aquí.

Por ejemplo, digamos que creamos una biblioteca llamada art para modelar conceptos artísticos. Dentro de esta biblioteca hay dos módulos: un módulo kinds que contiene dos enum denominados PrimaryColor y SecondaryColor y un módulo utils que contiene una función llamada mix, como se muestra en la Lista 14-3.

Nombre del archivo: src/lib.rs

//! ## Arte
//!
//! Una biblioteca para modelar conceptos artísticos.

pub mod kinds {
    /// Los colores primarios de acuerdo con el modelo de color RYB.
    pub enum PrimaryColor {
        Red,
        Yellow,
        Blue,
    }

    /// Los colores secundarios de acuerdo con el modelo de color RYB.
    pub enum SecondaryColor {
        Orange,
        Green,
        Purple,
    }
}

pub mod utils {
    use crate::kinds::*;

    /// Combina dos colores primarios en cantidades iguales para crear
    /// un color secundario.
    pub fn mix(
        c1: PrimaryColor,
        c2: PrimaryColor,
    ) -> SecondaryColor {
        --snip--
    }
}

Lista 14-3: Una biblioteca art con elementos organizados en los módulos kinds y utils

La Figura 14-3 muestra cómo se vería la página principal de la documentación de esta caja generada por cargo doc.

Figura 14-3: Página principal de la documentación de art que lista los módulos kinds y utils

Observa que los tipos PrimaryColor y SecondaryColor no se listan en la página principal, ni tampoco la función mix. Tenemos que hacer clic en kinds y utils para verlos.

Otra caja que depende de esta biblioteca necesitaría declaraciones use que traigan los elementos de art al ámbito, especificando la estructura de módulos que se define actualmente. La Lista 14-4 muestra un ejemplo de una caja que utiliza los elementos PrimaryColor y mix de la caja art.

Nombre del archivo: src/main.rs

use art::kinds::PrimaryColor;
use art::utils::mix;

fn main() {
    let red = PrimaryColor::Red;
    let yellow = PrimaryColor::Yellow;
    mix(red, yellow);
}

Lista 14-4: Una caja que utiliza los elementos de la caja art con su estructura interna exportada

El autor del código de la Lista 14-4, que utiliza la caja art, tuvo que averiguar que PrimaryColor está en el módulo kinds y mix está en el módulo utils. La estructura de módulos de la caja art es más relevante para los desarrolladores que trabajan en la caja art que para aquellos que la usan. La estructura interna no contiene ninguna información útil para alguien que intenta entender cómo usar la caja art, sino que más bien causa confusión porque los desarrolladores que la usan tienen que averiguar dónde buscar y deben especificar los nombres de los módulos en las declaraciones use.

Para eliminar la organización interna de la API pública, podemos modificar el código de la caja art de la Lista 14-3 para agregar declaraciones pub use para re-exportar los elementos en el nivel superior, como se muestra en la Lista 14-5.

Nombre del archivo: src/lib.rs

//! ## Arte
//!
//! Una biblioteca para modelar conceptos artísticos.

pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;

pub mod kinds {
    --snip--
}

pub mod utils {
    --snip--
}

Lista 14-5: Agregando declaraciones pub use para re-exportar elementos

La documentación de API que cargo doc genera para esta caja ahora listará y enlazará los re-exports en la página principal, como se muestra en la Figura 14-4, lo que hace que los tipos PrimaryColor y SecondaryColor y la función mix sean más fáciles de encontrar.

Figura 14-4: La página principal de la documentación de art que lista los re-exports

Los usuarios de la caja art todavía pueden ver y usar la estructura interna de la Lista 14-3 como se demuestra en la Lista 14-4, o pueden usar la estructura más conveniente de la Lista 14-5, como se muestra en la Lista 14-6.

Nombre del archivo: src/main.rs

use art::mix;
use art::PrimaryColor;

fn main() {
    --snip--
}

Lista 14-6: Un programa que utiliza los elementos re-exportados de la caja art

En casos donde hay muchos módulos anidados, re-exportar los tipos en el nivel superior con pub use puede marcar una gran diferencia en la experiencia de las personas que usan la caja. Otro uso común de pub use es re-exportar definiciones de una dependencia en la caja actual para que las definiciones de esa caja formen parte de la API pública de tu caja.

Crear una estructura de API pública útil es más un arte que una ciencia, y puedes iterar para encontrar la API que funcione mejor para tus usuarios. Elegir pub use te da flexibilidad en cómo estructuras tu caja internamente y desacopla esa estructura interna de lo que presentas a tus usuarios. Echa un vistazo al código de algunas de las cajas que has instalado para ver si su estructura interna difiere de su API pública.

Configurando una Cuenta en Crates.io

Antes de publicar cualquier caja, debes crear una cuenta en https://crates.io y obtener un token de API. Para hacer eso, visita la página principal en https://crates.io y inicia sesión a través de una cuenta de GitHub. (La cuenta de GitHub es actualmente un requisito, pero en el futuro el sitio puede admitir otros métodos de creación de una cuenta.) Una vez que hayas iniciado sesión, visita tus ajustes de cuenta en https://crates.io/me y recupera tu clave API. Luego ejecuta el comando cargo login con tu clave API, como se muestra a continuación:

cargo login abcdefghijklmnopqrstuvwxyz012345

Este comando informará a Cargo de tu token de API y lo almacenará localmente en ~/.cargo/credentials. Tenga en cuenta que este token es un secreto: no lo comparta con nadie más. Si lo comparte con alguien por cualquier motivo, debería revocarlo y generar un nuevo token en https://crates.io.

Agregando Metadatos a una Nueva Caja

Digamos que tienes una caja que quieres publicar. Antes de publicar, necesitarás agregar algunos metadatos en la sección [package] del archivo Cargo.toml de la caja.

Tu caja necesitará un nombre único. Mientras estás trabajando en una caja localmente, puedes nombrar la caja como quieras. Sin embargo, los nombres de las cajas en https://crates.io se asignan en un primer llegado, primer servido. Una vez que se ha tomado un nombre de caja, nadie más puede publicar una caja con ese nombre. Antes de intentar publicar una caja, busca el nombre que quieres usar. Si el nombre ya ha sido utilizado, necesitarás encontrar otro nombre y editar el campo name en el archivo Cargo.toml en la sección [package] para usar el nuevo nombre para la publicación, como se muestra a continuación:

Nombre del archivo: Cargo.toml

[package]
name = "guessing_game"

Incluso si has elegido un nombre único, cuando ejecutes cargo publish para publicar la caja en este momento, recibirás una advertencia y luego un error:

$ 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: missing or empty metadata fields:
description, license. Please see https://doc.rust-
lang.org/cargo/reference/manifest.html for how to upload metadata

Esto resulta en un error porque te falta información crucial: se requiere una descripción y una licencia para que las personas sepan lo que hace tu caja y bajo qué términos pueden usarla. En Cargo.toml, agrega una descripción que sea de una o dos frases, porque aparecerá con tu caja en los resultados de búsqueda. Para el campo license, necesitas dar un valor de identificador de licencia. El Software Package Data Exchange (SPDX) de The Linux Foundation en http://spdx.org/licenses lista los identificadores que puedes usar para este valor. Por ejemplo, para especificar que has licenciado tu caja con la Licencia MIT, agrega el identificador MIT:

Nombre del archivo: Cargo.toml

[package]
name = "guessing_game"
license = "MIT"

Si quieres usar una licencia que no aparece en el SPDX, debes colocar el texto de esa licencia en un archivo, incluir el archivo en tu proyecto y luego usar license-file para especificar el nombre de ese archivo en lugar de usar la clave license.

La guía sobre qué licencia es adecuada para tu proyecto está fuera del alcance de este libro. Muchas personas en la comunidad de Rust licencian sus proyectos de la misma manera que Rust, utilizando una doble licencia de MIT OR Apache-2.0. Esta práctica demuestra que también puedes especificar múltiples identificadores de licencia separados por OR para tener múltiples licencias para tu proyecto.

Con un nombre único, la versión, tu descripción y una licencia agregadas, el archivo Cargo.toml de un proyecto listo para publicar podría verse así:

Nombre del archivo: Cargo.toml

[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
description = "A fun game where you guess what number the
computer has chosen."
license = "MIT OR Apache-2.0"

[dependencies]

La documentación de Cargo en https://doc.rust-lang.org/cargo describe otros metadatos que puedes especificar para garantizar que los demás puedan descubrir y usar tu caja más fácilmente.

Publicando en Crates.io

Ahora que has creado una cuenta, guardado tu token de API, elegido un nombre para tu caja y especificado los metadatos requeridos, ¡estás listo para publicar! Publicar una caja sube una versión específica a https://crates.io para que otros la usen.

Ten cuidado, porque una publicación es permanente. La versión nunca puede ser sobrescrita y el código no puede ser eliminado. Un objetivo principal de Crates.io es actuar como un archivo permanente de código para que las compilaciones de todos los proyectos que dependen de cajas de https://crates.io continúen funcionando. Permitir la eliminación de versiones haría imposible cumplir ese objetivo. Sin embargo, no hay límite al número de versiones de caja que puedes publicar.

Ejecuta nuevamente el comando cargo publish. Ahora debería tener éxito:

$ cargo publish
    Updating crates.io index
   Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
   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 [unoptimized + debuginfo] target(s) in 0.19s
   Uploading guessing_game v0.1.0 (file:///projects/guessing_game)

¡Felicidades! Ahora has compartido tu código con la comunidad de Rust y cualquiera puede agregar fácilmente tu caja como dependencia de su proyecto.

Publicando una Nueva Versión de una Caja Existente

Cuando has realizado cambios en tu caja y estás listo para lanzar una nueva versión, cambias el valor de version especificado en tu archivo Cargo.toml y vuelves a publicar. Utiliza las reglas de Semantic Versioning en http://semver.org para decidir cuál es un número de versión siguiente adecuado, basado en los tipos de cambios que has realizado. Luego ejecuta cargo publish para subir la nueva versión.

Desestimando Versiones de Crates.io con cargo yank

Aunque no puedes eliminar versiones anteriores de una caja, puedes evitar que futuros proyectos la agreguen como una nueva dependencia. Esto es útil cuando una versión de una caja está rota por una u otra razón. En tales situaciones, Cargo admite desestimar una versión de una caja.

Desestimar una versión impide que nuevos proyectos dependan de esa versión mientras permite que todos los proyectos existentes que dependen de ella continúen. Esencialmente, un desestimado significa que todos los proyectos con un Cargo.lock no se romperán y cualquier archivo Cargo.lock generado en el futuro no usará la versión desestimada.

Para desestimar una versión de una caja, en el directorio de la caja que has publicado previamente, ejecuta cargo yank y especifica qué versión quieres desestimar. Por ejemplo, si hemos publicado una caja llamada guessing_game versión 1.0.1 y queremos desestimarla, en el directorio del proyecto de guessing_game ejecutaríamos:

$ cargo yank --vers 1.0.1
Updating crates.io index
Yank [email protected]

Al agregar --undo al comando, también puedes deshacer un desestimado y permitir que los proyectos vuelvan a depender de una versión:

$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank [email protected]

Un desestimado no elimina ningún código. No puede, por ejemplo, eliminar secretos cargados accidentalmente. Si eso sucede, debes restablecer esos secretos inmediatamente.

Resumen

¡Felicidades! Has completado el laboratorio de Publicación de una Caja en Crates.io. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.