How to filter nixpkgs by metadata?

I’m writing a Nix intro for some colleagues. While trying to run a simple filter on nixpkgs.*.meta.maintainers I run into the dreaded “Please be informed that this pseudo-package is not the only part of Nixpkgs that fails to evaluate.” error. How can I filter on maintainers without rebuilding each package, or is this just not possible?

The full code:

pkgs = import <nixpkgs> {}
eelcoMaintains = pkg: builtins.elem pkgs.lib.maintainers.eelco pkg.meta.maintainers
builtins.filter eelcoMaintains (builtins.attrValues pkgs)

The two things you probably need are 1) builtins.tryEval to detect errors thrown by nixpkgs, and 2) the or syntax for something like pkg.meta.maintainers or [] for eval errors that aren’t caught by tryEval such as accessing an attribute that doesn’t exist.

1 Like

Thanks for the hints! I tried that, while splitting things into as small parts as possible, and ended up with this:

pkgs = import <nixpkgs> {}
packageList = builtins.attrValues pkgs
pkgMaintainers = pkg: pkg.meta.maintainers or []
eelcoMaintains = pkg: builtins.elem pkgs.lib.maintainers.eelco (pkgMaintainers pkg)
robustEelcoMaintains = pkg: (builtins.tryEval (eelcoMaintains pkg)).success
builtins.filter robustEelcoMaintains packageList

Unfortunately it just pegs a couple CPUs for a bit and gets killed.

Also check https://github.com/NixOS/nixpkgs/blob/0a0f9e92de0adb1a225177451a41bc4f8901f335/maintainers/scripts/update.nix#L41-L82 if you want to do it recursively.

That’s probably too advanced for a beginner course. Getting the root-level code to work at all is my first priority right now.

This returns true for every package that evaluates, not just the ones that fit your desired filter. You need something more like let x = builtins.tryEval whatever; in if x.success then x.value else someDefault

Thanks! I’ve amended to robustEelcoMaintains = pkg: let result = builtins.tryEval (eelcoMaintains pkg); in if result.success then result.value else false (assuming Eelco doesn’t maintain any broken packages :grin:). It still crashes, tho.

I ran it and the failures come from the packages that eelco maintains that are broken for other reasons, like being unfree, insecure, or just actually marked broken. If you don’t do builtins.attrValues pkgs and use pkgs.lib.filterAttrs instead of builtins.filter, you then get back an attrset that you can use builtins.attrNames on to at least see the attribute names of the packages that match the filter

1 Like

Oh, it works? I guess it must’ve run out of memory. I’m trying this on a Vagrant box with 4GB RAM.

After bumping the Vagrant box to 8 GB memory I was able to use your suggestions to get there:

pkgs = import <nixpkgs> {}
pkgMaintainers = pkg: pkg.meta.maintainers or []
eelcoMaintains = pkg: builtins.elem pkgs.lib.maintainers.eelco (pkgMaintainers pkg)
robustEelcoMaintains = pkg: let result = builtins.tryEval (eelcoMaintains pkg); in if result.success then result.value else false
eelcoMaintainsPackages = pkgs.lib.filterAttrs (name: pkg: robustEelcoMaintains pkg) pkgs
builtins.attrNames eelcoMaintainsPackages

Thank you again!