viernes, 21 de febrero de 2014

La gestión de paquetes

Las distribuciones GNU Linux distribuyen los programas y lo que necesitan para ejecutarse en lo que se llaman paquetes. Estos paquetes son programas o bibliotecas ya compilados y listos para instalar. Para gestionar estos paquetes se utiliza lo que se llama «gestor de paquetes». Un gestor de paquetes permite instalar y desinstalar paquetes además de comprobar los paquetes ya instalados y otras propiedades tales como dependencias.
Así, los paquetes además de incluir el ejecutable del programa, también incluyen información para su instalación y desinstalación como por ejemplo qué otros paquetes requieren. Las bibliotecas (repositorios de funciones usables por más de un programa y que por tanto se pueden distribuir de forma separada para no tener tantas copias de esas funciones como programas tengas) también pueden estar en paquetes propios los cuales a su vez pueden depender de paquetes correspondientes a otras bibliotecas. La información de instalación y desinstalación incluye también las órdenes que el gestor de paquetes debe ejecutar a la hora de instalar un paquete y de desinstalarlo (qué archivos extraer, a dónde copiarlos o qué archivos hay que borrar).

Es decir, un paquete por sí sólo es una serie de archivos que son copiados en el sistema en los sitios indicados según la carga de información que lleva el propio paquete (pequeños scripts o guiones -de órdenes-). Dicha información también indica al gestor de paquetes si debe descargarse otros paquetes adicionales (las dependencias), paquetes que también llevan sus respectivas instrucciones.
Como ejemplo, tomemos un paquete cualquiera de *Ubuntu, como por ejemplo Firefox. En la interfaz gráfica del gestor de paquetes incluido en Kubuntu, Muon, se puede encontrar el paquete Firefox presentado de la siguiente manera:
Muon, interfaz gráfica de estilo «Centro de Software» para APT
Tanto Muon como el Centro de Software de Ubuntu son interfaces gráficas de APT (Advanced Packaging Tool). Muestran la información con fotos del programa e incluso *Ubuntu ha montado un sistema de comentarios accesible desde su Centro de Software y también desde Muon. Este sistema de comentarios no forma parte de lo que es APT.
Bien, se puede apreciar la versión del paquete pero nada más. Ni sus dependencias ni nada. Sería útil que añadieran un desplegable de información adicional para el que quiera ver esa información.

Esto nos lleva a que para instalar un único programa puede que haya que descargar e instalar una larga lista de paquetes que conformarán una cadena de dependencias, esto es que para instalar un determinado paquete antes han tenido que ser instalados los paquetes de los cuales depende. Si A depende de B, primero se instala B y luego se instala A.
Los gestores de paquetes mantienen en una base de datos la lista de paquetes instalados en el sistema y otra serie de parámetros configurables por el usuario (versiones de paquetes, servidores de paquetes deseados, etcétera). Así pues, para ver esa información adicional tendremos que ir a la consola de comandos y ejecutar la órden «apt-cache show firefox» o «aptitude show firefox». Sí, hay varias órdenes posibles dado que APT no tiene un único interfaz para usarlo. APT se puede integrar en cualquier programa mediante las bibliotecas que tiene disponibles y por tanto hay varios programas para poder usar APT, tanto gráficos (Muon, Centro de Software de Ubuntu, Synaptic, Kynaptic, Adept) como de comandos (apt-get o aptitude).
Una vez mostrada la información de firefox el usuario puede leer lo siguiente:

Paquete: firefox                                 
Estado: instalado
Instalado automáticamente: no
Versión: 27.0.1+build1-0ubuntu0.13.10.1
Prioridad: opcional
Sección: web
Desarrollador: Ubuntu Mozilla Team 
Arquitectura: amd64
Tamaño sin comprimir: 68,7 M
Depende de:
lsb-release, libasound2 (>= 1.0.16), libatk1.0-0 (>= 1.12.4), libc6
(>= 2.17), libcairo2 (>= 1.2.4), libdbus-1-3 (>= 1.0.2),
libdbus-glib-1-2 (>= 0.78), libfontconfig1 (>= 2.9.0), libfreetype6
(>= 2.2.1), libgcc1 (>= 1:4.1.1), libgdk-pixbuf2.0-0 (>= 2.22.0),
libglib2.0-0 (>= 2.37.3), libgtk2.0-0 (>= 2.24.0), libpango-1.0-0 (>=
1.22.0), libpangocairo-1.0-0 (>= 1.14.0), libstartup-notification0
(>= 0.8), libstdc++6 (>= 4.6), libx11-6, libxext6, libxrender1,
libxt6
Recomienda: xul-ext-ubufox, libcanberra0, libdbusmenu-glib4, libdbusmenu-gtk4
Sugiere: ttf-lyx
Tiene conflictos con: firefox
Reemplaza: kubuntu-firefox-installer, kubuntu-firefox-installer
Proporciona: gnome-www-browser, iceweasel, www-browser
Descripción: Navegador seguro y sencillo de Mozilla
 Firefox brinda seguridad, facilidad al navegar por la web. Una interfaz de
 usuario familiar, características de seguridad mejoradas incluyendo protección
 del robo de identidad en linea y búsqueda integrada que te permite sacarle todo
 le jugo a la web.

El desarrollador es el que ha hecho el paquete pero no el programa contenido en el paquete, ya que no sólo se suele coger el código fuente y compilarlo para meterlo en el paquete sino que se pueden hacer ciertas modificaciones necesarias, por lo que el autor del paquete no tiene porqué coincidir con el autor del programa empaquetado.
También hay información de la arquitectura del procesador sobre la que se puede ejecutar el programa que el paquete contiene y también del tamaño del paquete.
Luego vienen las dependencias. Esos son los otros paquetes que el paquete firefox necesita tener instalados en el sistema. En este caso todo son bibliotecas (lib*) salvo el paquete lsb-release. Para cada paquete del cual depende se indica entre paréntesis la versión que necesita de ese paquete (nótese que es la versión del paquete no de la biblioteca u otro software que empaquete, podrían no coincidir ya que un mismo paquete puede ser revisado varias veces). Además, la versión necesaria puede no ser una exacta, de ahí que esté el símbolo mayor o igual (>=). Esto es útil para bibliotecas que mantengan una API estable (no cambiante) a partir de cierta versión.
Las recomendaciones son paquetes que pueden añadir funcionalidad adicional pero que no son estrictamente necesarios para el programa. «aptitude» instala los recomendados por defecto, «apt-get» no lo hace. Que instale los recomendados por defecto a veces puede ser problemático porque introduce más dependencias y un paquete que podría instalarse con «apt-get» no se puede con «aptitude» salvo que se le añada la opción «-R» (o en su formato largo «--without-recommends»).
Los conflictivos son paquetes que no pueden estar instalados al mismo tiempo que el paquete que se desea instalar. Si se trata de instalar con un gestor de paquetes inteligente como Muon, Synaptic, Centro de Software de Ubuntu, apt-get o aptitude, estos gestores detectarán el problema y preguntarán al usuario qué desea hacer: si desinstalar el paquete conflictivo o no instalar el paquete que se quiere instalar. En el caso de apt-get o aptitude se plantean además varias alternativas para solucionar el conflicto.
Instalando múltiples paquetes de una sola vez
Una de las cosas que permiten los gestores de línea de comandos y no los gráficos (salvo Synaptic, Adept, Kynaptic, ...) es la de instalar múltiples paquetes en una sola orden. No hace falta ir instalando cada programa uno por uno. Claro, de hacerlo así pueden salir problemas de conflictos y entonces el usuario debe saber qué elección tomar. El gestor de paquetes suele presentar varias alternativas si se va diciendo «no» a las acciones propuestas, acciones constituidas por eliminar una serie de paquetes, no instalar algunos paquetes e instalar algunos. Cualquier combinación de esas tres posibilidades. Por suerte los conflictos no es algo común que surjan y por ejemplo a veces los conflictos surgen entre paquetes que aportan la misma funcionalidad pero una versión del mismo tiene más contenidos, por lo que se puede aceptar la desinstalación de los actuales y la instalación de los nuevos. Pongamos por ejemplo los paquetes libavformat53 y libavformat-extra-53. El extra contiene lo que tiene libavformat y más cosas. Si se tiene instalado libavformat53 y se desea instalar un programa que requiera el -extra, se nos informará de dicho conflicto y se nos presentarán varias alternativas para solventarlo. Atención, porque solventar un conflicto no significa que el  resultado sea algo deseado: te puedes quedar sin instalar el programa o desinstalando otros programas según la alternativa que quieras. Por suerte los empaquetadores de *Ubuntu (y Debian) tienen un buen hacer y todos los paquetes que dependen de libavformat53 admiten también el -extra, por lo que se puede instalar el -extra y eliminar el normal sin problemas.
Un paquete puede tener «ó-dependencias», necesita tener instalado un paquete u otro, pero ambos no puede ser porque se machacan entre ellos, hay conflictos entre ambos


La gestión de dependencias es algo muy importante ya que permite ahorrar espacio en disco al permitir reutilizar el máximo de componentes (bibliotecas) posibles entre los distintos programas. En la wikipedia inglesa hay un artículo entero dedicado a ello (dependency hell). Esta reutilización además hace posible que la corrección de fallos en una biblioteca permita a todos los programas que hacen uso de dicha biblioteca aprovechar esas correcciones. Pueden convivir varias versiones de una misma biblioteca, basta con un paquete para cada versión de la misma. Esto es algo habitual en casos en los que hay grandes diferencias de una a otra (cambios en el comportamiento de las funciones existentes y/o sus parámetros).

Aún con todo, el usuario normalmente sólo querrá buscar el paquete de un programa y las dependencias que arrastre son instaladas automáticamente sin mayores problemas. Sólo casos muy concretos pueden dar problemas, como cuando se quiere instalar múltiples paquetes de una sola vez y que dependan de bibliotecas muy interrelacionadas, algo que sería posible si quisieras instalar múltiples programas de audio o de vídeo. Si no quieres ver esos conflictos, como en el ejemplo anterior, instalas primero el programa con las bibliotecas extendidas y ya está, luego instalas el resto (si lo intentas hacer de una vez te informará de esos conflictos y tendrás que resolverlos tú, de ahí que Muon o el Centro de Software por el momento no opten por permitir instalar múltiples programas de una sentada, aunque para usuarios más avanzados podrían incluir dicha opción).

La creación de estos paquetes y la modularización (división) en paquetes de los distintos programas suele correr a cargo de la distribución GNU Linux de turno. Esa distribución GNU Linux tendrá una serie de gente que se hace cargo de la misma y de los paquetes que tiene disponibles. Estos paquetes son creados por una serie de personas que se descargan el código fuente original del programa y lo empaquetan, a veces corrigiendo fallos o aplicando parches necesarios para que dicho programa encaje y funcione debidamente con las versiones de bibliotecas que dicha distribución GNU Linux tenga empaquetada. Así pues, los repositorios de una distribución GNU Linux y los paquetes que contienen terminan siendo generados por alguien que ha hecho unas comprobaciones previas. Tienen un origen algo manual, sobre todo por el tema de la gestión de dependencias.

Los paquetes de Debian y derivados tienen la misma estructura interna. Se puede averiguar fácilmente abriéndolos con tu visor de archivos comprimidos favorito (File unroller, Ark, ...) ya que son un simple tarball con una estructura de directorios y archivos determinada. El contenido de un paquete Debian o derivado (archivo de extensión .deb) se puede ver en la figura siguiente:
Un paquete .deb contiene tres archivos, de los cuales dos también son tarballs. El control.tar.gz y el data.tar.gz. El control.tar.gz contiene la carga de información del paquete con respecto a sus dependencias y acciones que debe realizar el gestor de paquetes para instalarlo y desinstalarlo.
En la figura de encima se puede ver el contenido del control.tar.gz. Este archivo contiene una serie de archivos de texto (los guiones de órdenes/comandos -scripts- también son archivos de texto) incluyendo el archivo «conffiles» con la información de archivos de configuración que debe comprobar el gestor de paquetes por si acaso el usuario los ha modificado y que en caso de ser así el gestor de paquetes te preguntará en el momento de actualizar (o de volver a instalar el paquete sin haberlo purgado previamente, es decir, borrado completamente antes) si deseas mantener la versión actual de esos archivos o instalar los que trae el paquete por defecto. Te mostrará las diferencias entre ambos archivos para que puedas comprobar si hay cambios importantes que puedan provocar problemas si deseas mantener tu versión modificada de los archivos. Como estas modificaciones normalmente las hacen sólo usuarios avanzados, este tipo de avisos sólo los verán también los usuarios avanzados y se supone que sabrán lo que se hacen.
El archivo «control» contiene el texto que aparece al ejecutar el comando «apt-cache show firefox» o «aptitude show firefox». APT lee de ahí las dependencias (separadas por comas, números de versión de paquete entre paréntesis). Eso, al crear un paquete, hay que ponerlo a mano. No es algo difícil de averiguar, porque para compilar el programa has necesitado esas bibliotecas en tu sistema para poderlo hacer, además de los paquetes de desarrollo de dichas bibliotecas que contienen las cabeceras para poder compilar (en Debian las normas de estilo dictan añadirle «-dev» a los paquetes que contienen las cabeceras de las bibliotecas empaquetadas correspondientes).
El «md5sums» contiene los resúmenes (hashes) md5 de todos los archivos del paquete, incluyendo los que hay dentro del data.tar.gz. Esto permite comprobar la integridad de los archivos instalados en el sistema, utilizando por ejemplo la utilidad debsums. Claro, si modificaste algún archivo de configuración las comprobaciones de dichos archivos fallarán.
Los archivos «postinst», «postrm», «preinst» y «prerm» son los guiones que el gestor de paquetes ejecuta después de instalar, después de eliminar, antes de instalar y antes de eliminar el paquete, respectivamente.

El archivo «data.tar.gz» contiene los archivos del programa, en nuestro caso Firefox, manteniendo la estructura de carpetas que va a tener en nuestro sistema. El gestor de paquetes sólo tiene que descomprimir el data.tar.gz en la raíz de nuestro sistema de archivos (/) y fuera. Es el control.tar.gz el que da vida al data.tar.gz con las órdenes que APT debe seguir y archivos que debe tener en cuenta.
A la hora de crear estos paquetes existen utilerías que te dejan con una estructura para los distintos guiones y archivos del control.tar.gz, pero si hay algo especial que deban hacer es tarea del empaquetador añadirlo.
El «debian-binary» indica la versión de formato de paquete DEB de dicho paquete. Actualmente la especificación de paquetes Debian está en su versión 2.0, por lo que debian-binary tiene escrito un «2.0».

Todos estos archivos terminan copiados en nuestro sistema, incluyendo los del control.tar.gz que terminan en unos directorios que APT tiene bajo su control. En tu instalación de *Ubuntu podrás encontrar en los directorios /var/lib/apt, /var/lib/aptitude y /var/lib/dpkg la información relacionada con los paquetes Debian y sus gestores, mientras que en /etc/apt encontraréis las preferencias del usuario, como los servidores de origen (también llamados repositorios) de los paquetes en el archivo sources.list y directorio /etc/apt/sources.list.d/ o establecer configuraciones con respecto a qué versiones es preferible descargar de un paquete, ya sea según su origen, creador del paquete, su versión o lo que sea, en los archivos dentro de /etc/apt/preferences.d/. En /etc/apt también se almacenan las distintas claves que firman los paquetes de los diferentes repositorios de forma que se puede comprobar si el paquete proviene de un repositorio conocido y es de confianza (como cuando firmas algo con el DNI-e y la administración comprueba que tu firma es válida).
Los paquetes están repartidos entre varios repositorios según la prioridad que tengan en su mantenimiento. En el repositorio etiquetado como «main» se encuentran los paquetes mantenidos directamente por los creadores de la distribución GNU Linux. A partir de ahí tenemos el «universe», el «multiverse» y el «restricted». El «universe» consta de paquetes creados por la comunidad, el «restricted» está formado por paquetes privativos mientras que el «multiverse» contiene paquetes que pueden no ser legales en determinados países a pesar de ser igualmente software libre.
Listado de orígenes de paquetes en Muon

He hablado de unas cuantas utilidades de gestión de paquetes. Todas terminan haciendo uso de dpkg en última instancia. Los programas de entorno gráfico utilizan APT (comandos apt-get, apt-cache, ...) de igual modo que lo hacen aptitude y dselect. Y APT utiliza a su vez el sistema gestionado por dpkg. No está nada mal, un gestor inteligente de paquetes es un sistema bastante complejo y uno más complejo todavía es Guix, del cuál hablaré en otro momento.

Ventana de configuración de los orígenes
En esta entrada he rascado la superficie del funcionamiento interno del sistema de paquetes de Debian y derivados. Todo lo aquí explicado es totalmente innecesario para un usuario normal que abre su gestor de paquetes favorito e instala los programas que quiere o se descarga un *.deb de la red y con un doble clic se abre GDebi o QApt, pero cabe mencionar que los gestores por línea de comandos tienen muchísimas más opciones (y también albergan más peligros), desde reconfigurar un paquete, reinstalarlo hasta comprobar su integridad, descargarlo pero no instalarlo, listar dependencias inversas (ver paquetes que dependen o necesitan el paquete seleccionado, en contraposición de los que depende o necesita el seleccionado) y un largo etcétera. Por suerte estos gestores tienen unas más que dignas páginas de manual (comando man).

Los paquetes se parecen bastante al sistema empleado por Microsoft y sus InstallShield o Microsoft Software Installer (archivos *.msi), paquetes de software usados para instalar programas en Windows y tener un seguimiento de su estado gracias al registro de Windows, permitiendo desinstalar programas desde el Panel de Control. Esos archivos *.msi también deben ser creados con una serie de parámetros e indicaciones por parte del creador del programa, lo cual incluye las dependencias, directorios de instalación y demás. La diferencia radica en que es un sistema puramente binario, basado en bases de datos relacionales y transaccionales (que la verdad no parecen servir de mucho) además de un registro binario que no sólo sirve para seguir los paquetes software instalados sino también sus configuraciones así como las de todo el sistema y bueno, ya nos conocemos los múltiples problemas que esto termina generando. Además, el sistema de Microsoft provoca que se tienda a duplicar una gran cantidad de bibliotecas por lo que la propagación de soluciones a errores es menor. Es una de las explicaciones de porqué una instalación de Windows termina ocupando 15 GB mientras que una de *Ubuntu ocupa 5 GB y viene ya con unas cuantas aplicaciones.

Las ventajas del sistema usado en distribuciones GNU Linux reside en la centralización de la gestión del software instalado en la máquina así como la facilidad para su mantenimiento e incorruptibilidad (salvo un aborto forzoso en medio de una modificación de la base de datos de APT, p.ej. un kernel panic o un corte en la corriente eléctrica). Este sistema de gestión centralizada se ha puesto ahora muy de moda con los teléfonos inteligentes. Sistemas como iOS o Android introdujeron lo que se llama «tienda de aplicaciones» que en el fondo no dejan de ser un gestor de paquetes con la diferencia de que los paquetes de iOS y Android son autocontenidos, no tienen dependencias por lo que todas las bibliotecas necesarias (salvo las del sistema) están duplicadas en cada uno de los APK en el caso de Android o en los IPA de iOS, ocupando más megas de lo realmente necesario aunque se ahorran cualquier tipo de problema de dependencias. Guix permite solventar de una forma mucho más inteligente dicho debate además del tema de los abortos forzosos comentado anteriormente.

Este artículo me ha hecho venir a la cabeza la realización de un mega grafo con GraphViz, mostrando todos los paquetes del repositorio de Ubuntu y sus dependencias y conflictos. Probablemente saldría una cosa bastante chula.

No hay comentarios:

Publicar un comentario