-
-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Typed nixpkgs.config
married to NixOS
#57123
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
Conversation
This also makes "Unfree" and "Insecure" options homogenous.
This reverts commit 4ff1ab5. This type was removed because it usually implies a bad design. However, since that commit NixOS modules that can't live without it implemented several ugly ad-hoc replacements for it while other modules that could make a good use of it simply suffer. See the following commits.
What to pay attention to while reviewing:
|
3d91f41
to
8212a5d
Compare
Btw, changes in metrics of Before:
After:
I wouldn't believe the time metric, it's too random, but the rest are most certainly valid. So, despite adding type checking to |
682ccf1
to
9ab9e2a
Compare
haskellPackageOverridesAs for functionToDo we need generic "function to"? I'm biased here, as I like my "dependently typed selector" variant (#44601 (comment)). _file -> fileI've used
At least I know file name. make unifyModuleSyntax idempotent
I don't understand the comment. Which previous patch? As for changes, looks like you've removed pushDownProperties👍 I've also discovered that inside module system sometimes code is duplicated to not introduce extra variables, which take memory. Can you verify that it isn't the case here? opaque typeThis looks like introspection thing. It would generate questions - "what is this?". I guess a "module system manual" is needed now. I'm also not a фанат of introducing concepts without usages - maybe combine into one commit with next one? move defaultsI'm okayish here, just a note that it makes you an author in the last commitlooks very strange, have yet to review it. |
### haskellPackageOverrides
Yep, I guess, if @peti won't answer in the next couple of days I'll just comment it out.
### functionTo
I saw that, I'm 👍 on your proposal there but I think `packageOverrides` has exactly the type I gave it here and that can't be expressed as `*Selector`, AFAICS.
### _file -> file
...
At least I know file name.
By pasting your example into a random config I get
Module `configuration.nix:anon-1' has an unsupported attribute `_file'. This is caused by assignments to the top-level attributes `config' or `options'.
which is the expected correct behavior. You don't have a filename in your example because you `evalModules` on a nix expression, try to supply a path instead, e.g.
nix-repl> evalModules { modules = [ ../simple-2-modules.nix ]; }
### make unifyModuleSyntax idempotent
I don't understand the comment. Which previous patch?
_file -> file (duh)
### pushDownProperties
I don't believe it can make a difference in this case because the function is small and the value is immediately GC'd, but I'll check.
### opaque type
This looks like introspection thing. It would generate questions - "what is this?". I guess a "module system manual" is needed now.
I added some explanations both to the comment above it and to the nixos manual, though.
I'm also not a фанат of introducing concepts without usages - maybe combine into one commit with next one?
The commit that uses it is too big, IMHO.
### move defaults
What, you don't have
```
[alias]
praise = blame -w -M -C
```
in your `~/.gitconfig`, such blasphemy!
### the last commit
looks very strange, have yet to review it.
Yep, it touches a bunch of stuff, unfortunately I didn't come up with a way to break it into pieces.
|
that is because it is a top-level module parameter. You can't place it into random config, you have to massage module first.
You're right. But in my case I did exactly
Error is not in |
```
# simple-2-modules.nix
with import ./simple-module-generator.nix;
{
imports = [ module1 module2 ];
}
```
```
nix-repl> evalModules { modules = [ ../simple-2-modules.nix ]; }
{ config = «error: The option `error' defined in `/home/danbst/dev/simple-2-modules.nix' does not exist.»; options = { ... }; }
```
Error is not in `simple-2-modules.nix` file.
Well, sure, but it works the same on master and I don't see how this can be fixed using the current NixOS modules infra, if you don't specify `file` nor import the module via a path so that `evalModules` would set `file` for you it will be a "best guess", so to say.
|
I removed |
@peti Yes, that's a possible solution :)
But in the meantime I was thinking that maybe it would make sense to make `haskellPackageOverrides` into the default for `haskell.packageOverrides`. E.g. suppose you want to override several `ghc` versions at the same time.
|
But I see now that |
I am sorry, but I don't understand what you mean. |
haskellPackageOverrides
See the new patch. I made your ee1f34e not as violent with the HEAD of this branch. Does that look ok?
@danbst
release notes
Done.
lib/modules.nix: simplify pushDownProperties
Removed. Indeed that produced an overall negative effect of the metrics. I suspect nix needs tail call optimization to make that change useful.
|
No, please don't re-introduce that option. I'm glad it is gone. I also notice there's an |
…ate it This makes a removal of that attribute in ee1f34e less violent. Now it can be properly deprecated using the new infra.
d09994b
to
52e5e07
Compare
No, please don't re-introduce that option. I'm glad it is gone.
By reintroducing it we can deprecate it the same way NixOS does it. I don't like the idea of removing it without deprecating it first. Sure, it wasn't documented but I used it. I'm sure other people still do too. A warning describing what to do is much nicer than a evaluation failure.
See the freshly amended last commit.
I also notice there's an `rPackageOverrides` now which I don't want either (or did I misread the patch?).
In what sense "now"? That option de-facto exists in `config` on master, I simply made the new module system aware of it.
TBH, I would prefer to not deprecate too much too soon as the more I play with this, the more I think that `overlays` themselves should be made a part of `config` (for several reasons, for instance: by adding them there we get `addErrorContext` for their values for free, which is super awesome, try making a type error in the checked part of `config` on this branch, the errors are very nice, IMHO; moreover, the type of `overlays` itself can be simplified as you don't need the `self` argument inside `config` as it gets the `pkgs` argument anyway). So, I wouldn't rush to deprecate random `config` options before the things this makes possible are well-understood.
|
@oxij Your thoughts about overlays in config are very interesting! |
So, I'm reading the finalizing commit... I have two questions:
Then a) it would be possible to add use-flags thing without amending NixOS code, only As for implementation, I think it would require some massaging of config, but should be doable.
|
1. Maybe it would be cleaner to support `imports` directive in config?
In fact, this is supported already, config can be a normal NixOS module:
```nix
{ pkgs, ... }:
{
imports = [
./nothing-interesting-here.nix
];
config = {
checkMeta = true;
doCheckByDefault = false;
};
}
```
Then a) it would be possible to add use-flags thing without amending NixOS code, only `extraScope` needed;
Yes, though I think making a "flake" out of use-flags is undesirable, but that exactly is my plan "C".
b) it would remove the need to pass list of configs, just pass `config = { imports = cfg.config; }`
Hm, my immediate objections to this would be "but `evalModules` takes a list" and "it would make `types.opaque` handling a bit more complicated", but I'll think about it some more.
2. It also not very cool that `pkgs/top-level/default.nix` includes hacky "check only known options".
The `unknowns` hack is because module system doesn't support partial checks, right?
Yep.
Yes, I agree this is sole usage, but it may be harder to sell to others.
I think that this hackyness is ok because it is temporary: it will exist only until all the config options are added to `pkgs/top-level/config.nix`. I'm not very exited at the idea of making a generic mechanism for a use case that is designed to be eliminated ASAP.
Your thoughts about overlays in config are very interesting!
I think so too :] But the actual implementation needs some more work because ATM the fixpoint over pkgs is made too late in `stage.nix` and `config.nix` is fed with the resulting `pkgs` which means that, e.g.
```
{ pkgs, ... }:
{
config = {
packageOverrides = _: {
hello-test = pkgs.hello;
};
};
}
```
fails with infinite recursion error.
I'm still considering if I should fix that in this branch or not.
|
But the actual implementation needs some more work because ATM the fixpoint over pkgs is made too late in `stage.nix` and `config.nix` is fed with the resulting `pkgs` which means that, e.g.
```
{ pkgs, ... }:
{
config = {
packageOverrides = _: {
hello-test = pkgs.hello;
};
};
}
```
fails with infinite recursion error.
Ha-ha, turns out the problem was with `attrsOf`, not with the fixpointing of `pkgs`. I made a variant of `attrsOf` that is lazy in its attribute values and everything now works.
I.e. `packageOverrides` is now equivalent to an overlay for free. Example:
```
{ pkgs, ... }:
{
config = {
packageOverrides = super: {
libcardiacarrest = super.libcardiacarrest.overrideAttrs (oldAttrs: { name = "ha-ha" + oldAttrs.name; });
libpulseaudio = pkgs.libcardiacarrest;
hello-test = pkgs.hello;
};
};
}
```
:]
|
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.
Very cool overall!
|
||
# An opaque value. The result of evaluation of an option of this | ||
# type is a list of { file, value } pairs describing all the | ||
# values assigned to this option (with corresponding files where |
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.
Isn't this the complete opposite of opaque? Having access to all assignments is as transparent as can be, nothing gets hidden, maybe it should be called passthru
instead?
@@ -113,7 +78,7 @@ in | |||
'' | |||
{ allowBroken = true; allowUnfree = true; } | |||
''; | |||
type = configType; | |||
type = types.opaque; |
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.
And with such a type, all the values you can set won't be visible in the manual. I really think the whole config
type checking part should be cleanly separated as a module not tied to pkgs
, then it can be used as type = types.submodule (import ./path/to/config-module.nix)
here, and similarly in pkgs
.
}; | ||
|
||
allowBroken = mkMeta { | ||
default = builtins.getEnv "NIXPKGS_ALLOW_BROKEN" == "1"; |
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.
It would be nice if all the impurities could be put into a separate module which then gets imported with imports = [ ./impure.nix ]
. With nixpkgs becoming a Flake eventually, these impurities will have to be removed, so this would be a good preparation. And it's nice to know all impurities upfront too.
# should use something else. This type is a last resort and should | ||
# only be used when there is absolutely nothing else you can do. | ||
# Most uses of this type imply bad design. | ||
functionTo = elemType: mkOptionType { |
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.
I'll try to get #44601 moving and merged so it can be used here
// args.localSystem); | ||
|
||
crossSystem = if crossSystem0 == null then localSystem | ||
else lib.systems.elaborate crossSystem0; | ||
|
||
# Massage e into a NixOS module. | ||
# We need all this stuff only because we want to support unknown options, | ||
# without them this can be simplified a lot. |
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.
I think this should also indicate how unknown options are not something to stay, which can justify this hacky implementation.
@@ -291,6 +291,15 @@ rec { | |||
functor = (defaultFunctor name) // { wrapped = elemType; }; | |||
}; | |||
|
|||
# Same as attrsOf, but lazy towards attribute values (at the cost of not supporting mkIf and etc) | |||
lazyAttrsOf = elemType: attrsOf elemType // { |
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.
I'm not sure if it's worth introducing this confusing and slightly module breaking type (because it makes mkIf
, etc. not work anymore), just to add support for using the slightly deprecated packageOverrides
as overlays. If people want overlays they can use overlays directly, if the package set they're using doesn't support this then that should be fixed there imo.
options = { | ||
mkOverrides = args: mkMassRebuild ({ | ||
type = types.functionTo (types.lazyAttrsOf (types.uniq types.unspecified)); | ||
default = super: {}; |
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.
Actually I don't think we need all these new types by just not supporting setting packageOverrides
multiple times, which is totally okay because this wasn't supported previously either. packageOverrides
-like ways are kind of deprecated anyways too, we don't need to extend their support by giving new features. If people want to have overlay-like behavior they should use overlays, which package sets can add support for too (e.g. I'm trying to get python to support overlays right now in #67422). In addition, this type introduces yet another slightly different way of overriding packages, different from any other ways. I think we have enough ways of overriding things already, this will only make it more confusing.
So in short, I think this can be types.uniq types.unspecified
without worry, then the controversial functionTo
and lazyAttrsOf
can be dropped from this PR.
Actually I don't think we need all these new types by just not supporting setting `packageOverrides` multiple times, which is totally okay because this wasn't supported previously either.
That's not the only problem it solves, it also allows to do stuff like #57123 (comment)
`packageOverrides`-like ways are kind of deprecated anyways too, we don't need to extend their support by giving new features
Weeell, you see, IMHO the example in #57123 (comment), as noted above, actually gets the whole `overlays` thing into quite a pickle.
With properly typed `packageOverrides`, as in this PR, you don't really need `overlays`, you can just tie the knot over `pkgs` as #57123 (comment) does, which makes `packageOverrides` equivalent to `overlays`.
Moreover, consider this:
- the `overlays` attribute of nixpkgs seems like a part of `config` to me (it configures nixpkgs after all, moreover `grep 'inherit.*overlays'` shows that it _always_ gets inherited together with `config`, thus, IMO, it should be a part of `config`),
- `config` already has `packageOverrides`,
- which, given these changes, can express the same things as `overlays` without `overlays`.
That is to say, the `overlays` attribute of nixpkgs is just a list of `functionsTo (functionsTo (lazyAttrsOf whatever))` that gets merged and tied in a recursive knot using custom code instead of the normal `merge` function of the `lib.types` type it, semantically, has.
Therefore, IMHO, at the very least, we should move `overlays` into `config` (thus, probably, requiring all these new types, unless there's a way to fix the default ones to be more lazy) making `overlays` and `packageOverrides` into slightly different variants of the same thing. Either one of those can then be deprecated, but it is not so obvious to me which one should be deprecated, since by following a bit extended suggestion by @danbst above, we can just make all the files in `~/.nixpkgs/config/` into NixOS modules, thus getting everything else that `overlays` do with custom code for absolutely free for both NixOS and non-NixOS uses of Nixpkgs.
The rest are good suggestions, I'll use them (and the ones by @danbst) when making the v2 of this. Thanks.
|
A problem with this is that this doesn't give you the full power of overlays. I think with how it's defined right now, it's impossible to do multiple changes to the same attribute in different But a big problem with this I'm just seeing is that this will be very unnatural and maybe problematic for other package sets. E.g. suppose you want to override some python package in an overlay-style fashion and you decide to use this new way of defining I guess the thing I'm getting at here is that |
In fact I think the python example doesn't actually have a correct answer, because the overlay would get used for both python2 and python3 |
A problem with this is that this doesn't give you the full power of overlays. I think with how it's defined right now, it's impossible to do multiple changes to the same attribute in different `packageOverrides`, which standard overlays support.
Sure, but that's just because I made this into a simple demonstration of `functionTo`. I could have made `packageOverrides` into `types.opaque` and concatMapped that list to `overlays` to get exactly the opposite effect, for instance.
(But to be honest, I'm very suspicious of the idea of overriding the same thing differently in different modules and expecting anything good to come out of it. Which is why I use `types.uniq` there.)
However it might be possible to weave the different layers of the overlays through the merge function, so this can maybe even gotten to work.
Yes, that is the point. In fact, if `overlays` are moved into that module, the problem gets substantially easier.
But a big problem with this I'm just seeing is that this will be very unnatural and maybe problematic for other package sets. E.g. suppose you want to override some python package in an overlay-style fashion and you decide to use this new way of defining `pythonPackageOverrides` in `config.nix`. What is `self` going to be then? Is it `python.pkgs`/`pythonPackages` or perhaps `python3Packages` because a different overlay changed the default or so?
Even as it is now, in principle, nothing prevents you from doing this:
```
{ pkgs, ... }:
{
config = {
python3PackageOverrides = super: {
whatever = pkgs.python3Packages.whateverElse.overrideAttrs (...);
};
};
}
```
But, yes, ideally `pythonPackageOverrides` and such they should take their own set as `super` (not `pkgs` like `perlPackageOverrides` does, for instance), similarly to `overlays`. Then, even without the versioned ones you could do something like this:
```
{ pkgs, ... }:
{
config = {
pythonPackageOverrides = super:
let pythonPackages = if !super.isPy3k then pkgs.python2Packages else pkgs.python3Packages;
in {
whateverElse = super.whateverElse.overrideAttrs (...);
whatever = pythonPackages.whateverElse;
};
};
}
```
But I think we should just have both `pythonPackageOverrides` and the versioned ones (which is exactly why I wanted #40417).
|
The way you showed there, using I'd really like for this "making Also pinging @nbp who probably has an opinion on this. |
A 5 seconds reply, before a larger one coming over the weekend.
I named it What you do not see is that this attribute is propagated at all the level of the evaluation, and will cause issues as soon as a single option is named file. Either you will accidentally define the option, or you will take the value defined as argument as a file location.
|
@nbp is the longer review still coming? |
My #75031 includes making |
Thank you for your contributions. This has been automatically marked as stale because it has had no activity for 180 days. If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity. Here are suggestions that might help resolve this more quickly:
|
What? Why?
This is the next completely ready piece of #56227.
The four commits from master proceeding this branch, namely 570aed4 4a647dd 5aa813d 83ae1ff, are the previous completely ready piece cherry-picked onto master from #56227 by @danbst.
The previous piece introduced option checking to
pkgs
, this piece marries it tonixpkgs.config
option of NixOS.To make this marriage possible I had to type
packageOverrides
inpkgs
(to remove ad-hoc processing ofnixpkgs.config
in the corresponding NixOS module). To typepackageOverrides
I had to revivetypes.functionTo
.git log
check-meta.nix: move options to
config.nix
This also makes "Unfree" and "Insecure" options homogenous.
lib: resurrect
types.functionTo
This reverts commit 4ff1ab5.
This type was removed because it usually implies a bad design. However, since that
commit NixOS modules that can't live without it implemented several ugly ad-hoc
replacements for it while other modules that could make a good use of it
simply suffer. See the following commits.
pkgs/top-level/config.nix: add various
packageOverrides
Hm, Haskell's one is actually an overlay.
lib/modules.nix: rename _file -> file in unifyModuleSyntax
... and change all of its uses.
Strangely enough, before this
_file
was in the public interface of the modulesystem while
file
was used internally bylib.evalModules
codeafter
lib.unifyModuleSyntax
was applied._file
attribute was introduced in 800f9c2 butI see no reason behind having "_" in the name there, all other attrs
processed by
lib.unifyModuleSyntax
keep their names between its input and output.On the other hand, renaming
_file
intofile
makeslib.unifyModuleSyntax
accept its own output which is useful in cases when you want to modify
modules before shoving them into
lib.evalModules
but you don't want to duplicatelib.unifyModuleSyntax
.lib/modules.nix: make unifyModuleSyntax idempotent
The previous patch made it accept its own output, this also makes it
idempotent.
lib/modules.nix: simplify pushDownProperties
lib/types.nix: add opaque type
pkgs/top-level/impure.nix: move defaults into the preceding
let
blockpkgs/top-level: introduce
configs
argument and marrynixpkgs.config
of NixOS to itThis types
nixpkgs.config
of NixOS withtypes.opaque
type and applies theresulting evaluated value to the newly introduced
configs
argument ofpkgs
.The new
configs
argument is like the oldconfig
argument (still available forconvenience) but a list.
This design was chosen because we can't just make a submodule out of
pkgs/top-level/config.nix
in NixOS becausefirstly, we would have to duplicate all the magic
pkgs/top-level/default.nix
does to
config
in NixOS,secondly, in principle, we might not have all the arguments needed by
pkgs/top-level/config.nix
in NixOS because some of them can becomputed internally by
pkgs
(this is not a problem nowbut it will be a problem in use-flags patchset that comes after), thus all
of those computations will need to be duplicated too,
thirdly, doing it this way keeps NixOS and pkgs separated, so that, in
principle, one could replace NixOS with an alternative thing without duplicating
all of the above once again and/or one could use separate module and type
systems between NixOS and pkgs (
types.opaque
is trivial toimplement in any type system and pkgs can use "types-simple" of Rewrite meta-check.nix type checking logic. #37252 today,
if we were to wish it so).
Note that since this design removes the need to do any preprocessing of
nixpkgs.config
in NixOS all the ad-hoc merging code was removed. Yay!nix-instantiate
environmentnix-env -qaP
diffs/cc @dtzWill @Ericson2314 @matthewbauer @7c6f434c @infinisil @edolstra from the previous PR