Use lib.types system to merge attrsets without the module system?

You can relatively easily write your own module evaluating function without a dependency on NixOS, fully contained in the package definition:

  { stdenv, lib }:

  stdenv.mkDerivation {
    # ...

    passthru = rec {
      module = import ./module.nix;
      configFile = cfg: (lib.evalModules {
        modules = [
          module
          cfg
        ];
      }).config.file;
    };
  }

Have a module.nix that defines options like this:

  { lib, config }:

  with lib;

  {

    options = {
      file = mkOption {
        type = types.path;
      };
      fileContents = mkOption {
        type = types.lines;
      };
      params = mkOption {
        type = types.attrsOf (types.submodule {
          # ...
        });
      };
    };

    config = {
      file = builtins.toFile config.fileContents;
      fileContents = throw "Some function to convert config.params to a string, possibly with some assertions";
    };
  }

Then the user can directly get a config file from the package definition through pkgs.foo.configFile { params.foo = true; }. It’s then even possible to have this module as a submodule in NixOS by using options.some.nixos.option = mkOption { type = types.submodule pkgs.foo.module; };. This module declaration is in fact usable by anybody that has access to the package, so even different distros can benefit from it. I’d like to have more packages use something like this in the future, it’s really useful.

7 Likes