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
allow extending lib with an overlay #51797
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your PR. I appreciate your desire and willingness to improve nixpkgs. However, this part of the code is quite sensitive because it is part of many code paths, as also witnessed by its history.
Below are my thoughts about this change. I might have missed something, so please do respond if you find something wrong about my argumentation. I like to learn :)
This change breaks (unwritten?) rules about purity, breaking the purity of pinned projects, which I consider bad as a new default and worse as the only behavior.
Overlay functionality is hard to get right. In my understanding, to implement this for NixOS it will require (lazily) evaluating the configuration twice. One pass to determine lib
with the built-in ../lib
and once more with the new lib
. I'm skeptical about the cost vs benefit here, but I can be convinced with a PR and benchmark. One cost is that some code will have to work for both versions of lib
.
I am also concerned about the complexity caused by having another code path to override lib
. It can already be done from within an overlay, so the differences between the two approaches will have to be explained and kept in mind when making further improvements to NixOS/Nixpkgs top-level glue.
I am not quite convinced of the benefits of this feature yet. The use cases I can think of for overriding lib
are either modifications or additions.
Modifying the behavior of lib
is probably not a good idea because a lot of code depends on the current behavior. So all other modifications should be bugfixes, which are best resolved by PR or patch. New behaviors should be new functions - additions.
Additions are new and therefore under your control, so I don't see why they need to be in lib
. In fact, if you're not qualifying your names with some specific prefix, your addition may in the future collide with an upstream addition.
So why not put an attrset of your own in a regular overlay, or just import a certain file where you need it?
lib/default.nix
Outdated
@@ -7,6 +7,9 @@ let | |||
|
|||
inherit (import ./fixed-points.nix {}) makeExtensible; | |||
|
|||
# Allow extending lib by specifying an overlay file. | |||
finalLib = lib.try (lib.fix (lib.extends (import <lib-overlay>) (self: lib))) lib; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This defeats the split between for example pkgs/top-level/impure.nix
and pkgs/top-level/default.nix
.
Pinning Nix expressions only works because Nixpkgs (a) provides pure versions of things or (b) lets the caller set the argument instead of an impure default. This not only breaks (a), but also breaks (b).
lib/default.nix
Outdated
@@ -29,7 +32,7 @@ let | |||
versions = callLibs ./versions.nix; | |||
|
|||
# module system | |||
modules = callLibs ./modules.nix; | |||
modules = import ./modules.nix { lib = self; inherit finalLib; }; # module argument needs the final lib |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is self
not equal to finalLib
? If equal, finalLib
can be omitted here. If not, either the naming is not according to convention, or there's a bug somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No they are not equal, self
refers to the original lib and finalLib
refers to the potentially extended lib. Only when there has been no overlay specified via lib-overlay
in NIX_PATH
will they be equal (see the definition of finalLib
).
You seem to misunderstand the workings of overlays. They are just a Nix language trick for which you can lookup the definition yourself. The way I use them will not lead to the configuration being evaluated twice, the configuration has no effect on the final lib at all. With your last question you seemed to have missed the whole point of this PR. You seem solely focused on Nixpkgs (which reflects you thinking about overlays and suggested problems and solutions, etc.), while I was mostly focused on Nix/NixOS when making this PR, and this indeed made me miss the important argument you make about purity in Nixpkgs. I have some ideas on how to solve the purity issue and I will fix them, if not only for myself, and I will probably update this pull request to reflect this, but I will not be going to put a lot more effort in this, because of two reasons, 1) even if the purity issue is solved, and even though it is completely optional to use, there will remain people not liking the idea, so it is very unlikely to get merged anyway, and 2) like Eelco mentioned, there are going to big changes in the near future that might make all this work obsolete. I had some other contributions lined up (outside Nix packages), but I am not going to bother, I do not feel like it is worth the effort of trying to get it through (now especially with the big changes ahead), so I will just keep them for local use for now. |
Yes, but taking this feature to its logical conclusion will require it. (Which may or may not be a problem)
How hard it is really depends on the change you're proposing. This one had a very unfortunate complexity because this code is used in many different situations. Most changes will not be like this, so I hope that this pull request will not stop you from contributing in the future. |
I am not sure why you keep thinking this. What is this logical conclusion you are referring to. Could you elaborate? Again, the configuration itself has no effect on lib, you might change
Quite the contrary, almost any change made outside Nix packages and NixOS (application) modules will be like that. |
When lib overlays are not injected through NIX_PATH but through NixOS configuration, NixOS will have to evaluate the configuration in order to know what
What I was trying to convey is that other changes may be worthwhile to try to upstream, but it's your call. |
Which is why this approach is not being taken.
Indeed.
Again, which is why this approach is not taken.
If you just mean
That might very well be, but if I feel my changes are not taken seriously, as for example, it seems to me you have not really looked closely at what I have done and just went with some of your assumptions about overlays, then this does not exactly make me more forthcoming to do so. But back on topic, I have made a different approach that should still address my initially mentioned problems and should also address the valid feedback you made about the potential impurity it could cause, which I will force push after some more testing. |
The update in the PR has simplified things further, and now does only effect NixOS configurations, to lay the issues of potential impurities at rest, and since it does not affect
|
The default argument is still based on If the impurity by default remains, it should be added to the release notes and this PR should include fixes for |
It already is impure at that point in the code. Although that does not invalidate the argument of it making it less pure.
Personally I would find that out of the question, it should not require having to evaluate twice, than your own initial arguments apply and I would be making those same arguments back to you. Thank you for your feedback, by writing this response I realized that I could probably use the very impurity I referenced to, to make it work the way I want, without effecting others. It would only require one minor change in |
@roberth I see my comment about The best alternative would need to add an extra argument at all call sites of I will be closing this PR, because I no longer see it as the best course of action. |
This is sort of a revert and different take on 2703028, which I decided to do after reading github:NixOS/nixpkgs#51797. Preventing our functions from being transparently accessed by derivations and modules makes it easier to figure out what else needs to be upstreamed with them. Where that is still wanted, the new `lib/extension.nix` is an overlay done right, balking at conflicts between Nixpkgs and us.
Motivation for this change
I want to be able to extend lib, not just the lib argument being passed to NixOS modules, but I also want to be able to use the extended lib in e.g. my Nix scripts. I made a comment about this in the existing proposal to extend lib (#51109), but I felt this was not being sufficiently addressed, so I made this counter proposal. I will outline the problems I see with the existing proposal and my own initial plan, and how this proposal addresses them.
The problems with the existing proposal (#51109):
./lib/eval-config.nix
to behave consistently, they would need to be passed the same lib, but right now they are only being passed to the calls to./lib/eval-config.nix
being made innixos/default.nix
, but just to give an example,./lib/eval-config.nix
is also being called innixos/lib/build-vms.nix
. So placing the logic to determine the custom lib innixos/default.nix
seems like the wrong place to me.nixos/default.nix
function. At first this might look like it could be considered a feature, because it would allow you to easily overwrite the lib being passed to modules as an argument, but it would suffer from the same issues as described in (1). This is actually also being warned about in a comment above theevalModules
function defined inlib/modules.nix
. The feature of being able to just change the lib being passed to modules as an argument could be implemented without triggering this issue, e.g. by setting{ _module.args.lib = customLib; }
and changinglib/modules.nix
from inheriting lib tolib = _module.args.lib or lib
, but I consider this is a separate feature request / issue than being able to extend lib in general.NIX_PATH
, so rather than yourlooks-like-nixos-lib
, it is probably better to use something based ontryEval
, like how<nixpkgs-overlays>
is being looked up inpkgs/top-level/impure.nix
.pkgs.lib
. They would still refer to the default lib.../lib
, so these would still refer to default lib. It could be argued that this is fine, because they were implemented with the default lib in mind, unlike the NixOS configuration if we are allowed to modify lib, but it misses the point. I want to be able to modify lib, like Nixpkgs overrides/overlays allow me to modifypkgs
without having to modify a Nixpkgs checkout directly, since the modifications could include tweaks or bug fixes that I might want to have applied everywhere lib is being used.NIX_PATH
prefixnixos-lib
, because it implies the lib only being used for NixOS.My own initial plan to extend lib was to just duplicate what we have to overlay
pkgs
. In my prototype I used<nixpkgs-lib-overlays>
and~/.config/nixpkgs/lib/overlays{,.nix}
. It worked, but it too has problems aside those already mentioned above:pkgs
is much larger than that oflib
. The need for multiple overlays is clear in the case ofpkgs
, since even if you were to forget user defined overlays, it is already needed (or at least useful) inpkgs/top-level/stage.nix
. In case of extending lib, the most common solution right now is to just do something likewith import ./custom-lib.nix;
, where./custom-lib.nix
tends to just hold a few definitions, not something you need complex layering for.Other problems as already noted in the existing proposal by @4z3:
NIX_PATH
prefix<nixpkgs/lib>
, i.e. using the path itself as prefix, you can than no longer extend the default lib (without tricks) by referring to<nixpkgs/lib>
, this would now refer to the custom lib and so result in infinite recursion.This proposal for an extendable lib solves the above mentioned problems as follows:
./lib/eval-config.nix
, this solves (1).lib/modules.nix
, which needs a reference to the final lib (i.e. the extended one) in order to pass it along as an argument, but that is a safe argument to add and completely internal, so (2) does not apply.try
function defined inpkgs/top-level/impure.nix
and added it to the default lib. I wish I could remove the duplication and use lib.try inpkgs/top-level/impure.nix
, but that would require having to import (inefficient to reuse just one definition) or pass along lib as an argument (I am not sure what the impact of that is, considering potential problems as described in (2)). By defining and usingtry
(the interface I would have liked to see for thetryEval
builtin), we avoid (3).<nixpkgs/lib>
when defining our custom lib, solving (9). And the overlay will be applied innixpkgs/lib/default.nix
itself, so everything will automatically refer to the extended lib, with the exception of the default lib itself, which will still be defined in terms of itself (i.e. the way overlays work), which solves (4) and (5).NIX_PATH
prefixlib-overlay
. No,nixos
prefix (solves (6)), because that would imply too much coupling with NixOS, which is not the case, nor anixpkgs
prefix, because like mentioned in (8)nixpkgs
inNIX_PATH
and the NixOSnixpkgs
options refer to Nix packages rather thannixpkgs
the repo. If you talk about lib in the context of NixOS or some Nix script, it always refers to<nixpkgs/lib>
, so I propose no prefix.That should cover all the above mentioned problems.
I just saw the following comment by Eelco at the existing proposal:
So I am not sure how long this pull request will remain relevant, but in the meantime I will be using this.
Things done
sandbox
innix.conf
on non-NixOS)nix-shell -p nox --run "nox-review wip"
./result/bin/
)nix path-info -S
before and after)