11 noviembre 2021

Cómo empaquetar aplicaciones Rust - Paquetes DEB


El lenguaje Rust es duro y áspero. Tu primer contacto con el compilador y con el borrow checker suele ser traumático hasta que te das cuenta de que en realidad están allí para protegerte de ti mismo. Una vez que tienes esa revelación empiezas a adorar a ese lenguaje.

Pero todo lo que está más allá del lenguaje en si mismo es amable (incluso diría que cómodo). Con cargo, compilar, probar, documentar, medir e incluso publicar en crates.io (el equivalente a Pypi en Rust) es una gozada. El empaquetado no es una excepción ya que se integra con cargo, una vez hecha la configuración que vamos a ver aquí.

Para empaquetar mi aplicación Rust en paqueted debian, utilizo cargo-deb. Para instalarlo sólo hay que teclear:

dante@Camelot:~~/Projects/cifra-rust/$ cargo install cargo-deb
Updating crates.io index
Downloaded cargo-deb v1.32.0
Downloaded 1 crate (63.2 KB) in 0.36s
Installing cargo-deb v1.32.0
Downloaded crc v1.8.1
Downloaded build_const v0.2.2
[...]
Compiling crossbeam-deque v0.8.1
Compiling xz2 v0.1.6
Compiling toml v0.5.8
Compiling cargo_toml v0.10.1
Finished release [optimized] target(s) in 53.21s
Installing /home/dante/.cargo/bin/cargo-deb
Installed package `cargo-deb v1.32.0` (executable `cargo-deb`)


dante@Camelot:~$

Hecho eso, ya podemos empezar a empaquetar aplicaciones sencillas. Por defecto, cargo deb saca la información de tu fichero Cargo.toml. De esa manera saca los siguientes campos:

  • name
  • version
  • license
  • license-file
  • description
  • readme
  • homepage
  • repository

Sin embargo, rara vez ocurre que tu aplicación no tiene dependencias en absoluto. Para configurar casos de uso más avanzados hay que crear una sección [package.metadata.deb] en tu Cargo.toml. En esa sección se pueden configurar los siguientes campos:

  • maintainer
  • copyright
  • changelog
  • depends
  • recommends
  • enhances
  • conflicts
  • breaks
  • replaces
  • provides
  • extended-description
  • extended-description-file
  • section
  • priority
  • assets
  • maintainer-scripts

Como ejemplo de todo esto, puedes consultar esta versión del fichero Cargo.toml de mi aplicación Cifra.

Ahí se puede leer la sección general de la que cargo-deb saca su información básica:

 

 

Cargo tiene una gran documentación donde se puede encontrar una explicación para todas las secciones y etiquetas posibles.

Ten en cuenta que cada ruta de ficheros que se incluya en el fichero Cargo.toml es relativa a dicho fichero Cargo.toml.

La sección específica para cargo-deb no necesita muchos parámetros para conseguir un paquete válido:


 

Las etiquetas para esta sección están documentadas en la página principal de cargo-deb.

Las etiquetas section y priority se usan para clasificar la aplicación en la jerarquía de Debian. Aunque en mi configuración las he fijado, creo que no son muy útiles los requisitos para publicar paquetes en los repositorios oficiales de Debian son superiores a los que se pueden conseguir con cargo-deb por el momento, por lo que cualquier paquete generado con cargo-deb acabará casi con total probabilidad en un repositorio personal al que no se le aplicará la jerarquía de debian para las aplicaciones.

En realidad, la etiqueta más importante es la de assets. Esta etiqueta te permite fijar que ficheros deben incluirse en el paquete y dónde deben dejarse al instalar. El formato del contenido de esa etiqueta es sencillo. Se trata de una lista de tuplas de tres elementos:

  • Ruta relativa al fichero a incluir en el paquete: Esa ruta es relativa a la ubicación del fichero Cargo.toml. 
  • Ruta absoluta donde ubicar el fichero en el ordenador del usuario.
  • Los permisos que debe tener el fichero en el ordenador del usuario.

Debería haber incluido una etiqueta "depends" para añadir las dependencias del paquete. Cifra depende de SQLlite3 y este no se encuentra en un paquete de Rust sino en un paquete de sistema, por lo que es una dependencia del paquete debian de Cifra. Si quisieras usar la etiqueta "depends" podrías hacerlo pero tendrías que usar el formato de dependencias de debian, aunque en realidad no es necesario porque cargo-deb es capaz de calcular las dependencias automáticamente aunque no uses esa etiqueta. Lo que hace es usar ldd contra el binario compilado de nuestra aplicación y luego busca con dpkg qué paquetes de sistema ofrecen las librerías detectadas por ldd.

Una vez que tienes tu configuración de cargo-deb en tu Cargo.toml, empaquetar tu paquete debian es tan sencillo como hacer:

dante@Camelot:~/Projects/cifra-rust/$ cargo deb
[...]
Finished release [optimized] target(s) in 0.17s
/home/dante/Projects/cifra-rust/target/debian/cifra_0.9.1_amd64.deb

dante@Camelot:~$

Como se puede ver en la salida del comando, se puede encontrar el paquete generado en una nueva carpeta dentro de la de tu proyecto denominada /target/debian/.

Cargo-deb es una herramienta muy útil cuya única pega es no ser capaz de cumplir los requisitos de Debian para empaquetar paquetes viables para ser incluidos en los repositorios oficiales.