Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding (Haskell) packages repeatedly is surprising and non-modular #25887

Closed
ocharles opened this issue May 18, 2017 · 6 comments
Closed

Comments

@ocharles
Copy link
Contributor

ocharles commented May 18, 2017

Issue description

The .override attribute doesn't allow you to repeatedly override the set of Haskell packages. This means it's impossible to compose multiple overlays that change the Haskell package set.

Steps to reproduce

The following Nix expression fails to evaluate:

let hs-0 = (import <nixpkgs> {}).haskellPackages;
    hs-1 = hs-0.override { overrides = self: super: { x = 42; }; };
    hs-2 = hs-1.override { overrides = self: super: { y = super.x; }; };
in hs-2.y
error: attribute ‘x’ missing, at (string):3:59

But this is surpring, because:

let hs-0 = (import <nixpkgs> {}).haskellPackages;
    hs-1 = hs-0.override { overrides = self: super: { x = 42; }; };
in hs-1.x

evaluates to 42 as expected. The problem is overrides only looks at the initial result. Further overrides does not update what overrides begins with.

This issue is probably not limited to Haskell packaging.

Importance

The new overlays system means that one would expect it to be possible to combine multiple Haskell overlays. I wanted to have an overlay that contained some build fixes & unreleased (but public) Haskell libraries, and another overlay that contained company internal projects. This isn't possible, because as shown above - these overlays don't compose.

@ljli
Copy link
Contributor

ljli commented May 25, 2017

You can do that with extend.

let hs-0 = (import <nixpkgs> {}).haskellPackages;
    hs-1 = hs-0.extend (self: super: { x = 42; });
    hs-2 = hs-1.extend (self: super: { y = super.x; });
in hs-2.y

It is not surprising if it is clear what override does and where overrides comes from. override overrides function arguments. But it doesn't give you the previous set of arguments as as an argument like e.g. overrideAttrs does (not that you could use that instead). So you can only keep an argument in place or replace it completely. If override would provide you with the previous set of arguments, this would work:

hs-0.override (oldArgs: { overrides =
  composeExtensions (self: super: { y = super.x })
    (oldArgs.overrides or (self: super: {});
})

Theoretically override could work behind the scenes to consume and accumulate the overrides arguments. But despite the similar names those are two independent mechanisms. The overrides argument is haskell specific, it is declared in haskell-modules/default.nix. The override attribute is the result of wrapping a function call into callPackage which in turn wraps it into makeOverrideable. That happens in all-packages.nix.
To complete the saga, the extend attribute I suggested exists because all haskell package sets are wrapped with makeExtensible also in haskell-modules/default.nix.

EDIT:
override works with functions as well as attribute sets, so what is said above, that it couldn't give the old arguments, is false. The example in question could be written like this:

let lib = (import <nixpkgs> {}).lib;
    hs-0 = (import <nixpkgs> {}).haskellPackages;
    hs-2 =
      (hs-0.override (oldArgs: { overrides =
        lib.composeExtensions
          (lib.composeExtensions
            (oldArgs.overrides or (self: super: {}))
            (self: super: { x = 42; }))
          (self: super: { y = super.x; });}));
in hs-2.y

This even seems to be the recommended way to do it, please see the discussion linked further down the thread.

@ocharles
Copy link
Contributor Author

Thanks, I wasn't even aware of extend!

@srhb
Copy link
Contributor

srhb commented Oct 16, 2017

Is every example in the documentation rewritable with extend? Since the introduction of overlays, this has only become more confusing, since an overlay in the overrides style will entirely nuke nixpkgs packageOverrides, as far as I can tell. If this is not the case with extend, it seems a better choice. Thoughts?

@ElvishJerricco
Copy link
Contributor

FWIW, this was a duplicate of #26561. See there for discussion on how to work around this with override, and how extend needs to be fixed.

@bgamari
Copy link
Contributor

bgamari commented Jul 3, 2018

Is extend mentioned anywhere in the nixpkgs documentation? It seems its existence really needs to be better documented and advertised.

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/help-overriding-a-derivations-runtime-haskell-dependencies-reproducible-pinned-nix-file-included/8184/7

vst added a commit to telostat/telos.nix that referenced this issue Sep 28, 2022
Previous approach was too naive relying on my assumption that we can
keep overriding Haskell packages. It does not work like that:

NixOS/nixpkgs#25887

I had to step back and introduce an interface that puts more task on
the call-site. But, at least, it works now.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants