Adrianistán

Problemas de Nix

31/01/2020

En el post anterior vimos de forma general lo más básico de Nix. Aquí veremos algunos de los inconvenientes que posee Nix actualmente

Construcción de paquetes deterministas

Cuando construimos un paquete en Nix, normalmente hacemos un import a nixpkgs, que representa el canal central actualizado a ese momento. Los canales de Nix no soportan que convivan varias versiones del programa a nivel de código, sí a nivel binario, que como vimos es una de las grandes ventajas, pero no a nivel de código. Por tanto cuando recompilemos el paquete, si hemos actualizado nispkgs en nuestro ordenador, podemos estar usando otros paquetes diferentes, ya que la versión antigua ya no existe en el canal nixpkgs.

La solución es pinear los nixpkgs, es decir, tomar un punto (normalmente un commit) y construir siempre el paquete con esa versión de nixpkgs. Esto es fácil de conseguir gracias a varias funciones predefinidas, pero no deja de ser un poco coñazo

Así pues este código


let 
    nixpkgs = import <nixpkgs> {} ;
in
nixpkgs.stdenv.mkDerivation {
    name = "pcc-1.0.0" ;
    builder = ./builder.sh ;
    src = nixpkgs.fetchurl {
        url = https://github.com/aarroyoc/pcc/archive/3f90d424494f4d1971ea34e66883fdee8a587b1f.zip;
        sha256 = "ec80f0c8af5dc9d6f0fbb691a4132ac8d44e42dd05865e23c80c2e0f0219d56f";
    };
    buildInputs = [ nixpkgs.unzip nixpkgs.bison nixpkgs.flex];
}

se convertiría en este


let 
    nixpkgs = import (builtins.fetchTarball {
        name = "nixos-unstable-2018-09-12";
        url = https://github.com/NixOS/nixpkgs/archive/1144ee553852f5e91cf85a639ee2e30438a5136a.tar.gz;
        sha256 = "02lzg2m7snc3ph2a3hscb0az5prgab7ri8aic91x4b0slj54g168";
    }) {};
in
nixpkgs.stdenv.mkDerivation {
    name = "pcc-1.0.0" ;
    builder = ./builder.sh ;
    src = nixpkgs.fetchurl {
        url = https://github.com/aarroyoc/pcc/archive/3f90d424494f4d1971ea34e66883fdee8a587b1f.zip;
        sha256 = "ec80f0c8af5dc9d6f0fbb691a4132ac8d44e42dd05865e23c80c2e0f0219d56f";
    };
    buildInputs = [ nixpkgs.unzip nixpkgs.bison nixpkgs.flex];
}

Integración paquetería lenguajes

Nix tiene una forma muy particular de empaquetar el software. Por contra, cada vez es más habitual que cada lenguaje de programación use además su propio sistema de gestión de paquetes. Hay ciertos lenguajes que se adaptan bien a Nix, como Haskell o Python, pero hay muchos otros como Go o JavaScript (npm) que se comportan muy mal. Cualquier intento de portar estos sistemas a Nix implican crear paquetes Nix por cada paquete npm, algo que se vuelve muy tedioso. Actualmente se suelen recurrir a soluciones llamadas Nix-in-Nix. Básicamente consiste en usar programas como node2nix internamente, para que este programa nos genere automáticamente un montón de ficheros Nix que cargamos desde Nix. En mi opinión no es una solución elegante.

Actualizaciones de seguridad

Una de los inconvenientes de la paquetería Nix, es que cada paquete necesita ser responsables de sus fallos de seguridad, ya que aunque nixpkgs actualice la versión de la librería en cuestión, el programa va a seguir usando la versión con la que se construyó, y es imposible de cambiar a no ser que reconstruyamos el paquete.

Mi valoración personal

Nix me parece una propuesta interesante para los sistemas de paquetería en Linux. Aporta algo diferente, aun así, la situación es la siguiente:

A día de hoy para entornos de programación (para instalar todas las dependencias que necesita un proyecto) y en servidor usaría Docker. Es mucho más sencillo de aprender a usar, mucho más reproducible y cuenta con una mayor comunidad alrededor. Para el uso de escritorio, usaría una distro rolling o una distro con ciclos de vida tradicionales complementada bien con Snap/Flatpak/AppImage o Nix. No tengo una preferencia fuerte entre Snap/Flatpak/AppImage aunque suelo usar Snap. También estoy probando Nix ¿Cuál es vuestra opinión al respecto? ¿Cuál sería vuestra estrategia ideal?

Tags: programacion linux tutorial nix