Siguiente: , Anterior: , Subir: Interfaz programática   [Índice general][Índice]


8.3 Definición de variantes de paquetes

Una de las ventajas de Guix es que, dada una definición de paquete, puede derivar fácilmente variantes de dicho paquete—para una versión diferente del origen, con dependencias u opciones de compilación diferentes, diferentes, etcétera. Algunos de estos paquetes personalizados se pueden definir directamente en la línea de ordenes (véase Opciones de transformación de paquetes). Esta sección describe cómo definir variantes de paquetes en código. Esto puede ser útil en «manifiestos» (véase --manifest) y con su propia colleción de paquetes (véase Creación de un canal) entre otros usos.

Como se ha mostrado previamente, los paquetes son objetos de primera clase del lenguage Scheme. El módulo (guix packages) proporciona la forma sintáctica package para definir nuevos objetos de paquetes (véase Referencia de package). La forma más fácil de definir una variante de un paquete es usar la palabra clave inherit junto a package. Esto le permite heredar de una definición de paquete y modificar únicamente los campos que desee.

Por ejemplo, a partir de la variable hello, que contiene la definición de la versión actual de GNU Hello, podría definir de esta forma una variante para la versión 2.2 (publicada 2006, ¡con solera!):

(use-modules (gnu packages base))    ;para 'hello'

(define hello-2.2
  (package
    (inherit hello)
    (version "2.2")
    (source (origin
              (method url-fetch)
              (uri (string-append "mirror://gnu/hello/hello-" version
                                  ".tar.gz"))
              (sha256
               (base32
                "0lappv4slgb5spyqbh6yl5r013zv72yqg2pcl30mginf3wdqd8k9"))))))

El ejemplo previo es equivalente a lo que la opción de transformación de paquetes --with-source realiza. Esencialmente hello-2.2 preserva todos los campos de hello, excepto version y source, los cuales se modifican. Tenca en cuenta que la variable original hello todavía está disponible en el módulo (gnu packages base) sin sufrir ningún cambio. Cuando define un paquete personalizado como este realmente está añadiendo una nueva definición de paquete; la orignal sigue disponible.

De igual manera puede definir variantes con un conjunto de dependencias distinto al del paquete original. Por ejemplo, el paquete gdb predeterminado depende de guile pero, puesto que es una dependencia opcional, podría definir una variante que elimina dicha dependencia de este modo:

(use-modules (gnu packages gdb)    ;para 'gdb'
             (srfi srfi-1))        ;para 'alist-delete'

(define gdb-sin-guile
  (package
    (inherit gdb)
    (inputs (alist-delete "guile"
                          (package-inputs gdb)))))

La llamada alist-delete anterior elimina la tupla del campo inputs cuyo primer elemento es "guile" (véase SRFI-1 Association Lists en GNU Guile Reference Manual).

En ciertos casos encontrará útil escribir funciones («procedimientos» en el vocabulario de Scheme) que devuelven un paquete en base a ciertos parámetros. Por ejemplo, considere la biblioteca luasocket para el lenguaje de programación Lua. Se desea crear paquetes de luasocket para las versiones mayores de Lua. Una forma de hacerlo es definir un procedimiento que recibe un paquete Lua y devuelve un paquete luasocket que depende de él:

(define (make-lua-socket name lua)
  ;; Devuelve un paquete luasocket construido con LUA.
  (package
    (name name)
    (version "3.0")
    ;; se omiten varios campos
    (inputs
     `(("lua" ,lua)))
    (synopsis "Socket library for Lua")))

(define-public lua5.1-socket
  (make-lua-socket "lua5.1-socket" lua-5.1))

(define-public lua5.2-socket
  (make-lua-socket "lua5.2-socket" lua-5.2))

En este ejemplo se han definido los paquetes lua5.1-socket y lua5.2-socket llamando a crea-lua-socket con distintos parámetros. Véase Procedures en GNU Guile Reference Manual para más información sobre procedimientos. El hecho de disponer de definiciones públicas de nivel superior de estos dos paquetes permite que se les haga referencia desde la línea de órdenes (véase Módulos de paquetes).

Estas son variantes muy simples. Para facilitar esta tarea, el módulo (guix transformations) proporciona una interfaz de alto nivel que se corresponde directamente con las opciones de transformación de paquetes más sofisticadas (véase Opciones de transformación de paquetes):

Procedimiento Scheme: options->transformation opciones

Devuelve un procedimiento que, cuando se le proporciona un objeto que construir (paquete, derivación, etc.), aplica las transformaciones especificadas en opciones y devuelve los objetos resultantes. opciones debe ser una lista de pares símbolo/cadena como los siguientes:

((with-branch . "guile-gcrypt=master")
 (without-tests . "libgcrypt"))

Cada símbolo nombra una transformación y la cadena correspondiente es el parámetro de dicha transformación.

Por ejemplo, un manifiesto equivalente a esta orden:

guix build guix \
  --with-branch=guile-gcrypt=master \
  --with-debug-info=zlib

... sería algo parecido a esto:

(use-modules (guix transformations))

(define transforma
  ;; El procedimiento de transformación del paquete.
  (options->transformation
   '((with-branch . "guile-gcrypt=master")
     (with-debug-info . "zlib"))))

(packages->manifest
 (list (transforma (specification->package "guix"))))

El procedimiento options->transformation es conveniente, pero quizá no es tan flexible como pudiese desear. ¿Cómo se ha implementado? Es posible que ya se haya percatado de que la mayoría de las opciones de transformación de paquetes van más allá de los cambios superficiales mostrados en los primeros ejemplos de esta sección: implican reescritura de entradas, lo que significa que el grafo de dependencias de un paquete se reescribe sustituyendo entradas específicas por otras.

La reescritura del grafo de dependencias, con el propósito de reemplazar paquetes del grafo, es implementada por el procedimiento package-input-rewriting en (guix packages).

Procedimiento Scheme: package-input-rewriting reemplazos [nombre-reescrito] [#:deep? #t]

Devuelve un procedimiento que, cuando se le pasa un paquete, reemplaza sus dependencias directas e indirectas, incluyendo sus entradas implícitas cuando deep? es verdadero, de acuerdo a reemplazos. reemplazos es una lista de pares de paquetes; el primer elemento de cada par es el paquete a reemplazar, el segundo es el reemplazo.

Opcionalmente, nombre-reescrito es un procedimiento de un parámetro que toma el nombre del paquete y devuelve su nuevo nombre tras la reescritura.

Considere este ejemplo:

(define libressl-en-vez-de-openssl
  ;; Esto es un procedimiento para reemplazar OPENSSL
  ;; por LIBRESSL, recursivamente.
  (package-input-rewriting `((,openssl . ,libressl))))

(define git-con-libressl
  (libressl-en-vez-de-openssl git))

Aquí primero definimos un procedimiento de reescritura que substituye openssl por libressl. Una vez hecho esto, lo usamos para definir una variante del paquete git que usa libressl en vez de openssl. Esto es exactamente lo que hace la opción de línea de órdenes --with-input (véase --with-input).

La siguiente variante de package-input-rewriting puede encontrar paquetes a reemplazar por su nombre en vez de por su identidad.

Procedimiento Scheme: package-input-rewriting/spec reemplazos [#:deep? #t]

Devuelve un procedimiento que, proporcionado un paquete, realiza los reemplazos proporcionados sobre todo el grafo del paquete, incluyendo las entradas implícitas a menos que deep? sea falso. reemplazos es una lista de pares de especificación y procedimiento; cada especificación es una especificación de paquete como "gcc" o "guile@2", y cada procedimiento toma un paquete que corresponda con la especificación y devuelve un reemplazo para dicho paquete.

El ejemplo previo podría ser reescrito de esta forma:

(define libressl-en-vez-de-openssl
  ;; Reemplaza todos los paquetes llamados "openssl" con LibreSSL.
  (package-input-rewriting/spec `(("openssl" . ,(const libressl)))))

La diferencia principal en este caso es que, esta vez, los paquetes se buscan por su especificación y no por su identidad. En otras palabras, cualquier paquete en el grafo que se llame openssl será reemplazado.

Un procedimiento más genérico para reescribir el grafo de dependencias de un paquete es package-mapping: acepta cambios arbitrarios sobre nodos del grafo.

Scheme Procedure: package-mapping proc [cortar?] [#:deep? #f]

Devuelve un procedimiento que, dado un paquete, aplica proc a todos los paquetes de los que depende y devuelve el paquete resultante. El procedimiento para la recursión cuando cortar? devuelve verdadero para un paquete dado. Cuando deep? tiene valor verdadero, proc se aplica también a las entradas implícitas.


Siguiente: , Anterior: , Subir: Interfaz programática   [Índice general][Índice]