[Nix-dev] Moving some of the NixOS setup to nixpkgs

Jan Malakhovski oxij at oxij.org
Wed Oct 15 13:09:11 CEST 2014


Hi,

What would you say about the following idea:
(important lines in the following boiler-plate are marked with "!!!")

1) Package maintainers write something like

# packages jack and alsa-plugins need to configure for each other or
# else starting jack will seizure the default sound output and alsa
# programs will not work

jack/default.nix:

{ stdenv, ... }:

stdenv.mkDerivation {
  ...
  #option name is a subject to change
  os = {config, ...}: { # !!!
    options = {
      enable = {
        type = bool;
      };
    };
    config = mkIf config.packages.jack2.enable {
      # service definition or whatever # !!!
    };
  };
  ...
}

alsa-plugins/default.nix:

{ stdenv, ... }:

stdenv.mkDerivation {
  ...
  os = {config, ...}:
    let conf = ''
      ...
      ${optional (hasAttr config.packages "jack2" && config.packages.jack2.enable) ''
      pcm.default {
        type jack
        ...
      }''}
      ...
      '';
    in {
      config = {
        environment.variables.ALSA_PLUGINS_DIR = ... #or whatever
        environment.etc."asound.conf" = conf; # !!!
        environment.home."asoundrc" = conf;
      };
    };
  ...
}

# while writing this I realized that this is not the best example in
# terms of how this should be done. alsa config should be defined and
# generated in alsalib, alsaPlugins should not generate asoundrc, and
# jack config should modify alsalib options, e.g. for jack:
{stdenv, alsaPlugins, ...}:

stdenv.mkDerivation {
  ...
  os = {config, ...}: {
    options = {
      jack2.enable = {
        type = bool;
      };
    };
    config = {
      requirePackages = [ alsaPlugins ]; # !!!
      # maybe "propagatedPackages" is a better name
      packages.alsa.asoundconf = mkIf config.packages.jack2.enable ''
        pcm.default {
          type jack
          ...
        }''
      '';
      # service definition or whatever
    };
  };
  ...
}

alsa:

{stdenv, ...}:

stdenv.mkDerivation {
  ...
  os = {config, ...}: {
    options = { ... asoundconf definition ...} # !!!
    config = {
      environment.etc."asound.conf" = config.alsa.asoundconf;
      environment.home."asoundrc" = config.alsa.asoundconf;
    };
  };
  ...
}

# but accepting that this is just an example from the top of my head,
# accepting that both versions show off some of the features I have in
# mind, and ignoring all other minor points like option names

2) stdenv gets another parameter which describes how to use this
config, so that NixOS evaluates packages in systemPackages together
and then merges the resulting config into the system config, and user
install generates a wrapper package with a script to be sourced in
.bashrc, systemd user services and so on.

E.g.

environment.systemPackages = [
  # these two see all systemPackages and configure for each other and
  # for other systemPackages
  jack2
  alsaPlugins

  # these two see only each other; vim configures for
  # suchAndSuchPlugin (or suchAndSuchPlugin configures vim for itself)
  (inABox [ vimFull suchAndSuchPlugin ])

  # this will make stdenv to completely ignore the config (e.g. apply
  # the function (whatever: {}) to a derivation or something) and
  # generate a pure package without any configuration and any options
  # to be seen by other packages
  (pure somePackage)
];

3) All in all, my proposal is to allow grouping packages into boxes
(environment.systemPackages is just such a box), evaluate their
nixos-like configurations relating to a given box, and then allow
higher level system (NixOS or user profile generator) decide what to
do with the resulting box config: use it as a part in the higher level
config, generate scripts and wrappers from it or just ignore it.

Note that this proposal:

* reuses packages built for different environments (packages outputs
  stay the same between boxes, it's boxes that change),
* doesn't generate a ton of wrappers by generating a wrapper for every
  single package,
* gives a somewhat natural way to decide which options go where (using
  the same logic as in NixOS).

I would even allow to do something like:

environments.systemPackages = [
  (userEnvironment "oxij" {
     requirePackages = [ ... xmonad and other programs ... ];
     environment.home.".xsession" = ''
       ...
       exec xmonad
     '';
  })
  ];

and then running
/run/current-system/sw/bin/setup-user-environment-oxij should
resymlink files in $HOME in the same way as nixos-rebuild switch
resymlinks files in /etc. A killer feature I'd say.

A disputable disadvantage is that a huge part of NixOS (at least
pretty much all the services) should migrate into nixpkgs.

Cheers,
  Jan

On Wed, 1 Oct 2014 11:11:38 +0200
Wout Mertens <wout.mertens at gmail.com> wrote:

> Hi all,
> 
> TL;DR: I'd like to discuss the empty space between declarative NixOS
> systems and imperative nix-env user profiles.
> 
> ...


More information about the nix-dev mailing list