Flakes: cognitive overload, gateway drugs, self-contained simple recipes

Like this:

<attr>.<system> -> packages.<system>.<attr>


Is there something in flake-utils that does that? Or puts it there in the first place? It seems irksome to have to treat the two so differently.

flake-utils.eachDefaultSystem should do that for you.

And it is packages.${system}.${name}, such that you can do nix build .#$name.

All the functions in flake-utils that iterate over a list of systems, do exactly that, they will add the “current” system as second layer in the attributes of the attribute set you returned from the function.

… maybe I’m being dense, but isn’t that exactly what I was originally trying to do here:

… or do you mean something else?

… which is exactly what I was using already …

If you want to build an unknown top-level attribute, then it has to be a derivation directly.

If you move it to packages.${system}, then you can use it with infering of the system from the CLI.

Yes, but without packages, perhaps do not use flake-utils until you understood how the flake actually should look like, with hard coded systems in the attribute pathes.

IIUC the answer seems to be that the code sample I provided originally (with the non-defaultPackage name shortened for convenience):

should be modified thus:

-         NOT-defaultPackage = pkgs.stdenv.mkDerivation {
+packages.NOT-defaultPackage = pkgs.stdenv.mkDerivation {

After this change

nix build .#NOT-defaultPackage

works sensibly, and

nix flake show


│   ├───aarch64-linux: package 'whatever'
│   ├───i686-linux: package 'whatever'
│   ├───x86_64-darwin: package 'whatever'
│   └───x86_64-linux: package 'whatever'
    │   └───NOT-defaultPackage: package 'whatever'
    │   └───NOT-defaultPackage: package 'whatever'
    │   └───NOT-defaultPackage: package 'whatever'
        └───NOT-defaultPackage: package 'whatever'

(I wonder whether I’ll learn to appreciate this special-case/inconsistency in the long run. Right now it’s just a PITA!)

This is not an inconsistency.

Any of the non-well known output attributes as described in the wiki linked above, have to be directly buildable derivations. At least if you want to use them as “packages”.

Though this is exactly the reason why you should use packages instead, as there the flake system knows how to resolve in the context of the current system.

Also the recommended way of using defaultPackage is more like this:

  outputs = { self, nixpkgs }: {
    packages."x86_64-linux".hello = nixpkgs.legacyPackages."x86_64-system".hello;

    defaultPackage."x86_64-linux" = self.packages."x86_64-linux".hello;
1 Like

The presence of a hidden (starting with dot) file whose name matches the name of a package in the flake in the current directory, breaks nix {shell,build} .#the-package.

Demo: I have a flake containing a package called aaa-and-bbb which contains an executable aaa which prints out This is program AAA.

$ pwd
$ nix shell .#aaa-and-bbb -c aaa
This is program AAA.
$ touch .aaa-and-bbb
$ nix shell .#aaa-and-bbb -c aaa
error: --- BadURL -------------------------------------------------------------- nix
path '/tmp/aaaaaargh/.aaa-and-bbb' is not a flake (because it's not a directory)

In other words, nix .#aaa-and-bbb -c aaa works fine, unless the file ./.aaa-and-bbb exists.

Bug or feature?

No problems here…

$ nix shell .#flux2 -c flux --version
flux version 0.8.0
$ touch .flux2
$ nix shell .#flux2 -c flux --version
flux version 0.8.0

Perhaps some bash vs zsh thing?

It may depend on configuration, but for me, in zsh also without the hidden file it doesn’t work:

$ nix run .#hello
zsh: no matches found: .#hello
$ touch .hello
$ nix run .#hello
error: --- BadURL ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- nix
path '/home/johannes/testflake/.hello' is not a flake (because it's not a directory)

Basically, in zsh you have to escape the hash:

$ touch .hello   
$ nix run .\#hello
Hello, world!
$ nix run '.#hello'
Hello, world!

I never had to escape the # sign. Not sure why…

I’m on nix (Nix) 2.4pre20201201_5a6ddb3 and zsh 5.8 (x86_64-pc-linux-gnu).

The octothorpe only has special meaning in zsh with EXTENDED_GLOB set, requiring either the escape or quotes for flake refs. Of course, I’ve been using zsh so long now, it took me a while to realize this wasn’t the case in bash.

1 Like

I had the issue with zsh which force me to escape the # but thanks to your comment @nrdxp I found out that setting this in my .zshrc fix problem:

setopt no_extendedglob