-
-
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
module system: Improve error messages around faulty imports #197547
module system: Improve error messages around faulty imports #197547
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.
NACK from me. This is non-compositional and bloats the evalModules arguments, there is a much simpler solution #196584 (comment)
I'm not sure I follow. You may be referring to either commit.
I disagree. It is optional and it will only be set in contexts where
That's unnecessary logic. I'd rather read some extra attribute paths than some custom |
I was blurring things together, let me separate them. Re My real objection, and the lack of modularity, is in hard-coding the |
Cool. I don't really like the name I came up with. I've also considered
It is conveniently low overhead when it comes to most evalModules calls (submodules), but I have not made a measurement.
That is exactly the intent. Some things shouldn't be left to opinion.
We already have this, and a Final question If we have
then wouldn't it make sense to have
If you agree, and the module system can't know about flake attributes, we'd need a generic mechanism. I this case the disagreement would be with infinisil. |
What overhead do you mean? Syntactically,
We shouldn't layer flake-specific knowledge into the module system.
I understand your disagreement with my stance, but I object to this characterization. The abstract principles I'm applying here, of composable interfaces without layering violations, are principles I hold because I think they result in better software and I'm applying them because I think this case is within the context that those principles are sound. The "ivory tower" comment suggests that there is some necessary conflict between theory and practice and I'm choosing theory here, but there is no such conflict. In this particular case, I only think this is a "loss for users" in a short term sense. The ultimate cost of this decision, and more importantly making decisions like this down the road, is that the code becomes less maintainable, more tightly coupled, more brittle, less usable in new contexts. Especially since the exact same functionality can be moved to components that are actually flake-specific, I see no reason to add this here that wouldn't also result in more and more cruft over time. |
... and
We disagree.
Each decision should be judged by its merit.
It can not. It's supposed to be a convenience, not an eyesore. We've already discussed this.
I find this disrespectful. Infinisil and I have been maintaining and improving the module system for the last couple of years, with diligence and care. Why wouldn't we continue to do so? |
Ah, right. Would be nice to see measurements here but makes sense.
Nix is a language for package management. Why shouldn't lib have knowledge of systems and derivations? As for the package issue, this does actually bother me a bit since it encourages testing only on NixOS and discourages building a testing interface that is decoupled from the distro. But there is also an important difference between a layering violation in leaf applications of a system and layering violations in a core library component, one which is actually used in many different contexts.
I agree, my point is that a) on this particular case, this is a small step of additional tight coupling and magic surprise and b) the reasoning applied in this case, if applied in future decisions, would equally justify further tight coupling and magic surprise.
I wasn't making a comment on your diligence or care, and I appreciate the ongoing work on the module system. I was making a claim about the logical implication of the reasoning being applied here, not about the quality of your efforts. If you disagree, OK, you disagree, I think that you're wrong and that the overall quality of the work will suffer as a result but that doesn't mean I think you're not overall doing an important job well. |
9c1a30e
to
d61f364
Compare
I've pivoted the PR to type checking instead of type matching, and it now covers an extra set of errors where we can be quite helpful with our error messages. |
d61f364
to
4c4a9d3
Compare
I've addressed the comments and pivoted the change towards checking
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 took another close look at this and I think I'm onboard with this idea, though I still have some things to point out.
And in addition to the points below, this should also have documentation.
2f7c660
to
7624c5b
Compare
This simplifies the documentation. `configuration` is implied by `_type`.
3666e3b
to
eab660d
Compare
Thanks for the many reviews ❤️ |
Here's a PR for the postponed |
@roberth as far as i can tell, my use case isn't covered by non-deprecated functions. as you expected, external uses of these are a bit gnarly, but i'll try here to condense my justification for its use.
{ 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
|
@uninsane That seems like a valid use case. Could you create an issue for it? |
the if you prefer i formalize that feedback through some issue, i'm happy to do that, but i'd need guidance because i have so much less context here than you that i don't know what the substance of any issue here actually is. |
My goal is just to have a separate thread for it, not to put you through the bureaucratic wringer or something. This thread already has over a hundred messages, and changing the topic of a long thread makes things harder to find. GitHub hiding the middle also doesn't help.
While there's an element of there being a fundamental problem that prevents the simplest fix imaginable, that doesn't stop is from finding practical solutions, like you did!
Most issues are conversations. They don't have to be full-on research presentations. You might fill in the template and paste your existing prose in the appropriate header(s). Markdown source is under the comment edit button ;) |
This enables a module system feature documented here: https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules-param-class This allows the mistake of loading a NixOS module into home-manager to be caught, provided that a module declares what it's for with a `_class` attribute. The class feature has been available in the module system since NixOS/nixpkgs#197547, merged May 6, 2023. It has been part of all releases since 23.05-beta. The last NixOS release that did _not_ support it has been end-of-life for close to a year now. It is not expected that users declare the `_type`, because the payoff is small. It is only expected to be set by generic code, such as functions or libraries that help with the "publishing" of modules (e.g. flake-parts, flake-utils). Example: (lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; modules = [{ _class = "nixos"; imports = [ ./foo.nix ]; }]; }).activation-script Corresponding error: error: The module <unknown-file> was imported into homeManager instead of nixos. (`<unknown-file>` can be improved by also setting `_file`, if known; a much older feature)
This enables a module system feature documented here: https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules-param-class For example, it allows a mistake to be caught, which is loading a NixOS module into home-manager. This only works when the offending module declares what it's for with a `_class` attribute. It is not expected that users declare the `_type`, because the payoff is small. It is only expected to be set by generic code, such as functions or libraries that help with the "publishing" of modules (e.g. flake-parts, flake-utils). The class feature has been available in the module system since NixOS/nixpkgs#197547, merged May 6, 2023. It has been part of all releases since 23.05-beta. The last NixOS release that did _not_ support it has been end-of-life for close to a year now. Example: (lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; modules = [{ _class = "nixos"; imports = [ ./foo.nix ]; }]; }).activation-script Corresponding error: error: The module <unknown-file> was imported into homeManager instead of nixos. (`<unknown-file>` can be improved by also setting `_file`, if known; a much older feature)
This enables a module system feature documented here: https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules-param-class For example, it allows a mistake to be caught, which is loading a NixOS module into home-manager. This only works when the offending module declares what it's for with a `_class` attribute. It is not expected that users declare the `_type`, because the payoff is small. It is only expected to be set by generic code, such as functions or libraries that help with the "publishing" of modules (e.g. flake-parts, flake-utils). The class feature has been available in the module system since NixOS/nixpkgs#197547, merged May 6, 2023. It has been part of all releases since 23.05-beta. The last NixOS release that did _not_ support it has been end-of-life for close to a year now. Example: (lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; modules = [{ _class = "nixos"; imports = [ ./foo.nix ]; }]; }).activation-script Corresponding error: error: The module <unknown-file> was imported into homeManager instead of nixos. (`<unknown-file>` can be improved by also setting `_file`, if known; a much older feature)
This enables a module system feature documented here: https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules-param-class For example, it allows a mistake to be caught, which is loading a NixOS module into home-manager. This only works when the offending module declares what it's for with a `_class` attribute. It is not expected that users declare the `_type`, because the payoff is small. It is only expected to be set by generic code, such as functions or libraries that help with the "publishing" of modules (e.g. flake-parts, flake-utils). The class feature has been available in the module system since NixOS/nixpkgs#197547, merged May 6, 2023. It has been part of all releases since 23.05-beta. The last NixOS release that did _not_ support it has been end-of-life for close to a year now. Example: (lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; modules = [{ _class = "nixos"; imports = [ ./foo.nix ]; }]; }).activation-script Corresponding error: error: The module <unknown-file> was imported into homeManager instead of nixos. (`<unknown-file>` can be improved by also setting `_file`, if known; a much older feature) PR #5339
This is intended as a module system "library" in the format <flake>.modules.<class>.<name> where class is e.g. "nixos" or "homeManager", and the name is of the author's choice. Modules that can be loaded in any module system application should use the name "generic". - Implemented in the module system in NixOS/nixpkgs#197547 - Class parameter for checking: https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules-param-class
Probably a missed left over from somewhere in the commit 58f385f. As can be seen in that commit where this line was introduced, "$@" was also just emptied by the last `set` call in line 169. This line is currently valid, but breaks suddenly when somewhere earlier a `set --` instruction is used in the future. Neither in commit 58f385f nor in PR NixOS#197547 have I found anything stating that this "defect" was intentional.
Probably a missed left over from somewhere in the commit 9420324. As can be seen in that commit where this line was introduced, "$@" was also just emptied by the last `set` call in line 169. This line is currently valid, but breaks suddenly when somewhere earlier a `set --` instruction is used in the future. Neither in commit 9420324 nor in PR NixOS/nixpkgs#197547 have I found anything stating that this "defect" was intentional.
This enables a module system feature documented here: https://nixos.org/manual/nixpkgs/stable/index.html#module-system-lib-evalModules-param-class For example, it allows a mistake to be caught, which is loading a NixOS module into home-manager. This only works when the offending module declares what it's for with a `_class` attribute. It is not expected that users declare the `_type`, because the payoff is small. It is only expected to be set by generic code, such as functions or libraries that help with the "publishing" of modules (e.g. flake-parts, flake-utils). The class feature has been available in the module system since NixOS/nixpkgs#197547, merged May 6, 2023. It has been part of all releases since 23.05-beta. The last NixOS release that did _not_ support it has been end-of-life for close to a year now. Example: (lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; modules = [{ _class = "nixos"; imports = [ ./foo.nix ]; }]; }).activation-script Corresponding error: error: The module <unknown-file> was imported into homeManager instead of nixos. (`<unknown-file>` can be improved by also setting `_file`, if known; a much older feature) PR nix-community#5339
Description of changes
Make explicit the module "class", which identifies the module system application, such as
"nixos"
,"darwin"
or"homeManager"
. This allows us to print an appropriate error when importing for example a home-manager module into NixOS:The module foo.nix#darwinModules.default was imported into nixos instead of home-manager.
I do not expect users or module authors to set the
class
attribute in their modules (although they may). Instead I envision a library like flake-parts to set this for us.Use the new class information to automatically import the appropriate default module from a flake.Detect other mistakes that involve the importing
_type
-carrying values. For instance importing anixosSystem
result into NixOps network appears to be a somewhat common mistake, and for good reason. These changes detect this scenario and explain what to do instead.Depends on NixOS/nix#7186
Things done
sandbox = true
set innix.conf
? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)nixos/doc/manual/md-to-db.sh
to update generated release notes