-
-
Notifications
You must be signed in to change notification settings - Fork 14.5k
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
lib.pushDownProperties
visibility change breaks external users
#231427
Comments
copying this from the PR above: the code i have in deployment which depends on the now-deprecated { config, ... }:
{
options.my.option = mkOption {
type = types.listOf types.string;
};
config = mkMerge (map generateMoreConfig config.my.option);
# ^ ERROR: `config.*` depends on `config.my.option` => infinite recursion
} assume config = let
genAssertions = conf: (generateMoreConfig conf).assertions;
genUsers = conf: (generateMoreConfig conf).users;
in {
assertions = mkMerge (map genAssertions config.my.option);
users = mkMerge (map genUsers config.my.option);
}; however, this fails if generateMoreConfig = value: lib.mkIf value != "root" {
assertions = ...; users = ...;
}; hence, any more robust equivalent to module-scope generateMoreConfig = value: {
assertions = lib.mkIf value != "root" ...;
users = lib.mkIf value != "root" ...;
}; but you don't want to manually push these down. ideally one could take the original, clean-but-unsupported code: config = mkMerge (map generateMoreConfig config.my.option); and defeat the infinite recursion by constraining the attrnames at the outer layer -- without contorting the logic everywhere below that: config = let
mergeEachAttr (map generateMoreConfig config.my.option);
in {
assertions = mergeEachAttr.assertions;
users = mergeEachAttr.users;
}; hence, this
|
This has a particularly strong requirement that isn't sufficiently solved by any solution that merely derives the returned attrset structure from the values, because the number of items returned from the map can only be determined after I'm confident that whenever the number of The need to specify which options a merge can write to has also come up in "supermodules", which is a slightly different perspective on the same kind of data flow: This is similar to what you describe as
I think it's important for the module system to steer towards solutions that are general and robust. When it comes to robustness, one of the goals has to be the avoidance of unnecessary dependencies between options. Both "supermodules" and your solution suffer a bit from an incentive to be too general when it comes to specifying evaluation dependencies, as that's essentially what you're doing when you say {
assertions = mergeEachAttr.assertions;
users = mergeEachAttr.users;
}; For instance, it would be more robust to specify So I'm ambivalent about whether we should make this pattern easier. Fundamentally what the module system needs, to work well, is some sort of mechanical specification of which options may be written to, to the deepest point possible. To resolve this issue I think we should have at least one of these outcomes
I suppose what's annoying about multiple mkDynamicMerge
{ # deeper is better, to avoid infinite recursion
assertions = null;
systemd.services = null;
users.users = null;
}
myList ... where It wouldn't hurt to keep that comment around as a reminder; very few contributors would read up on mkMerge semantics. I think |
We have another issue with a highly similar use case now (#238592), which can be covered by a perhaps more user friendly function such as Also I've recently had to use it for a different use case as well
So although we can cover a manageable set of just 2 use cases for now, I don't feel confident that those two functions cover everything, so I'm open to undeprecating the |
Describe the bug
lib.modules.pushDownProperties
(and adjacent functions) were made private in module system: Improve error messages around faulty imports #197547.Expected behavior
at the request of @roberth, the intent of this report is to make known any external users that are dependent on the private functions:
lib.modules.{applyModuleArgsIfFunction,dischargeProperties,evalOptionValue,mergeModules,pushDownProperties,unifyModuleSyntax}
. from there we can decide how to balance serving those use cases against the desire to lift internal restrictions around the modules system.if you have a use-case which depends on these private functions, please make it known in this thread.
The text was updated successfully, but these errors were encountered: