How to build an arbitrary nixpkgs file?

I’m trying to work through a nixpkgs issue, but I don’t know how to just build a single file (nixos/modules/security/pam.nix, in case that’s relevant) and check its result. Basically something like nix-build -E 'print options' nixos/modules/security/pam.nix. One of the things which seemed particularly promising was this one:

$ nix-build '<nixpkgs/nixos>' --attr config nixos/modules/security/pam.nix
trace: Obsolete option `jobs' is used. It was renamed to `systemd.services'.
error: The option `passthru' is used but not defined.
(use '--show-trace' to show detailed location information)
1 Like

I’m not sure what you want exactly, but you can explore the options using:

$ nix repl '<nixpkgs/nixos>'
Welcome to Nix version 2.3.15. Type :? for help.

Loading '<nixpkgs/nixos>'...
Added 6 variables.

nix-repl> config.security.pam      
trace: Obsolete option `security.pam.enableU2F' is used. It was renamed to `security.pam.u2f.enable'.
false; loginLimits = [ ... ]; makeHomeDir = { ... }; mount = { ... }; oath = { ... }; p11 = { ... }; services = { ... }; u2f = { ... }; usb = { ... }; yubico = { ... }; }

Where would I go from here to build nixos/modules/security/pam.nix and inspect the resulting derivation?

A NixOS module by itself doesn’t result in a derivation.
When you build a NixOS configuration, a single derivation is built by combining all the modules you imported. This is implemented as

import <nixpkgs/nixos/lib/eval-config.nix> {
  system = builtins.currentSystem;
  modules = [ (import ./configuration.nix) ];
}

Technically you could try to evaluate a single module, but it likely going to fail because many NixOS modules depend on each other. For example, the module you cited depends on (at least):

  • nixos/modules/system/etc/etc.nix
  • nixos/modules/security/wrappers/default.nix
  • nixos/modules/security/apparmor.nix

I guess the question then becomes how I would use a module in order to build the simplest possible derivation (or any other thing, I’m not embedded in the jargon yet) which can be inspected. Basically, I need some way to figure out whether my code change did what I expected without having to build all of nixpkgs to find out.

Do you mean modules don’t include their own dependencies? Does that make sense in Nix unlike in other languages?

Yes, modules don’t explicitely state their (module) dependencies: the NixOS module system works by having a single global namespace where any module can declare any option that can be assigned by any other module. By default all the modules (they are listed in nixos/modules/modules-list.nix are imported and can be used without further steps.

Nix evaluation is lazy, so you don’t actually evaluate everything, however the option definitions need to (otherwise you wouldn’t be able to just write services.nginx.enable = true), so there is a fixed cost when a new module is added to that list.

1 Like

Ok, by reading the issue you linked I think I understand what you want.
I think you want to make sure the files generated by the pam.nix module are still valid after you tweaked a bit the module.

So, there are two ways to do that:

  1. Write a sample configuration, build a full NixOS system, run it in a VM and check that everything works as expected. This is basically what NixOS tests do.
  2. Write a sample configuration, build only the parts you care about and inspect them.

In your case the files are stored in the config.environment.etc attribute set. For example

nix-build '<nixpkgs/nixos>' \
  -I nixos-config=test-config.nix \
  -A 'config.environment.etc."pam.d/xlock".source' | xargs $EDITOR

Alternatively you can wander around the attribute set with the nix repl and
build some file using the :b command to see it:

λ nix repl '<nixpkgs/nixos>' -I nixos-config=test-config.nix
Welcome to Nix version 2.3.15. Type :? for help.

Loading '<nixpkgs/nixos>'...
Added 6 variables.

nix-repl> :b config.environment.etc."pam.d/xlock".source
this derivation produced the following outputs:
  out -> /nix/store/5q39923l77znmxgjczg8d1sp1ahwscai-xlock.pam
5 Likes

If you’re using flakes, one nice thing is that you can then inspect what’s going on.

nix repl
nix-repl> :lf .
Added 13 variables.
nix-repl> outputs.nixosConfigurations.<hostname>.config.<path>.<I>.<care>.<about>
1 Like

Oh, that’s a cool feature!

As a side note, I wish the wiki page was better at explaining why we should be using flakes. “allow you to specify your code’s dependencies (e.g. remote Git repositories) in a declarative way” is not something I care about (yet).

Thanks @rnhmjoj! That’s getting closer. There’s no test-config.nix in the nixpkgs repo (and I wouldn’t know what to put in it) and Vim complained that “Input is not from a terminal” and broke my terminal completely when used with xargs for some reason.

$EDITOR "$(nix-build '<nixpkgs/nixos>' -A 'config.environment.etc."pam.d/xlock".source')" almost worked, but doesn’t evaluate the expression I’m interested in (tested by messing up the first line of that expression and not getting an error when building). It looks like this command is not actually building the code in the nixpkgs repo I’m in, because it runs fine from outside the repo as well.

Finally found it out: Run $PAGER "$(nix-build nixos -A 'config.environment.etc."pam.d/xlock".source')" in the root of the nixpkgs repo to build the source.

1 Like

The resulting nixpkgs PR. Thank you all for the help!

There’s no test-config.nix in the nixpkgs repo

Yes, that was supposed to be the sample configuration I was talking about.
You could not pass -I nixos-config to use your system configuration, or write a very minimal one because pam is enabled by default.

broke my terminal completely when used with xargs for some reason.

I suppose because nix-build didn’t output a path but some error message that confused vim.

No, it broke only when the build was successful.