From 992349ba7a200ec8bb0256587bd347966698d884 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Fri, 29 Aug 2025 11:26:46 +0300 Subject: [PATCH 01/21] wip: rewrite squash squash --- README.md | 50 ---- examples/module/flake.lock | 192 +++++++++++++ examples/module/flake.nix | 39 +++ examples/module/module.nix | 17 ++ flake.lock | 47 +-- flake.nix | 36 +-- lib/attrset.nix | 9 +- lib/configurations/apply.nix | 62 ---- lib/configurations/default.nix | 268 ------------------ lib/configurations/host.nix | 123 -------- lib/configurations/module.nix | 72 ----- lib/configurations/rice.nix | 68 ----- lib/default.nix | 53 ++-- lib/extension.nix | 183 ------------ lib/extensions/args.nix | 51 ---- lib/extensions/base/default.nix | 20 -- lib/extensions/base/hosts.nix | 170 ----------- lib/extensions/base/rices.nix | 73 ----- lib/maintainers.nix | 30 -- lib/modules/config/denix.nix | 63 ++++ lib/modules/config/moduleSystems/darwin.nix | 3 + lib/modules/config/moduleSystems/default.nix | 81 ++++++ lib/modules/config/moduleSystems/home.nix | 3 + lib/modules/config/moduleSystems/myconfig.nix | 55 ++++ lib/modules/config/moduleSystems/nixos.nix | 3 + lib/modules/default.nix | 119 ++++++++ lib/options.nix | 251 +++++++++------- lib/{ => toplevel}/fixed-points.nix | 22 +- lib/toplevel/lib.nix | 140 +++++++++ lib/umport.nix | 56 ---- .../extensions/extension.nix | 41 --- templates/extensions-collection/flake.nix | 13 - templates/minimal-no-rices/flake.nix | 56 ---- .../hosts/desktop/default.nix | 6 - .../hosts/desktop/hardware.nix | 23 -- .../modules/config/constants.nix | 11 - .../minimal-no-rices/modules/config/home.nix | 22 -- .../minimal-no-rices/modules/config/user.nix | 35 --- templates/minimal/flake.nix | 56 ---- templates/minimal/hosts/desktop/default.nix | 7 - templates/minimal/hosts/desktop/hardware.nix | 23 -- .../minimal/modules/config/constants.nix | 11 - templates/minimal/modules/config/home.nix | 22 -- templates/minimal/modules/config/user.nix | 35 --- templates/minimal/rices/dark/default.nix | 4 - 45 files changed, 935 insertions(+), 1789 deletions(-) delete mode 100644 README.md create mode 100644 examples/module/flake.lock create mode 100644 examples/module/flake.nix create mode 100644 examples/module/module.nix delete mode 100644 lib/configurations/apply.nix delete mode 100644 lib/configurations/default.nix delete mode 100644 lib/configurations/host.nix delete mode 100644 lib/configurations/module.nix delete mode 100644 lib/configurations/rice.nix delete mode 100644 lib/extension.nix delete mode 100644 lib/extensions/args.nix delete mode 100644 lib/extensions/base/default.nix delete mode 100644 lib/extensions/base/hosts.nix delete mode 100644 lib/extensions/base/rices.nix delete mode 100644 lib/maintainers.nix create mode 100644 lib/modules/config/denix.nix create mode 100644 lib/modules/config/moduleSystems/darwin.nix create mode 100644 lib/modules/config/moduleSystems/default.nix create mode 100644 lib/modules/config/moduleSystems/home.nix create mode 100644 lib/modules/config/moduleSystems/myconfig.nix create mode 100644 lib/modules/config/moduleSystems/nixos.nix create mode 100644 lib/modules/default.nix rename lib/{ => toplevel}/fixed-points.nix (73%) create mode 100644 lib/toplevel/lib.nix delete mode 100644 lib/umport.nix delete mode 100644 templates/extensions-collection/extensions/extension.nix delete mode 100644 templates/extensions-collection/flake.nix delete mode 100644 templates/minimal-no-rices/flake.nix delete mode 100644 templates/minimal-no-rices/hosts/desktop/default.nix delete mode 100644 templates/minimal-no-rices/hosts/desktop/hardware.nix delete mode 100644 templates/minimal-no-rices/modules/config/constants.nix delete mode 100644 templates/minimal-no-rices/modules/config/home.nix delete mode 100644 templates/minimal-no-rices/modules/config/user.nix delete mode 100644 templates/minimal/flake.nix delete mode 100644 templates/minimal/hosts/desktop/default.nix delete mode 100644 templates/minimal/hosts/desktop/hardware.nix delete mode 100644 templates/minimal/modules/config/constants.nix delete mode 100644 templates/minimal/modules/config/home.nix delete mode 100644 templates/minimal/modules/config/user.nix delete mode 100644 templates/minimal/rices/dark/default.nix diff --git a/README.md b/README.md deleted file mode 100644 index 98b4991..0000000 --- a/README.md +++ /dev/null @@ -1,50 +0,0 @@ -

- - - - - Denix - - -

- -Denix is a Nix library designed to help you build scalable configurations for [NixOS](https://nixos.org/), [Home Manager](https://github.com/nix-community/home-manager), and [Nix-Darwin](https://github.com/nix-darwin/nix-darwin). - -## Documentation - -You can find the documentation here: [Denix Documentation](https://yunfachi.github.io/denix/getting_started/introduction) - -## Key Features - -### Modular System -Custom modules allow you to define options and related configurations in a flexible way, simplifying the management of your entire system. - -### Hosts and Rices -* **Hosts**: Unique configurations tailored for each machine. -* **Rices**: Customizations that can be applied to all hosts. - -### Extensions -Write your own extensions for the Denix or use existing ones that add new functions and modules. - -### Unified NixOS, Home Manager, and Nix-Darwin Configurations -Write your NixOS, Home Manager, and Nix-Darwin configurations in a single file*, and Denix will automatically handle the separation for you. - -## Templates - -### [minimal](./templates/minimal/) (recommended) -Hosts, rices, and initial modules for quick setup: -```sh -nix flake init -t github:yunfachi/denix#minimal -``` - -### [minimal-no-rices](./templates/minimal-no-rices/) -Hosts and initial modules without rices: -```sh -nix flake init -t github:yunfachi/denix#minimal-no-rices -``` - -### [extensions-collection](./templates/extensions-collection/) -Flake for creating your own collection of Denix extensions: -```sh -nix flake init -t github:yunfachi/denix#extensions-collection -``` diff --git a/examples/module/flake.lock b/examples/module/flake.lock new file mode 100644 index 0000000..9fb6730 --- /dev/null +++ b/examples/module/flake.lock @@ -0,0 +1,192 @@ +{ + "nodes": { + "denix": { + "inputs": { + "home-manager": "home-manager", + "nix-darwin": "nix-darwin", + "nixpkgs": "nixpkgs", + "nixpkgs-lib": "nixpkgs-lib", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "path": "../../.", + "type": "path" + }, + "original": { + "path": "../../.", + "type": "path" + }, + "parent": [] + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "denix", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "denix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1754613544, + "narHash": "sha256-ueR1mGX4I4DWfDRRxxMphbKDNisDeMPMusN72VV1+cc=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "cc2fa2331aebf9661d22bb507d362b39852ac73f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "master", + "repo": "home-manager", + "type": "github" + } + }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "denix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1751313918, + "narHash": "sha256-HsJM3XLa43WpG+665aGEh8iS8AfEwOIQWk3Mke3e7nk=", + "owner": "nix-darwin", + "repo": "nix-darwin", + "rev": "e04a388232d9a6ba56967ce5b53a8a6f713cdfcf", + "type": "github" + }, + "original": { + "owner": "nix-darwin", + "repo": "nix-darwin", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1754498491, + "narHash": "sha256-erbiH2agUTD0Z30xcVSFcDHzkRvkRXOQ3lb887bcVrs=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c2ae88e026f9525daf89587f3cbee584b92b6134", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1754184128, + "narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "02e72200e6d56494f4a7c0da8118760736e41b60", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1754340878, + "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cab778239e705082fe97bb4990e0d24c50924c04", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1756159630, + "narHash": "sha256-ohMvsjtSVdT/bruXf5ClBh8ZYXRmD4krmjKrXhEvwMg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "84c256e42600cb0fdf25763b48d28df2f25a0c8b", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1754416808, + "narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "denix": "denix", + "nixpkgs": "nixpkgs_3" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/examples/module/flake.nix b/examples/module/flake.nix new file mode 100644 index 0000000..4f51159 --- /dev/null +++ b/examples/module/flake.nix @@ -0,0 +1,39 @@ +{ + inputs = { + #nixpkgs.url = "/home/yunfachi/files/desktop/git/nixpkgs"; + denix.url = "../../."; + #denix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + { + denix, + self, + ... + }: + let + delib = denix.lib; + in + { + denixConfiguration = delib.denixConfiguration { + modules = [ ./module.nix ]; + }; + + nixosModules.default = delib.compileModule { + moduleSystem = "nixos"; + configuration = self.denixConfiguration; + }; + + homeModules.default = delib.compileModule { + moduleSystem = "home"; + configuration = self.denixConfiguration; + /* + applyMyConfig = + { myconfig, ... }: + { + imports = myconfig.type.getSubModules; + }; + */ + }; + }; +} diff --git a/examples/module/module.nix b/examples/module/module.nix new file mode 100644 index 0000000..bebc842 --- /dev/null +++ b/examples/module/module.nix @@ -0,0 +1,17 @@ +{ delib, ... }: +{ + modules."programs.module" = { + options = with delib; { + enable = boolOption true; + test = intOption 0; + }; + + myconfig.ifEnabled = { + programs.module.test = 213; + }; + + nixos.ifEnabled = { + nixpkgs.hostPlatform = "x86_64-linux"; + }; + }; +} diff --git a/flake.lock b/flake.lock index 8ea9049..f25ae56 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,11 @@ ] }, "locked": { - "lastModified": 1754613544, - "narHash": "sha256-ueR1mGX4I4DWfDRRxxMphbKDNisDeMPMusN72VV1+cc=", + "lastModified": 1756261190, + "narHash": "sha256-eiy0klFK5EVJLNilutR7grsZN/7Itj9DyD75eyOf83k=", "owner": "nix-community", "repo": "home-manager", - "rev": "cc2fa2331aebf9661d22bb507d362b39852ac73f", + "rev": "77f348da3176dc68b20a73dab94852a417daf361", "type": "github" }, "original": { @@ -65,11 +65,11 @@ ] }, "locked": { - "lastModified": 1751313918, - "narHash": "sha256-HsJM3XLa43WpG+665aGEh8iS8AfEwOIQWk3Mke3e7nk=", + "lastModified": 1755825449, + "narHash": "sha256-XkiN4NM9Xdy59h69Pc+Vg4PxkSm9EWl6u7k6D5FZ5cM=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "e04a388232d9a6ba56967ce5b53a8a6f713cdfcf", + "rev": "8df64f819698c1fee0c2969696f54a843b2231e8", "type": "github" }, "original": { @@ -80,32 +80,35 @@ }, "nixpkgs": { "locked": { - "lastModified": 1754498491, - "narHash": "sha256-erbiH2agUTD0Z30xcVSFcDHzkRvkRXOQ3lb887bcVrs=", - "owner": "nixos", + "lastModified": 1756410287, + "narHash": "sha256-X7KtENXtzWShJwynb4jk14Sg+9yhRS/zbE5qh+ZgMt0=", + "owner": "yunfachi", "repo": "nixpkgs", - "rev": "c2ae88e026f9525daf89587f3cbee584b92b6134", + "rev": "f222f92233a60bc85e7eb7af81380da61073597d", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "owner": "yunfachi", + "ref": "patch-2", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-lib": { "locked": { - "lastModified": 1754184128, - "narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "02e72200e6d56494f4a7c0da8118760736e41b60", + "dir": "lib", + "lastModified": 1756478791, + "narHash": "sha256-F2fHTBUA/S99Kwv99k51Xb990LIihlK2Ys29rrTfMoE=", + "owner": "yunfachi", + "repo": "nixpkgs", + "rev": "da2a71835653a4d11bbe3738830d90f048ae9d30", "type": "github" }, "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", + "dir": "lib", + "owner": "yunfachi", + "ref": "patch-2", + "repo": "nixpkgs", "type": "github" } }, @@ -132,11 +135,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1754416808, - "narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=", + "lastModified": 1755960406, + "narHash": "sha256-RF7j6C1TmSTK9tYWO6CdEMtg6XZaUKcvZwOCD2SICZs=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864", + "rev": "e891a93b193fcaf2fc8012d890dc7f0befe86ec2", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 61df5ba..9e0beac 100644 --- a/flake.nix +++ b/flake.nix @@ -2,12 +2,21 @@ description = "Nix library for creating scalable NixOS, Home Manager, and Nix-Darwin configurations with modules, hosts, and rices."; inputs = { - nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; + #nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; + nixpkgs-lib.url = "github:yunfachi/nixpkgs/patch-2?dir=lib"; pre-commit-hooks = { url = "github:cachix/git-hooks.nix"; }; - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + /** + The reason for separating nixpkgs and nixpkgs-lib is that nixpkgs, home-manager, + and nix-darwin are inputs used exclusively for creating the system configuration + (e.g., lib.nixosSystem, ...). nixpkgs is an input, which implies user overrides + to their own channel, while nixpkgs-lib is a library used by Denix, and it should + not be overridden by the user without a special reason. + */ + #nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixpkgs.url = "github:yunfachi/nixpkgs/patch-2"; home-manager = { url = "github:nix-community/home-manager/master"; inputs.nixpkgs.follows = "nixpkgs"; @@ -44,29 +53,6 @@ inherit home-manager nix-darwin nixpkgs; }; - templates = { - minimal = { - description = '' - Minimal configuration with hosts, rices, constants, home manager, and user config. - It is not recommended to use if this is your first time or if you haven't read or don't plan to read the documentation. - ''; - path = ./templates/minimal; - }; - minimal-no-rices = { - description = '' - Minimal configuration with hosts, constants, home manager, and user config. - It is not recommended to use if this is your first time or if you haven't read or don't plan to read the documentation. - ''; - path = ./templates/minimal-no-rices; - }; - extensions-collection = { - description = '' - Flake for creating your own collection of Denix extensions. - ''; - path = ./templates/extensions-collection; - }; - }; - checks = forAllSystems (system: { pre-commit-check = pre-commit-hooks.lib.${system}.run { src = ./.; diff --git a/lib/attrset.nix b/lib/attrset.nix index bb79604..b97d445 100644 --- a/lib/attrset.nix +++ b/lib/attrset.nix @@ -1,12 +1,11 @@ { lib, ... }: { getAttrByStrPath = - strPath: attrset: default: - lib.attrByPath (lib.splitString "." strPath) default attrset; + set: strPath: default: + lib.attrByPath (lib.splitString "." strPath) default set; - setAttrByStrPath = strPath: value: lib.setAttrByPath (lib.splitString "." strPath) value; + setAttrByStrPath = value: strPath: lib.setAttrByPath (lib.splitString "." strPath) value; hasAttrs = - attrs: attrset: - if attrs != [ ] then builtins.any (attr: builtins.hasAttr attr attrset) attrs else true; + set: attrs: if attrs != [ ] then builtins.any (attr: builtins.hasAttr attr set) attrs else true; } diff --git a/lib/configurations/apply.nix b/lib/configurations/apply.nix deleted file mode 100644 index 40c022e..0000000 --- a/lib/configurations/apply.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ - useHomeManagerModule, - homeManagerUser, - moduleSystem, - myconfigName, - ... -}: -rec { - configForModuleSystem = - { - nixos ? { }, - home ? { }, - darwin ? { }, - }: - { - inherit nixos home darwin; - } - .${moduleSystem}; - - myconfig = _myconfig: { ${myconfigName} = _myconfig; }; - - nixos = - _nixos: - configForModuleSystem { - nixos = _nixos; - home = { }; - darwin = { }; - }; - home = - _home: - configForModuleSystem { - nixos = - if useHomeManagerModule then - { - home-manager.users.${homeManagerUser} = _home; - } - else - { }; - home = _home; - darwin = - if useHomeManagerModule then - { - home-manager.users.${homeManagerUser} = _home; - } - else - { }; - }; - darwin = - _darwin: - configForModuleSystem { - nixos = { }; - home = { }; - darwin = _darwin; - }; - - listOfEverything = _myconfig: _nixos: _home: _darwin: [ - (myconfig _myconfig) - (nixos _nixos) - (home _home) - (darwin _darwin) - ]; -} diff --git a/lib/configurations/default.nix b/lib/configurations/default.nix deleted file mode 100644 index be482f6..0000000 --- a/lib/configurations/default.nix +++ /dev/null @@ -1,268 +0,0 @@ -{ - delib, - lib, - nixpkgs, - home-manager, - nix-darwin, - ... -}@args: -{ - configurations = - { - # Denix - myconfigName ? "myconfig", - denixLibName ? "delib", - moduleSystem ? null, # TODO: remove the default value once the deprecated isHomeManager is removed - extensions ? [ ], - # Umport - paths ? [ ], - exclude ? [ ], - recursive ? true, - # System - specialArgs ? { }, - extraModules ? [ ], - # Inputs - nixpkgs ? args.nixpkgs, - home-manager ? args.home-manager, - nix-darwin ? args.nix-darwin, - # Home Manager - homeManagerNixpkgs ? nixpkgs, - homeManagerUser ? null, # not default value! - useHomeManagerModule ? true, - isHomeManager ? null, # TODO: DEPRECATED since 2025/05/05 - # Dev - mkConfigurationsSystemExtraModule ? { - nixpkgs.hostPlatform = "x86_64-linux"; - }, # just a plug; FIXME - }@topArgs: - ( - if topArgs ? isHomeManager then - builtins.trace "'delib.configurations :: isHomeManager' is deprecated, use 'delib.configurations :: moduleSystem' with values \"nixos\", \"home\", or \"darwin\" instead." - else - _: _ - ) - ( - let - moduleSystem = - topArgs.moduleSystem or ( - if isHomeManager == null then - builtins.abort "Please specify 'delib.configurations :: moduleSystem'. Valid values are \"nixos\", \"home\", or \"darwin\"." - else - (if isHomeManager then "home" else "nixos") - ); - - files = delib.umport { inherit paths exclude recursive; }; - - mkApply = - moduleSystem: useHomeManagerModule: - import ./apply.nix { - inherit - useHomeManagerModule - homeManagerUser - moduleSystem - myconfigName - ; - }; - mkDenixLib = - { - config, - moduleSystem, - useHomeManagerModule, - homeManagerUser, - currentHostName ? null, - }: - let - extendedDelib = delib.recursivelyExtend ( - final: prev: - let - apply = mkApply moduleSystem useHomeManagerModule; - inherit (final) _callLib; - in - { - _callLibArgs = prev._callLibArgs // { - inherit - apply - config - myconfigName - currentHostName - useHomeManagerModule - homeManagerUser - ; - }; - - inherit (_callLib ./host.nix) - host - hostSubmoduleOptions - hostOption - hostsOption - hostNamesAssertions - ; - - inherit (_callLib ./module.nix) module; - - inherit (_callLib ./rice.nix) - rice - riceSubmoduleOptions - riceOption - ricesOption - riceNamesAssertions - ; - } - ); - in - extendedDelib.withExtensions extensions; - - mkSystem = - { - moduleSystem, - useHomeManagerModule, - homeManagerUser, - homeManagerSystem, - currentHostName, - isInternal ? false, - internalExtraModules ? (moduleSystem_: [ ]), - }@args: - if homeManagerUser == null && (useHomeManagerModule || moduleSystem == "home") then - abort "Please specify 'delib.configurations :: homeManagerUser' or 'delib.host :: homeManagerUser'." - else - let - useHomeManagerModule = - if isInternal then topArgs.useHomeManagerModule or true else args.useHomeManagerModule; - homeManagerUser = if isInternal then topArgs.homeManagerUser or null else args.homeManagerUser; - - extensionsModules = builtins.concatMap (extension: extension.modules) extensions; - nixosSystem = nixpkgs.lib.nixosSystem { - specialArgs = specialArgs // { - ${denixLibName} = mkDenixLib { - config = nixosSystem.config; - moduleSystem = "nixos"; - inherit currentHostName useHomeManagerModule homeManagerUser; - }; - inherit useHomeManagerModule homeManagerUser; # otherwise it's impossible to make config.home-manager optional when not useHomeManagerModule. - }; - modules = - (internalExtraModules "nixos") - ++ extraModules - ++ files - ++ (lib.optionals useHomeManagerModule [ home-manager.nixosModules.home-manager ]) - ++ extensionsModules; - }; - homeSystem = home-manager.lib.homeManagerConfiguration { - extraSpecialArgs = specialArgs // { - ${denixLibName} = mkDenixLib { - config = homeSystem.config; - moduleSystem = "home"; - inherit currentHostName useHomeManagerModule homeManagerUser; - }; - inherit useHomeManagerModule homeManagerUser; # otherwise it's impossible to make config.home-manager optional when not useHomeManagerModule. - }; - pkgs = homeManagerNixpkgs.legacyPackages.${homeManagerSystem}; - modules = (internalExtraModules "home") ++ extraModules ++ files ++ extensionsModules; - }; - darwinSystem = nix-darwin.lib.darwinSystem { - specialArgs = specialArgs // { - ${denixLibName} = mkDenixLib { - config = darwinSystem.config; - moduleSystem = "darwin"; - inherit currentHostName useHomeManagerModule homeManagerUser; - }; - inherit useHomeManagerModule homeManagerUser; # otherwise it's impossible to make config.home-manager optional when not useHomeManagerModule. - }; - # FIXME: is this really necessary? - # pkgs = ...; - modules = - (internalExtraModules "darwin") - ++ extraModules - ++ files - ++ (lib.optionals useHomeManagerModule [ home-manager.darwinModules.home-manager ]) - ++ extensionsModules; - }; - in - { - nixos = nixosSystem; - home = homeSystem; - darwin = darwinSystem; - } - .${moduleSystem}; - - inherit - ( - { - rices = { }; - } - // (mkSystem { - # TODO: maybe add moduleSystem = "empty", which "apply" would skip entirely*? - moduleSystem = "nixos"; - useHomeManagerModule = topArgs.useHomeManagerModule; # FIXME - homeManagerUser = "user"; - homeManagerSystem = "x86_64-linux"; # just a plug; FIXME - currentHostName = null; - isInternal = true; - internalExtraModules = _: [ mkConfigurationsSystemExtraModule ]; - }).config.${myconfigName} - ) - hosts - rices - ; - - mkHost = - { - host, - rice ? null, - }: - let - myconfig = system.config.${myconfigName}; - - system = mkSystem { - inherit moduleSystem; - inherit (host) useHomeManagerModule homeManagerUser homeManagerSystem; - currentHostName = host.name; - internalExtraModules = - moduleSystem: - let - apply = mkApply moduleSystem host.useHomeManagerModule; - in - [ - ( - { options, ... }: - { - config.${myconfigName} = { - inherit host; - } - // lib.optionalAttrs (options.${myconfigName} ? rice) { inherit rice; }; - } - ) - ] - ++ (lib.optionals (rice != null) ( - apply.listOfEverything rice.myconfig rice.nixos rice.home rice.darwin - )) - ++ builtins.concatMap ( - riceName: - (apply.listOfEverything rices.${riceName}.myconfig rices.${riceName}.nixos rices.${riceName}.home) - rices.${riceName}.darwin - ) (rice.inherits or [ ]); - }; - in - system; - - configurations = - let - mkHostAttrs = - riceName: rice: hostName: host: - lib.optionalAttrs (!rice.inheritanceOnly or false) { - "${lib.optionalString (moduleSystem == "home") "${host.homeManagerUser}@"}${hostName}${ - lib.optionalString (riceName != null) "-${riceName}" - }" = - mkHost { - inherit host; - rice = - if rice == null then (if (host.rice or null) == null then null else rices.${host.rice}) else rice; - }; - }; - in - lib.concatMapAttrs (mkHostAttrs null null) hosts - // lib.concatMapAttrs (riceName: rice: lib.concatMapAttrs (mkHostAttrs riceName rice) hosts) rices; - in - configurations - ); -} diff --git a/lib/configurations/host.nix b/lib/configurations/host.nix deleted file mode 100644 index 3afeaa8..0000000 --- a/lib/configurations/host.nix +++ /dev/null @@ -1,123 +0,0 @@ -{ - delib, - apply, - myconfigName, - config, - currentHostName, - useHomeManagerModule, - homeManagerUser, - ... -}: -{ - host = - { - name, - myconfig ? { }, - nixos ? { }, - home ? { }, - darwin ? { }, - shared ? { }, - # to avoid overwriting - # useHomeManagerModule ? null, - # homeManagerUser ? null, - # homeManagerSystem ? null, - # rice ? null, - ... - }@args: - { - imports = [ - ( - { config, ... }: - let - sharedDefaults = - { - myconfig ? { }, - nixos ? { }, - home ? { }, - darwin ? { }, - }: - { - inherit - myconfig - nixos - home - darwin - ; - }; - _shared = sharedDefaults shared; - - wrap = - x: - if builtins.typeOf x == "lambda" then - x { - inherit name; - cfg = config.${myconfigName}.hosts.${name}; - myconfig = config.${myconfigName}; - } - else - x; - in - { - config.${myconfigName}.hosts.${name} = args // { - myconfig = wrap myconfig; - nixos = wrap nixos; - home = wrap home; - darwin = wrap darwin; - shared = { - myconfig = wrap _shared.myconfig; - nixos = wrap _shared.nixos; - home = wrap _shared.home; - darwin = wrap _shared.darwin; - }; - }; - - imports = - (apply.listOfEverything (wrap _shared.myconfig) (wrap _shared.nixos) (wrap _shared.home) ( - wrap _shared.darwin - )) - ++ ( - if currentHostName == name then - apply.listOfEverything (wrap myconfig) (wrap nixos) (wrap home) (wrap darwin) - else - [ ] - ); - } - ) - ]; - }; - - # TODO: get config through `hostSubmoduleOption = config: ...` - hostSubmoduleOptions = with delib.options; { - name = noDefault (strOption null); - - useHomeManagerModule = boolOption useHomeManagerModule; - homeManagerUser = noNullDefault (strOption homeManagerUser); - homeManagerSystem = description (noDefault (strOption null)) "Passed to the `homeManagerConfiguration` as `nixpkgs.legacyPackages.`"; - - myconfig = attrsOption { }; - nixos = attrsOption { }; - home = attrsOption { }; - darwin = attrsOption { }; - - shared = { - myconfig = attrsOption { }; - nixos = attrsOption { }; - home = attrsOption { }; - darwin = attrsOption { }; - }; - - rice = allowNull (enumOption (builtins.attrNames (config.${myconfigName}.rices or { })) null); - }; - - hostOption = host: with delib.options; noDefault (submoduleOption host null); - hostsOption = host: with delib.options; attrsOfOption (submodule host) { }; - - hostNamesAssertions = - hosts: - builtins.attrValues ( - builtins.mapAttrs (name: value: { - assertion = (builtins.hashString "sha256" name) == (builtins.hashString "sha256" value.name); - message = "The hosts attribute '${name}' does not match the value of hosts.'${name}'.name (${value.name})"; - }) hosts - ); -} diff --git a/lib/configurations/module.nix b/lib/configurations/module.nix deleted file mode 100644 index aa683bb..0000000 --- a/lib/configurations/module.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ - delib, - lib, - apply, - myconfigName, - ... -}: -{ - module = - { - name, - options ? { }, - myconfig ? { }, - nixos ? { }, - home ? { }, - darwin ? { }, - }: - { - imports = [ - ( - { config, ... }: - let - cfg = delib.attrset.getAttrByStrPath name config.${myconfigName} { }; - - wrap = - object: - if builtins.typeOf object == "lambda" then - object { - inherit name cfg; - myconfig = config.${myconfigName}; - } - else - object; - - defaults = - { - ifEnabled ? { }, - ifDisabled ? { }, - always ? { }, - }: - { - inherit ifEnabled ifDisabled always; - }; - - _myconfig = defaults myconfig; - _nixos = defaults nixos; - _home = defaults home; - _darwin = defaults darwin; - - # If the `cfg.enable` option is missing, do not import ifEnabled or ifDisabled. - enabled = delib.attrset.getAttrByStrPath "enable" cfg false; - # Not `disabled = !enabled`, because it behaves differently when the 'enable' option is missing. - disabled = !(delib.attrset.getAttrByStrPath "enable" cfg true); - in - { - options.${myconfigName} = wrap options; - - imports = - (apply.listOfEverything (wrap _myconfig.always) (wrap _nixos.always) (wrap _home.always) ( - wrap _darwin.always - )) - ++ (apply.listOfEverything (lib.mkIf enabled (wrap _myconfig.ifEnabled)) (lib.mkIf enabled ( - wrap _nixos.ifEnabled - )) (lib.mkIf enabled (wrap _home.ifEnabled)) (lib.mkIf enabled (wrap _darwin.ifEnabled))) - ++ (apply.listOfEverything (lib.mkIf disabled (wrap _myconfig.ifDisabled)) (lib.mkIf disabled ( - wrap _nixos.ifDisabled - )) (lib.mkIf disabled (wrap _home.ifDisabled)) (lib.mkIf disabled (wrap _darwin.ifDisabled))); - } - ) - ]; - }; -} diff --git a/lib/configurations/rice.nix b/lib/configurations/rice.nix deleted file mode 100644 index a702442..0000000 --- a/lib/configurations/rice.nix +++ /dev/null @@ -1,68 +0,0 @@ -{ - delib, - myconfigName, - ... -}: -{ - rice = - { - name, - inherits ? [ ], - inheritanceOnly ? false, - myconfig ? { }, - nixos ? { }, - home ? { }, - darwin ? { }, - ... - }@args: - { - imports = [ - ( - { config, ... }: - let - wrap = - x: - if builtins.typeOf x == "lambda" then - x { - inherit name; - cfg = config.${myconfigName}.rices.${name}; - myconfig = config.${myconfigName}; - } - else - x; - in - { - config.${myconfigName}.rices.${name} = args // { - myconfig = wrap myconfig; - nixos = wrap nixos; - home = wrap home; - darwin = wrap darwin; - }; - } - ) - ]; - }; - - riceSubmoduleOptions = with delib.options; { - name = strOption null; - inherits = listOfOption str [ ]; - inheritanceOnly = boolOption false; - - myconfig = attrsOption { }; - nixos = attrsOption { }; - home = attrsOption { }; - darwin = attrsOption { }; - }; - - riceOption = rice: with delib.options; allowNull (submoduleOption rice null); - ricesOption = rice: with delib.options; attrsOfOption (submodule rice) { }; - - riceNamesAssertions = - rices: - builtins.attrValues ( - builtins.mapAttrs (name: value: { - assertion = (builtins.hashString "sha256" name) == (builtins.hashString "sha256" value.name); - message = "The rices attribute '${name}' does not match the value of rices.'${name}'.name (${value.name})"; - }) rices - ); -} diff --git a/lib/default.nix b/lib/default.nix index 54f154d..ac474ee 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -6,34 +6,17 @@ ... }: let - inherit (lib.fix (delib: import ./fixed-points.nix { inherit delib lib; })) - makeRecursivelyExtensible - ; + inherit (import ./toplevel/lib.nix { inherit lib; }) mkLib; in -makeRecursivelyExtensible ( +mkLib "delib" ( delib: - let - inherit (delib) _callLib; - in { - _callLib = file: import file delib._callLibArgs; - _callLibArgs = { - inherit - delib - lib - nixpkgs - home-manager - nix-darwin - ; + inherit nixpkgs home-manager nix-darwin; }; - attrset = _callLib ./attrset.nix; - inherit (delib.attrset) getAttrByStrPath setAttrByStrPath hasAttrs; - - inherit (_callLib ./configurations) configurations; - - inherit (_callLib ./fixed-points.nix) + fixedPoints = delib._callLib ./toplevel/fixed-points.nix; + inherit (delib.fixedPoints) fix fixWithUnfix recursivelyExtends @@ -43,21 +26,21 @@ makeRecursivelyExtensible ( makeRecursivelyExtensibleWithCustomName ; - inherit (_callLib ./maintainers.nix) maintainers; + inherit (delib._callLib ./toplevel/lib.nix) mkLib; - options = _callLib ./options.nix; - - inherit (_callLib ./extension.nix) - extension - extensions - callExtension - callExtensions - withExtensions - mergeExtensions + modules = delib._callLib ./modules; + inherit (delib.modules) + denixConfiguration + declareFunctionArgs + callDenixModule + compileModule ; - inherit (_callLib ./umport.nix) umport; + attrset = delib._callLib ./attrset.nix; + inherit (delib.attrset) getAttrByStrPath setAttrByStrPath hasAttrs; + + options = delib._callLib ./options.nix; } - // (import ./options.nix { inherit delib lib; }) - # After implementing https://github.com/NixOS/nix/issues/4090 it will be possible to use `// callLib` (to inherit all) + # After implementing https://github.com/NixOS/nix/issues/4090 it will be possible to use `// delib.options` (to inherit all) + // (import ./options.nix) { inherit lib delib; } ) diff --git a/lib/extension.nix b/lib/extension.nix deleted file mode 100644 index eb8d539..0000000 --- a/lib/extension.nix +++ /dev/null @@ -1,183 +0,0 @@ -{ - delib, - lib, - ... -}: -let - pretty = - value: - (lib.generators.toPretty { } ( - lib.generators.withRecursion { - depthLimit = 10; - throwOnDepthLimit = false; - } value - )); - toExtensionWithConfig = - f: - if lib.isFunction f then - config: final: prev: - let - fConfig = f config; - in - if lib.isFunction fConfig then - let - fConfigPrev = f config prev; - in - if lib.isFunction fConfigPrev then - # f is (config: final: prev: { ... }) - f config final prev - else - # f is (config: prev: { ... }) - fConfigPrev - else - # f is (config: { ... }) - fConfig - else - # f is not a function; probably { ... } - config: final: prev: - f; -in -{ - extension = - { - # Meta - name, - description ? null, - maintainers ? [ ], - # Extension - config ? final: prev: { }, - initialConfig ? null, - configOrder ? 0, # Used in mergeExtensions. Lower values mean earlier execution. - # Configuration - libExtension ? - config: final: prev: - { }, - libExtensionOrder ? 0, # Used in mergeExtensions. Lower values mean earlier execution. - modules ? config: [ ], - }: - let - _initialConfig = initialConfig; - f = - _config: - let - config = lib.toExtension _config; - initialConfig = - if _initialConfig == null || lib.isFunction _initialConfig then - _initialConfig - else - _: _initialConfig; - fixedConfig = delib.fix ( - delib.recursivelyExtends config (if initialConfig != null then initialConfig else _: { }) - ); - in - { - inherit - name - description - maintainers - initialConfig - configOrder - libExtensionOrder - ; - - libExtension = (toExtensionWithConfig libExtension) fixedConfig; - modules = if lib.isFunction modules then modules fixedConfig else modules; - - __unfix__ = f; - __unfixConfig__ = config; - config = fixedConfig; - withConfig = - configOverlay: f (delib.recursivelyComposeExtensions config (lib.toExtension configOverlay)); - }; - in - f config; - - extensions = delib.callExtensions { paths = [ ./extensions ]; }; - - callExtension = file: delib._callLib file // { _file = file; }; - - callExtensions = - { - # Umport - paths ? [ ], - exclude ? [ ], - recursive ? true, - }: - let - allExtensions = map delib.callExtension (delib.umport { inherit paths exclude recursive; }); - groupedByName = builtins.groupBy (extension: extension.name) allExtensions; - in - lib.mapAttrs delib.mergeExtensions groupedByName; - - withExtensions = lib.foldl (acc: extension: acc.recursivelyExtend extension.libExtension) delib; - - mergeExtensions = - name: extensions: - let - totalExtensions = builtins.length extensions; - in - if totalExtensions == 0 then - delib.extension { inherit name; } - else if totalExtensions == 1 then - builtins.removeAttrs (builtins.elemAt extensions 0) [ "_file" ] - else - let - config = - let - sorted = builtins.sort (q: p: q.configOrder < p.configOrder) extensions; - configs = builtins.map (x: x.__unfixConfig__) sorted; - in - delib.recursivelyComposeManyExtensions configs; - in - delib.extension { - inherit name; - description = - let - withDescription = builtins.filter (extension: extension.description != null) extensions; - withUniqueDescription = lib.foldl' ( - acc: e: - if builtins.any (extension: e.description == extension.description) acc then acc else acc ++ [ e ] - ) [ ] withDescription; - totalUnique = builtins.length withUniqueDescription; - in - if totalUnique == 0 then - null - else if totalUnique == 1 then - (builtins.head withDescription).description - else - lib.warn ( - "Denix extension with the name '${name}' has conflicting 'description' values:\n" - + (lib.concatMapStringsSep "\n" ( - extension: "- ${extension._file or extension.name}: ${pretty extension.description}" - ) withDescription) - ) null; - - inherit config; - initialConfig = - let - withInitialConfig = builtins.filter (extension: extension.initialConfig != null) extensions; - total = builtins.length withInitialConfig; - in - if total == 0 then - null - else if total == 1 then - (builtins.head withInitialConfig).initialConfig - else - lib.warn ( - "Denix extension with the name '${name}' has conflicting 'initialConfig' values:\n" - + (lib.concatMapStringsSep "\n" ( - extension: "- ${extension._file or extension.name}: ${pretty extension.initialConfig}" - ) withInitialConfig) - ) null; - - maintainers = lib.unique (builtins.concatMap (extension: extension.maintainers) extensions); - - libExtension = - let - sorted = builtins.sort (q: p: q.libExtensionOrder < p.libExtensionOrder) extensions; - libExtensions = config: builtins.map (extension: (extension.__unfix__ config).libExtension) sorted; - in - config: delib.recursivelyComposeManyExtensions (libExtensions config); - modules = config: builtins.concatMap (extension: (extension.__unfix__ config).modules) extensions; - }; -} diff --git a/lib/extensions/args.nix b/lib/extensions/args.nix deleted file mode 100644 index ff646fe..0000000 --- a/lib/extensions/args.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ delib, ... }: -delib.extension { - name = "args"; - description = "More convenient way to configure `_module.args` via `myconfig`"; - maintainers = with delib.maintainers; [ yunfachi ]; - - config.path = "args"; - - modules = config: [ - ( - { delib, ... }: - delib.module { - name = config.path; - - options = - with delib; - setAttrByStrPath config.path { - shared = attrsLegacyOption { }; - nixos = attrsLegacyOption { }; - home = attrsLegacyOption { }; - darwin = attrsLegacyOption { }; - }; - - nixos.always = - { cfg, ... }: - { - imports = [ - { _module.args = cfg.shared; } - { _module.args = cfg.nixos; } - ]; - }; - home.always = - { cfg, ... }: - { - imports = [ - { _module.args = cfg.shared; } - { _module.args = cfg.home; } - ]; - }; - darwin.always = - { cfg, ... }: - { - imports = [ - { _module.args = cfg.shared; } - { _module.args = cfg.darwin; } - ]; - }; - } - ) - ]; -} diff --git a/lib/extensions/base/default.nix b/lib/extensions/base/default.nix deleted file mode 100644 index 3c3ceaa..0000000 --- a/lib/extensions/base/default.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ delib, ... }: -delib.extension { - name = "base"; - description = "Implement feature-rich and fine-tunable modules for hosts and rices with minimal effort"; - maintainers = with delib.maintainers; [ yunfachi ]; - - initialConfig = { - enableAll = true; - - args = { - enable = false; - path = "args"; - }; - - assertions = { - enable = true; - moduleSystem = "home-manager"; - }; - }; -} diff --git a/lib/extensions/base/hosts.nix b/lib/extensions/base/hosts.nix deleted file mode 100644 index 6b70e0a..0000000 --- a/lib/extensions/base/hosts.nix +++ /dev/null @@ -1,170 +0,0 @@ -{ - delib, - lib, - ... -}: -delib.extension { - name = "base"; - - config = final: prev: { - hosts = { - enable = final.enableAll; - inherit (final) args assertions; - - type = { - enable = true; - generateIsType = true; - types = [ - "desktop" - "server" - ]; - }; - - features = { - enable = true; - generateIsFeatured = true; - features = [ ]; - default = [ ]; - defaultByHostType = { }; - }; - - displays = { - enable = true; - # TODO: hyprland = {enable = false; moduleSystem = "home";}; ... - }; - - extraSubmodules = [ ]; - }; - }; - - libExtension = - extensionConfig: final: prev: with final; { - generateHostType = - { - hostConfig, - generateIsType ? extensionConfig.hosts.type.generateIsType, - types ? extensionConfig.hosts.type.types, - }: - { - type = noDefault (enumOption types null); - } - // lib.optionalAttrs generateIsType ( - builtins.listToAttrs ( - map (type: { - name = - let - chars = lib.stringToCharacters type; - in - "is${lib.toUpper (lib.head chars) + lib.concatStrings (lib.tail chars)}"; - value = boolOption (hostConfig.type == type); - }) types - ) - ); - - generateHostFeatures = - { - hostConfig, - generateIsFeatured ? extensionConfig.hosts.features.generateIsFeatured, - features ? extensionConfig.hosts.features.features, - default ? extensionConfig.hosts.features.default, - defaultByHostType ? extensionConfig.hosts.features.defaultByHostType, - }: - { - defaultFeatures = listOfOption (enum features) ( - default ++ (defaultByHostType.${hostConfig.type} or [ ]) - ); - features = listOfOption (enum features) [ ]; - } - // lib.optionalAttrs generateIsFeatured ( - builtins.listToAttrs ( - map (feature: { - name = "${feature}Featured"; - value = boolOption (builtins.elem feature (hostConfig.features ++ hostConfig.defaultFeatures)); - }) features - ) - ); - - generateHostDisplays = - { hostConfig }: - { - displays = listOfOption (submodule { - options = { - enable = boolOption true; - - name = noDefault (strOption null); - primary = boolOption (builtins.length hostConfig.displays == 1); - touchscreen = boolOption false; - - refreshRate = intOption 60; - width = intOption 1920; - height = intOption 1080; - x = intOption 0; - y = intOption 0; - }; - }) [ ]; - }; - }; - - modules = - extensionConfig: - lib.optionals extensionConfig.hosts.enable [ - ( - { delib, ... }: - let - assertionsConfig = - { myconfig, ... }: - { - assertions = delib.hostNamesAssertions myconfig.hosts; - }; - assertionsModuleSystem = - { - nixos = "nixos"; - home-manager = "home"; - nix-darwin = "darwin"; - } - .${extensionConfig.hosts.assertions.moduleSystem} or extensionConfig.hosts.assertions.moduleSystem; - in - delib.module ( - { - name = "hosts"; - - options = - with delib; - let - host = - lib.singleton ( - { config, ... }: - { - options = - hostSubmoduleOptions - // delib.generateHostType { hostConfig = config; } - // delib.generateHostFeatures { hostConfig = config; } - // delib.generateHostDisplays { hostConfig = config; }; - } - ) - ++ extensionConfig.hosts.extraSubmodules; - in - { - host = hostOption host; - hosts = hostsOption host; - }; - - myconfig.always = - { myconfig, ... }: - lib.optionalAttrs extensionConfig.hosts.args.enable ( - delib.setAttrByStrPath extensionConfig.hosts.args.path { - shared = { inherit (myconfig) host hosts; }; - } - ) - // lib.optionalAttrs (assertionsModuleSystem == "myconfig") ( - lib.optionalAttrs extensionConfig.hosts.assertions.enable assertionsConfig - ); - } - // (lib.optionalAttrs (assertionsModuleSystem != "myconfig") { - ${assertionsModuleSystem}.always = - lib.optionalAttrs extensionConfig.hosts.assertions.enable assertionsConfig; - }) - ) - ) - ]; -} diff --git a/lib/extensions/base/rices.nix b/lib/extensions/base/rices.nix deleted file mode 100644 index 87c96d5..0000000 --- a/lib/extensions/base/rices.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ - delib, - lib, - ... -}: -delib.extension { - name = "base"; - - config = final: prev: { - rices = { - enable = final.enableAll; - inherit (final) args assertions; - - extraSubmodules = [ ]; - }; - }; - - modules = - extensionConfig: - lib.optionals extensionConfig.rices.enable [ - ( - { delib, ... }: - let - assertionsConfig = - { myconfig, ... }: - { - assertions = delib.riceNamesAssertions myconfig.rices; - }; - assertionsModuleSystem = - { - nixos = "nixos"; - home-manager = "home"; - nix-darwin = "darwin"; - } - .${extensionConfig.rices.assertions.moduleSystem} or extensionConfig.rices.assertions.moduleSystem; - in - delib.module ( - { - name = "rices"; - - options = - with delib; - let - rice = - lib.singleton { - options = riceSubmoduleOptions; - } - ++ extensionConfig.rices.extraSubmodules; - in - { - rice = riceOption rice; - rices = ricesOption rice; - }; - - myconfig.always = - { myconfig, ... }: - lib.optionalAttrs extensionConfig.rices.args.enable ( - delib.setAttrByStrPath extensionConfig.rices.args.path { - shared = { inherit (myconfig) rice rices; }; - } - ) - // lib.optionalAttrs (assertionsModuleSystem == "myconfig") ( - lib.optionalAttrs extensionConfig.rices.assertions.enable assertionsConfig - ); - } - // (lib.optionalAttrs (assertionsModuleSystem != "myconfig") { - ${assertionsModuleSystem}.always = - lib.optionalAttrs extensionConfig.rices.assertions.enable assertionsConfig; - }) - ) - ) - ]; -} diff --git a/lib/maintainers.nix b/lib/maintainers.nix deleted file mode 100644 index 2287ba4..0000000 --- a/lib/maintainers.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - delib, - lib, - ... -}: -let - maintainer = - { - name, - email ? null, - github ? null, - githubId ? null, - telegram ? null, - telegramId ? null, - }@args: - lib.warnIf (!delib.hasAttrs [ "email" "githubId" "telegramId" ] args) - "Maintainer '${name}' is missing contact info: expected at least one of email, githubId, or telegramId'" - args; -in -{ - maintainers = { - yunfachi = maintainer { - name = "yunfachi"; - github = "yunfachi"; - githubId = 73419713; - telegram = "yunfachi"; - telegramId = 1349897307; - }; - }; -} diff --git a/lib/modules/config/denix.nix b/lib/modules/config/denix.nix new file mode 100644 index 0000000..1c3ff1a --- /dev/null +++ b/lib/modules/config/denix.nix @@ -0,0 +1,63 @@ +{ + delib, + lib, + config, + ... +}: +{ + imports = [ + ./moduleSystems/default.nix + ]; + + options = + with delib; + let + modulesOption = lib.mkOption { + type = lib.mkOptionType { + name = "modules"; + check = with lib; x: !(isFunction x && isPath x && isAttrs x && isList x); + merge = + loc: defs: + lib.concatLists ( + map ( + def: + lib.toList ( + if lib.isFunction def.value then + lib.setFunctionArgs def.value (lib.functionArgs def.value) + else + def.value + ) + ) defs + ); + }; + default = [ ]; + }; + in + { + myconfigPrefix = allowNull (strOption "myconfig"); + + modules = attrsOfOption ( + functionTo (submoduleWith { + # NOTE: requires https://github.com/NixOS/nixpkgs/pull/437972 + onlyDefinesConfig = true; + modules = [ + ( + { name, ... }: + { + options = { + name = readOnly (strOption name) true; + + options = modulesOption; + } + // builtins.mapAttrs (name: value: { + always = modulesOption; + ifEnabled = modulesOption; + ifDisabled = modulesOption; + }) config.moduleSystems; + } + ) + ]; + }) + ); + }; +} diff --git a/lib/modules/config/moduleSystems/darwin.nix b/lib/modules/config/moduleSystems/darwin.nix new file mode 100644 index 0000000..d694a53 --- /dev/null +++ b/lib/modules/config/moduleSystems/darwin.nix @@ -0,0 +1,3 @@ +{ + moduleSystems.darwin = { }; +} diff --git a/lib/modules/config/moduleSystems/default.nix b/lib/modules/config/moduleSystems/default.nix new file mode 100644 index 0000000..cef0cfa --- /dev/null +++ b/lib/modules/config/moduleSystems/default.nix @@ -0,0 +1,81 @@ +{ + delib, + lib, + config, + ... +}: +let + myconfigPrefixDefault = config.myconfigPrefix; +in +{ + imports = [ + ./darwin.nix + ./home.nix + ./nixos.nix + ]; + + options = with delib; { + moduleSystems = lazyAttrsOfOption (submoduleWith { + modules = [ + ( + { config, name, ... }: + let + mkMyConfigPrefix = myconfigPrefix: lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; + in + { + options = { + name = readOnly (strOption name); + + myconfigPrefix = allowNull (strOption myconfigPrefixDefault); + + applyOptions = functionToOption attrs ( + { + myconfigPrefix, + moduleName, + value, + }: + { + imports = [ + (lib.setFunctionArgs (args: { + options = delib.setAttrByStrPath (value args) ((mkMyConfigPrefix myconfigPrefix) + moduleName); + }) (lib.functionArgs value)) + ]; + } + ); + + applyModuleSystemsConfig = functionToOption attrs ( + { + myconfigPrefix, + moduleSystem, + moduleName, + value, + type, + }: + lib.optionalAttrs (moduleSystem == name) { + imports = [ + { + always = value; + ifEnabled = lib.setFunctionArgs ( + { config, ... }@args: + lib.mkIf (delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" + false + ) (value args) + ) ({ config = false; } // (lib.functionArgs value)); + ifDisabled = lib.setFunctionArgs ( + { config, ... }@args: + lib.mkIf ( + !(delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" true) + ) (value args) + ) ({ config = false; } // (lib.functionArgs value)); + } + .${type} + ]; + } + ); + }; + } + ) + ]; + }) { }; + }; +} diff --git a/lib/modules/config/moduleSystems/home.nix b/lib/modules/config/moduleSystems/home.nix new file mode 100644 index 0000000..7fda68c --- /dev/null +++ b/lib/modules/config/moduleSystems/home.nix @@ -0,0 +1,3 @@ +{ + moduleSystems.home = { }; +} diff --git a/lib/modules/config/moduleSystems/myconfig.nix b/lib/modules/config/moduleSystems/myconfig.nix new file mode 100644 index 0000000..c13f3a1 --- /dev/null +++ b/lib/modules/config/moduleSystems/myconfig.nix @@ -0,0 +1,55 @@ +{ delib, ... }: +{ + moduleSystems.myconfig = + with delib; + { name, ... }: + { + applyModuleSystemsConfig = + { + myconfigPrefix, + moduleSystem, + moduleName, + value, + type, + }: + { + imports = [ + (lib.setFunctionArgs ( + { config, ... }@args: + let + mkMyConfigPrefix = myconfigPrefix: lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; + applied = value args; + unified = lib.unifyModuleSyntax ./default.nix "somekey" applied; + in + { + always = { + config = delib.setAttrByStrPath unified.config myconfigPrefix; + options = delib.setAttrByStrPath unified.options myconfigPrefix; + }; + + ifEnabled = { + config = lib.mkIf (delib.getAttrByStrPath config + "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" + false + ) (delib.setAttrByStrPath unified.config myconfigPrefix); + options = lib.mkIf (delib.getAttrByStrPath config + "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" + false + ) (delib.setAttrByStrPath unified.options myconfigPrefix); + }; + + ifDisabled = { + config = lib.mkIf ( + !(delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" true) + ) (delib.setAttrByStrPath unified.config myconfigPrefix); + options = lib.mkIf ( + !(delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" true) + ) (delib.setAttrByStrPath unified.options myconfigPrefix); + }; + } + .${type} + ) (lib.getFunctionArgs value)) + ]; + }; + }; +} diff --git a/lib/modules/config/moduleSystems/nixos.nix b/lib/modules/config/moduleSystems/nixos.nix new file mode 100644 index 0000000..10cf243 --- /dev/null +++ b/lib/modules/config/moduleSystems/nixos.nix @@ -0,0 +1,3 @@ +{ + moduleSystems.nixos = { }; +} diff --git a/lib/modules/default.nix b/lib/modules/default.nix new file mode 100644 index 0000000..a5b2444 --- /dev/null +++ b/lib/modules/default.nix @@ -0,0 +1,119 @@ +{ + delib, + lib, + nixpkgs, + home-manager, + nix-darwin, + ... +}: +{ + denixConfiguration = + { + modules ? [ ], + specialArgs ? { }, + }: + lib.evalModules { + modules = [ ./config/denix.nix ] ++ modules; + + specialArgs = { + inherit nixpkgs home-manager nix-darwin; + } + // lib.recursiveUpdate { + inherit delib; + } specialArgs; + }; + + callDenixModule = + { module, myconfigPrefix }: + { config, options, ... }: + delib.fix ( + self: + let + modulePath = lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}." + self.name; + in + module { + inherit (self) name; + cfg = delib.getAttrByStrPath config modulePath { }; + opt = delib.getAttrByStrPath options modulePath { }; + } + ); + + compileModule = + { + configuration, + moduleSystem, + myconfigPrefix ? configuration.config.moduleSystems.${moduleSystem}.myconfigPrefix, + applyModuleSystemsConfig ? + configuration.config.moduleSystems.${moduleSystem}.applyModuleSystemsConfig, + applyOptions ? configuration.config.moduleSystems.${moduleSystem}.applyOptions, + applyMyConfig ? configuration.config.moduleSystems.${moduleSystem}.applyMyConfig, + }: + ( + let + allModules = lib.attrValues configuration.config.modules; + allModuleSystems = lib.attrNames configuration.config.moduleSystems; + in + { + imports = lib.concatMap ( + module: + let + fakeCalled = delib.callDenixModule { inherit module myconfigPrefix; } { + config = { }; + options = { }; + }; + genModulesWithCalled = + y: + lib.genList ( + index: + { config, options, ... }@args: + let + called = delib.callDenixModule { inherit module myconfigPrefix; } args; + in + y index called + ); + in + genModulesWithCalled ( + index: called: + applyOptions { + inherit myconfigPrefix; + moduleName = called.name; + value = lib.elemAt called.options index; + } + ) (lib.length fakeCalled.options) + ++ lib.concatMap ( + moduleSystem': + genModulesWithCalled ( + index: called: + applyModuleSystemsConfig { + inherit myconfigPrefix; + moduleSystem = moduleSystem'; + moduleName = called.name; + value = lib.elemAt called.${moduleSystem'}.always index; + type = "always"; + } + ) (lib.length fakeCalled.${moduleSystem'}.always) + ++ genModulesWithCalled ( + index: called: + applyModuleSystemsConfig { + inherit myconfigPrefix; + moduleSystem = moduleSystem'; + moduleName = called.name; + value = lib.elemAt called.${moduleSystem'}.ifEnabled index; + type = "ifEnabled"; + } + ) (lib.length fakeCalled.${moduleSystem'}.ifEnabled) + ++ genModulesWithCalled ( + index: called: + applyModuleSystemsConfig { + inherit myconfigPrefix; + moduleSystem = moduleSystem'; + moduleName = called.name; + value = lib.elemAt called.${moduleSystem'}.ifDisabled index; + type = "ifDisabled"; + } + ) (lib.length fakeCalled.${moduleSystem'}.ifDisabled) + ) allModuleSystems + ) allModules; + } + ); +} diff --git a/lib/options.nix b/lib/options.nix index eef8586..6dd84f3 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -1,117 +1,152 @@ -{ - delib, - lib, - ... -}: +{ delib, lib, ... }: let - mkOption = - default: types: - lib.mkOption { - type = lib.types.oneOf (lib.toList types); - inherit default; - }; + genOptions = f: lib.listToAttrs (map f (lib.attrsToList types)); - addTypeToOption = - type: option: - option - // { - type = lib.types.oneOf [ - option.type - type - ]; + types = { + inherit (lib.types) + anything + attrsOf + bool + coercedTo + enum + float + int + oneOf + listOf + number + package + path + port + singleLineStr + str + submodule + submoduleWith + lazyAttrsOf + ; + attrs = delib.options.attrsOf delib.options.anything; + attrsLegacy = lib.types.attrs; + lazyAttrs = delib.options.lazyAttrsOf delib.options.anything; + # FIX https://github.com/NixOS/nixpkgs/issues/438933 + functionTo = + elemType: + lib.mkOptionType { + name = "functionTo"; + description = "function that evaluates to a(n) ${ + lib.types.optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType + }"; + descriptionClass = "composite"; + check = lib.isFunction; + merge = loc: defs: { + # An argument attribute has a default when it has a default in all definitions + __functionArgs = lib.zipAttrsWith (_: lib.all (x: x)) ( + lib.map (fn: lib.functionArgs fn.value) defs + ); + __functor = + _: callerArgs: + (lib.mergeDefinitions loc elemType ( + map (fn: { + inherit (fn) file; + value = fn.value callerArgs; + }) defs + )).mergedValue; + }; + getSubOptions = prefix: elemType.getSubOptions prefix; + getSubModules = elemType.getSubModules; + substSubModules = m: delib.options.functionTo (elemType.substSubModules m); + functor = lib.defaultFunctor "functionTo" // { + type = payload: types.functionTo payload.elemType; + payload.elemType = elemType; + binOp = + a: b: + let + merged = a.elemType.typeMerge b.elemType.functor; + in + if merged == null then null else { elemType = merged; }; + }; + nestedTypes.elemType = elemType; + }; + function = delib.options.functionTo delib.options.anything; + list = delib.options.listOf delib.options.anything; + intBetween = lib.types.ints.between; + null = lib.mkOptionType { + name = "null"; + description = "null"; + descriptionClass = "noun"; + check = x: x == null; + merge = lib.mergeEqualOption; + emptyValue = { + value = null; + }; }; - addTypeWithParameterToOption = - type: elemType: option: - addTypeToOption (type elemType) option; + }; - simpleOption = type: default: mkOption default type; - simpleOptionWithParameter = - type: elemType: default: - simpleOption (type elemType) default; -in -rec { - # Types - inherit (lib.types) - anything - attrsOf - bool - coercedTo - enum - float - int - listOf - number - package - path - port - singleLineStr - str - submodule - ; - attrs = attrsOf anything; - attrsLegacy = lib.types.attrs; - lambda = lib.types.functionTo anything; - lambdaTo = lib.types.functionTo; - list = listOf anything; + functorForType = type: { + __functor = + option: + if lib.isFunction type then + typeArg: option // { type = type typeArg; } // functorForType (type typeArg) + else + default: option // { inherit default; }; + }; - # Options - anythingOption = simpleOption anything; - attrsLegacyOption = simpleOption attrsLegacy; - attrsOfOption = simpleOptionWithParameter attrsOf; - attrsOption = simpleOption attrs; - boolOption = simpleOption bool; - coercedToOption = - coercedType: coerceFunc: finalType: - simpleOption (coercedTo coercedType coerceFunc finalType); - enumOption = simpleOptionWithParameter enum; - floatOption = simpleOption float; - intOption = simpleOption int; - lambdaOption = simpleOption lambda; - lambdaToOption = simpleOptionWithParameter lambdaTo; - listOfOption = simpleOptionWithParameter listOf; - listOption = simpleOption list; - numberOption = simpleOption number; - packageOption = simpleOption package; - pathOption = simpleOption path; - portOption = simpleOption port; - singleLineStrOption = simpleOption singleLineStr; - strOption = simpleOption str; - submoduleOption = simpleOptionWithParameter submodule; + typeOptions = genOptions ( + { name, value }: + { + name = "${name}Option"; + value = + lib.mkOption { + type = value; + } + // functorForType value; + } + ); - # Option type extensions - allowAnything = addTypeToOption anything; - allowAttrs = addTypeToOption attrs; - allowAttrsLegacy = addTypeToOption attrsLegacy; - allowAttrsOf = addTypeWithParameterToOption attrsOf; - allowBool = addTypeToOption bool; - allowCoercedToOption = - coercedType: coerceFunc: finalType: - addTypeToOption (coercedTo coercedType coerceFunc finalType); - allowEnum = addTypeWithParameterToOption enum; - allowFloat = addTypeToOption float; - allowInt = addTypeToOption int; - allowLambda = addTypeToOption lambda; - allowLambdaTo = addTypeWithParameterToOption lambdaTo; - allowList = addTypeToOption list; - allowListOf = addTypeWithParameterToOption listOf; - allowNull = option: option // { type = lib.types.nullOr option.type; }; - allowNumber = addTypeToOption number; - allowPackage = addTypeToOption package; - allowPath = addTypeToOption path; - allowPortOption = addTypeToOption port; - allowSingleLineStrOption = addTypeToOption singleLineStr; - allowStr = addTypeToOption str; + allowTypeOptions = genOptions ( + { name, value }: + { + name = "allow${ + lib.toUpper (builtins.substring 0 1 name) + (builtins.substring 1 (builtins.stringLength name) name) + }"; + value = + option: + option + // { + type = lib.types.oneOf [ + value + option.type + ]; + }; + } + ); +in +types +// typeOptions +// allowTypeOptions +// { + readOnly = + option: + option + // { + readOnly = true; + __functor = self: readOnly: self // { inherit readOnly; }; + }; + internal = + option: + option + // { + internal = true; + __functor = self: internal: self // { inherit internal; }; + }; + visible = + option: visible: + option + // { + inherit visible; + }; - # Option modifiers - noDefault = option: builtins.removeAttrs option [ "default" ]; - # This is a more convenient way to handle the presence of a default value in the option based on the condition (#18) - noNullDefault = - option: if option.default == null then builtins.removeAttrs option [ "default" ] else option; - readOnly = option: option // { readOnly = true; }; - apply = option: apply: option // { inherit apply; }; + defaultText = option: defaultText: option // { inherit defaultText; }; + example = option: example: option // { inherit example; }; description = option: description: option // { inherit description; }; - - # Predefined option patterns - singleEnableOption = - default: { name, ... }: delib.attrset.setAttrByStrPath "${name}.enable" (boolOption default); + relatedPackages = option: relatedPackages: option // { inherit relatedPackages; }; + apply = option: apply: option // { inherit apply; }; } diff --git a/lib/fixed-points.nix b/lib/toplevel/fixed-points.nix similarity index 73% rename from lib/fixed-points.nix rename to lib/toplevel/fixed-points.nix index dabffd1..c9fab09 100644 --- a/lib/fixed-points.nix +++ b/lib/toplevel/fixed-points.nix @@ -1,9 +1,8 @@ { - delib, lib, ... }: -{ +lib.fix (delib: { fix = f: let @@ -42,6 +41,23 @@ final: prev: { } ); + toExtensionWithFinalFirst = + f: + if lib.isFunction f then + final: prev: + let + fFinal = f final; + in + if lib.isFunction fFinal then + # f is (final: prev: { ... }) + fFinal prev + else + # f is (final: { ... }) + fFinal + else + # f is not a function; probably { ... } + final: prev: f; + makeRecursivelyExtensible = delib.makeRecursivelyExtensibleWithCustomName "recursivelyExtend"; makeRecursivelyExtensibleWithCustomName = @@ -56,4 +72,4 @@ } ) ); -} +}) diff --git a/lib/toplevel/lib.nix b/lib/toplevel/lib.nix new file mode 100644 index 0000000..2766bc9 --- /dev/null +++ b/lib/toplevel/lib.nix @@ -0,0 +1,140 @@ +{ lib, ... }: +let + fixedPoints = import ./fixed-points.nix { inherit lib; }; +in +{ + /** + Creates a recursively extensible library with additional `_callLib` and `_callLibArgs`. + + # Inputs + + `libName` + + : 1\. The attribute name that will represent the "self" of the library in the arguments of library parts called via `_callLib` + + `ext` + + : 2\. The initial extension for the library. It is transformed using `toExtensionWithFinalFirst` + + # Type + + ``` + mkLib :: string -> ((attrset -> attrset -> attrset) | (attrset -> attrset) | attrset) -> attrset + ``` + + # Example + + ```nix + customLib = mkLib "customLib" (customLib: prev: { + # No need to do `_callLibArgs = prev.callLibArgs // { foo = "foo"; };`, + # because mkLib uses recursive updating of attrsets. + _callLibArgs.foo = "foo"; + + function = x: x + 1 + antiFunction = x: customLib.function x - 1 + }) + ``` + */ + mkLib = + libName: ext: + let + extensible = fixedPoints.makeRecursivelyExtensible (self: { + + /** + Arguments passed to library parts called via `_callLib`. + + # Type + + ``` + attrset + ``` + + # Example + + ```nix + customLib = mkLib "customLib" {} + + customLib = customLib.recursivelyExtend ( + final: prev: { + _callLibArgs = { + denixNamePrefix = "de"; + }; + + inherit + (final._callLib ( + { denixNamePrefix, ... }: { denixName = "${denixNamePrefix}nix"; } + )) + denixName; + } + ) + + customLib.denixNamePrefix + => error: attribute 'denixNamePrefix' missing + + customLib.denixName + => "denix" + + customLib._callLibArgs + => + { + customLib = { ... }; + denixNamePrefix = "de"; + lib = { ... }; + } + ``` + */ + _callLibArgs = { + inherit lib; + ${libName} = self; + }; + + /** + Сall a library part `target` using `_callLibArgs`. + + The `target` may be: + + * a `path` - import it, then if it's a function call it with `_callLibArgs`; + * a function - call it with `_callLibArgs`; + * otherwise - returned unchanged. + + # Inputs + + `target` + + : 1\. Path, function, or anything else + + # Type + + ``` + _callLib :: (path | (attrset -> any) | any) -> any + ``` + + # Example + + ```nix + # ./mylib.nix => args: { greeting = "hi"; } + + _callLib ./mylib.nix + => { greeting = "hi"; } + + _callLib ({ ... }: { greeting = "hi"; }) + => { greeting = "hi"; } + + _callLib { greeting = "hi"; } + => { greeting = "hi"; } + + _callLib "hi" + => "hi" + ``` + */ + _callLib = + target: + let + maybeFunction = if builtins.isPath target then import target else target; + callable = if lib.isFunction maybeFunction then maybeFunction else _: maybeFunction; + in + callable self._callLibArgs; + }); + in + extensible.recursivelyExtend (fixedPoints.toExtensionWithFinalFirst ext); +} diff --git a/lib/umport.nix b/lib/umport.nix deleted file mode 100644 index ceff2a9..0000000 --- a/lib/umport.nix +++ /dev/null @@ -1,56 +0,0 @@ -# This function is copied from: -# https://github.com/yunfachi/nypkgs/blob/master/lib/umport.nix -# -# !!! REMOVING THIS NOTICE VIOLATES THE MIT LICENSE OF THE UMPORT PROJECT !!! -# This notice must be retained in all copies of this function, including modified versions! -# The MIT License can be found here: -# https://github.com/yunfachi/nypkgs/blob/master/LICENSE -{ lib, ... }: -{ - umport = - { - path ? null, - paths ? [ ], - include ? [ ], - exclude ? [ ], - recursive ? true, - }: - let - recursively = - let - inherit (lib.fileset) - unions - union - difference - fileFilter - toList - ; - nixOnly = paths: unions (map (fileFilter (file: file.hasExt "nix")) paths); - - pathsFs = nixOnly (paths ++ lib.optionals (path != null) [ path ]); - includeFs = nixOnly include; - excludeFs = nixOnly exclude; - - excluded = difference pathsFs excludeFs; - included = union excluded includeFs; - in - toList included; - - nonRecursively = - let - isNotExcluded = path: lib.all (x: !lib.path.hasPrefix x path) exclude; - readDirs = builtins.concatMap ( - path: map (x: path + "/${x}") (builtins.attrNames (builtins.readDir path)) - ); - - pathsList = readDirs (paths ++ lib.optionals (path != null) [ path ]); - includeList = readDirs include; - - excluded = lib.filter isNotExcluded pathsList; - included = lib.unique (excluded ++ includeList); - nixOnly = lib.filter (file: lib.pathIsDirectory file || lib.hasSuffix ".nix" file) included; - in - nixOnly; - in - if recursive then recursively else nonRecursively; -} diff --git a/templates/extensions-collection/extensions/extension.nix b/templates/extensions-collection/extensions/extension.nix deleted file mode 100644 index 07fb212..0000000 --- a/templates/extensions-collection/extensions/extension.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - lib, - delib, - ... -}: -delib.extension { - name = "awesomeExtension"; - description = "..."; - - config = final: prev: { - path = "sequence"; - fun1 = n: n / 2; - fun2 = n: 3 * n + 1; - }; - - libExtension = config: final: prev: { - genSequence = - n: - if n <= 0 then - [ ] - else if n == 1 then - [ 1 ] - else - [ n ] ++ final.genSequence (config."fun${toString (n - n / 2 * 2 + 1)}" n); - }; - - modules = config: [ - ( - { delib, ... }: - delib.module { - name = config.path; - - options = - with delib; - setAttrByStrPath config.path { - first100Sequences = listOption (lib.genList delib.genSequence 100); - }; - } - ) - ]; -} diff --git a/templates/extensions-collection/flake.nix b/templates/extensions-collection/flake.nix deleted file mode 100644 index edf66fb..0000000 --- a/templates/extensions-collection/flake.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ - description = "Denix extensions collection"; - - inputs.denix.url = "github:yunfachi/denix"; - - outputs = - { denix, ... }: - { - denixExtensions = denix.lib.callExtensions { - paths = [ ./extensions ]; - }; - }; -} diff --git a/templates/minimal-no-rices/flake.nix b/templates/minimal-no-rices/flake.nix deleted file mode 100644 index e1d2195..0000000 --- a/templates/minimal-no-rices/flake.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - description = "Modular configuration of NixOS, Home Manager, and Nix-Darwin with Denix"; - - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - home-manager = { - url = "github:nix-community/home-manager/master"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nix-darwin = { - url = "github:nix-darwin/nix-darwin/master"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - denix = { - url = "github:yunfachi/denix"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.home-manager.follows = "home-manager"; - inputs.nix-darwin.follows = "nix-darwin"; - }; - }; - - outputs = - { denix, ... }@inputs: - let - mkConfigurations = - moduleSystem: - denix.lib.configurations { - inherit moduleSystem; - homeManagerUser = "sjohn"; # !!! REPLACEME - - paths = [ - ./hosts - ./modules - ]; - - extensions = with denix.lib.extensions; [ - args - (base.withConfig { - args.enable = true; - rices.enable = false; - }) - ]; - - specialArgs = { - inherit inputs; - }; - }; - in - { - # If you're not using NixOS, Home Manager, or Nix-Darwin, - # you can safely remove the corresponding lines below. - nixosConfigurations = mkConfigurations "nixos"; - homeConfigurations = mkConfigurations "home"; - darwinConfigurations = mkConfigurations "darwin"; - }; -} diff --git a/templates/minimal-no-rices/hosts/desktop/default.nix b/templates/minimal-no-rices/hosts/desktop/default.nix deleted file mode 100644 index 70ce254..0000000 --- a/templates/minimal-no-rices/hosts/desktop/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ delib, ... }: -delib.host { - name = "desktop"; - - type = "desktop"; -} diff --git a/templates/minimal-no-rices/hosts/desktop/hardware.nix b/templates/minimal-no-rices/hosts/desktop/hardware.nix deleted file mode 100644 index 4323d74..0000000 --- a/templates/minimal-no-rices/hosts/desktop/hardware.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ delib, ... }: -delib.host { - name = "desktop"; - - # useHomeManagerModule = false; - homeManagerSystem = "x86_64-linux"; # !!! REPLACEME - home.home.stateVersion = "24.05"; # !!! REPLACEME - - # If you're not using NixOS, you can remove this entire block. - nixos = { - nixpkgs.hostPlatform = "x86_64-linux"; # !!! REPLACEME - system.stateVersion = "24.05"; # !!! REPLACEME - - # nixos-generate-config --show-hardware-config - # other generated code here... - }; - - # If you're not using Nix-Darwin, you can remove this entire block. - darwin = { - nixpkgs.hostPlatform = "aarch64-darwin"; # !!! REPLACEME - system.stateVersion = 6; # !!! REPLACEME - }; -} diff --git a/templates/minimal-no-rices/modules/config/constants.nix b/templates/minimal-no-rices/modules/config/constants.nix deleted file mode 100644 index 55332cf..0000000 --- a/templates/minimal-no-rices/modules/config/constants.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ delib, ... }: -delib.module { - name = "constants"; - - options.constants = with delib; { - #!!! REPLACEME - username = readOnly (strOption "sjohn"); - userfullname = readOnly (strOption "John Smith"); - useremail = readOnly (strOption "johnsmith@example.com"); - }; -} diff --git a/templates/minimal-no-rices/modules/config/home.nix b/templates/minimal-no-rices/modules/config/home.nix deleted file mode 100644 index a9ff355..0000000 --- a/templates/minimal-no-rices/modules/config/home.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - delib, - pkgs, - ... -}: -delib.module { - name = "home"; - - home.always = - { myconfig, ... }: - let - inherit (myconfig.constants) username; - in - { - home = { - inherit username; - # If you don't need Nix-Darwin, or if you're using it exclusively, - # you can keep the string here instead of the condition. - homeDirectory = if pkgs.stdenv.isDarwin then "/Users/${username}" else "/home/${username}"; - }; - }; -} diff --git a/templates/minimal-no-rices/modules/config/user.nix b/templates/minimal-no-rices/modules/config/user.nix deleted file mode 100644 index 466939a..0000000 --- a/templates/minimal-no-rices/modules/config/user.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ delib, ... }: -delib.module { - name = "user"; - - # If you're not using NixOS, you can remove this entire block. - nixos.always = - { myconfig, ... }: - let - inherit (myconfig.constants) username; - in - { - users = { - groups.${username} = { }; - - users.${username} = { - isNormalUser = true; - initialPassword = username; - extraGroups = [ "wheel" ]; - }; - }; - }; - - # If you're not using Nix-Darwin, you can remove this entire block. - darwin.always = - { myconfig, ... }: - let - inherit (myconfig.constants) username; - in - { - users.users.${username} = { - name = username; - home = "/Users/${username}"; - }; - }; -} diff --git a/templates/minimal/flake.nix b/templates/minimal/flake.nix deleted file mode 100644 index d30874b..0000000 --- a/templates/minimal/flake.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - description = "Modular configuration of NixOS, Home Manager, and Nix-Darwin with Denix"; - - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - home-manager = { - url = "github:nix-community/home-manager/master"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - nix-darwin = { - url = "github:nix-darwin/nix-darwin/master"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - denix = { - url = "github:yunfachi/denix"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.home-manager.follows = "home-manager"; - inputs.nix-darwin.follows = "nix-darwin"; - }; - }; - - outputs = - { denix, ... }@inputs: - let - mkConfigurations = - moduleSystem: - denix.lib.configurations { - inherit moduleSystem; - homeManagerUser = "sjohn"; # !!! REPLACEME - - paths = [ - ./hosts - ./modules - ./rices - ]; - - extensions = with denix.lib.extensions; [ - args - (base.withConfig { - args.enable = true; - }) - ]; - - specialArgs = { - inherit inputs; - }; - }; - in - { - # If you're not using NixOS, Home Manager, or Nix-Darwin, - # you can safely remove the corresponding lines below. - nixosConfigurations = mkConfigurations "nixos"; - homeConfigurations = mkConfigurations "home"; - darwinConfigurations = mkConfigurations "darwin"; - }; -} diff --git a/templates/minimal/hosts/desktop/default.nix b/templates/minimal/hosts/desktop/default.nix deleted file mode 100644 index cd2008d..0000000 --- a/templates/minimal/hosts/desktop/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ delib, ... }: -delib.host { - name = "desktop"; - - rice = "dark"; - type = "desktop"; -} diff --git a/templates/minimal/hosts/desktop/hardware.nix b/templates/minimal/hosts/desktop/hardware.nix deleted file mode 100644 index 4323d74..0000000 --- a/templates/minimal/hosts/desktop/hardware.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ delib, ... }: -delib.host { - name = "desktop"; - - # useHomeManagerModule = false; - homeManagerSystem = "x86_64-linux"; # !!! REPLACEME - home.home.stateVersion = "24.05"; # !!! REPLACEME - - # If you're not using NixOS, you can remove this entire block. - nixos = { - nixpkgs.hostPlatform = "x86_64-linux"; # !!! REPLACEME - system.stateVersion = "24.05"; # !!! REPLACEME - - # nixos-generate-config --show-hardware-config - # other generated code here... - }; - - # If you're not using Nix-Darwin, you can remove this entire block. - darwin = { - nixpkgs.hostPlatform = "aarch64-darwin"; # !!! REPLACEME - system.stateVersion = 6; # !!! REPLACEME - }; -} diff --git a/templates/minimal/modules/config/constants.nix b/templates/minimal/modules/config/constants.nix deleted file mode 100644 index 55332cf..0000000 --- a/templates/minimal/modules/config/constants.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ delib, ... }: -delib.module { - name = "constants"; - - options.constants = with delib; { - #!!! REPLACEME - username = readOnly (strOption "sjohn"); - userfullname = readOnly (strOption "John Smith"); - useremail = readOnly (strOption "johnsmith@example.com"); - }; -} diff --git a/templates/minimal/modules/config/home.nix b/templates/minimal/modules/config/home.nix deleted file mode 100644 index a9ff355..0000000 --- a/templates/minimal/modules/config/home.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - delib, - pkgs, - ... -}: -delib.module { - name = "home"; - - home.always = - { myconfig, ... }: - let - inherit (myconfig.constants) username; - in - { - home = { - inherit username; - # If you don't need Nix-Darwin, or if you're using it exclusively, - # you can keep the string here instead of the condition. - homeDirectory = if pkgs.stdenv.isDarwin then "/Users/${username}" else "/home/${username}"; - }; - }; -} diff --git a/templates/minimal/modules/config/user.nix b/templates/minimal/modules/config/user.nix deleted file mode 100644 index 466939a..0000000 --- a/templates/minimal/modules/config/user.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ delib, ... }: -delib.module { - name = "user"; - - # If you're not using NixOS, you can remove this entire block. - nixos.always = - { myconfig, ... }: - let - inherit (myconfig.constants) username; - in - { - users = { - groups.${username} = { }; - - users.${username} = { - isNormalUser = true; - initialPassword = username; - extraGroups = [ "wheel" ]; - }; - }; - }; - - # If you're not using Nix-Darwin, you can remove this entire block. - darwin.always = - { myconfig, ... }: - let - inherit (myconfig.constants) username; - in - { - users.users.${username} = { - name = username; - home = "/Users/${username}"; - }; - }; -} diff --git a/templates/minimal/rices/dark/default.nix b/templates/minimal/rices/dark/default.nix deleted file mode 100644 index 2dffcc6..0000000 --- a/templates/minimal/rices/dark/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ delib, ... }: -delib.rice { - name = "dark"; -} From 20ec5bec41ef1744a2071ed1fc161c19ba749019 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Sun, 7 Sep 2025 11:21:00 +0300 Subject: [PATCH 02/21] add generated code, keep-sorted, flake check workflow --- .github/workflows/flake-check.yml | 24 +++ flake.lock | 84 ++++---- flake.nix | 40 +++- lib/default.nix | 182 ++++++++++++++---- lib/modules/config/moduleSystems/myconfig.nix | 4 +- lib/options.nix | 141 +++----------- lib/types.nix | 90 +++++++++ 7 files changed, 370 insertions(+), 195 deletions(-) create mode 100644 .github/workflows/flake-check.yml create mode 100644 lib/types.nix diff --git a/.github/workflows/flake-check.yml b/.github/workflows/flake-check.yml new file mode 100644 index 0000000..7c4651e --- /dev/null +++ b/.github/workflows/flake-check.yml @@ -0,0 +1,24 @@ +name: Nix Flake Check + +on: + pull_request: + push: + branches: master + workflow_dispatch: + +permissions: read-all + +jobs: + nix-flake-check: + name: Nix Flake Check + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + + - name: Check Flake + run: nix flake check + diff --git a/flake.lock b/flake.lock index f25ae56..c9cff97 100644 --- a/flake.lock +++ b/flake.lock @@ -16,10 +16,30 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1757191023, + "narHash": "sha256-E9spYi9lxm2f1zWQLQ7xQt8Xs2nWgr1T4QM7ZjLFphM=", + "owner": "yunfachi", + "repo": "git-hooks.nix", + "rev": "57e70dd1e97d57fdb2bcf16add926628272a716c", + "type": "github" + }, + "original": { + "owner": "yunfachi", + "repo": "git-hooks.nix", + "type": "github" + } + }, "gitignore": { "inputs": { "nixpkgs": [ - "pre-commit-hooks", + "git-hooks", "nixpkgs" ] }, @@ -44,11 +64,11 @@ ] }, "locked": { - "lastModified": 1756261190, - "narHash": "sha256-eiy0klFK5EVJLNilutR7grsZN/7Itj9DyD75eyOf83k=", + "lastModified": 1757075491, + "narHash": "sha256-a+NMGl5tcvm+hyfSG2DlVPa8nZLpsumuRj1FfcKb2mQ=", "owner": "nix-community", "repo": "home-manager", - "rev": "77f348da3176dc68b20a73dab94852a417daf361", + "rev": "f56bf065f9abedc7bc15e1f2454aa5c8edabaacf", "type": "github" }, "original": { @@ -65,11 +85,11 @@ ] }, "locked": { - "lastModified": 1755825449, - "narHash": "sha256-XkiN4NM9Xdy59h69Pc+Vg4PxkSm9EWl6u7k6D5FZ5cM=", + "lastModified": 1757130842, + "narHash": "sha256-4i7KKuXesSZGUv0cLPLfxbmF1S72Gf/3aSypgvVkwuA=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "8df64f819698c1fee0c2969696f54a843b2231e8", + "rev": "15f067638e2887c58c4b6ba1bdb65a0b61dc58c5", "type": "github" }, "original": { @@ -80,16 +100,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1756410287, - "narHash": "sha256-X7KtENXtzWShJwynb4jk14Sg+9yhRS/zbE5qh+ZgMt0=", - "owner": "yunfachi", + "lastModified": 1754340878, + "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "f222f92233a60bc85e7eb7af81380da61073597d", + "rev": "cab778239e705082fe97bb4990e0d24c50924c04", "type": "github" }, "original": { - "owner": "yunfachi", - "ref": "patch-2", + "owner": "NixOS", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -114,47 +134,27 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1754340878, - "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", - "owner": "NixOS", + "lastModified": 1756478791, + "narHash": "sha256-F2fHTBUA/S99Kwv99k51Xb990LIihlK2Ys29rrTfMoE=", + "owner": "yunfachi", "repo": "nixpkgs", - "rev": "cab778239e705082fe97bb4990e0d24c50924c04", + "rev": "da2a71835653a4d11bbe3738830d90f048ae9d30", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", + "owner": "yunfachi", + "ref": "patch-2", "repo": "nixpkgs", "type": "github" } }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1755960406, - "narHash": "sha256-RF7j6C1TmSTK9tYWO6CdEMtg6XZaUKcvZwOCD2SICZs=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "e891a93b193fcaf2fc8012d890dc7f0befe86ec2", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" - } - }, "root": { "inputs": { + "git-hooks": "git-hooks", "home-manager": "home-manager", "nix-darwin": "nix-darwin", - "nixpkgs": "nixpkgs", - "nixpkgs-lib": "nixpkgs-lib", - "pre-commit-hooks": "pre-commit-hooks" + "nixpkgs": "nixpkgs_2", + "nixpkgs-lib": "nixpkgs-lib" } } }, diff --git a/flake.nix b/flake.nix index 9e0beac..5451a8a 100644 --- a/flake.nix +++ b/flake.nix @@ -4,9 +4,8 @@ inputs = { #nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; nixpkgs-lib.url = "github:yunfachi/nixpkgs/patch-2?dir=lib"; - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - }; + #git-hooks.url = "github:cachix/git-hooks.nix"; + git-hooks.url = "github:yunfachi/git-hooks.nix"; /** The reason for separating nixpkgs and nixpkgs-lib is that nixpkgs, home-manager, @@ -31,7 +30,7 @@ { self, nixpkgs-lib, - pre-commit-hooks, + git-hooks, nixpkgs, home-manager, nix-darwin, @@ -54,9 +53,38 @@ }; checks = forAllSystems (system: { - pre-commit-check = pre-commit-hooks.lib.${system}.run { + pre-commit-check = git-hooks.lib.${system}.run { src = ./.; - hooks.nixfmt-rfc-style.enable = true; + hooks = { + nixfmt-rfc-style.enable = true; + keep-sorted = { + enable = true; + name = "keep-sorted"; + language = "system"; + entry = "${nixpkgs.legacyPackages.${system}.keep-sorted}/bin/keep-sorted"; + }; + cog = { + enable = true; + name = "cog"; + language = "system"; + entry = nixpkgs.lib.getExe ( + nixpkgs.legacyPackages.${system}.writeShellApplication { + name = "denix-cog"; + + runtimeInputs = with nixpkgs.legacyPackages.${system}; [ + python313Packages.cogapp + nix + ]; + + text = '' + export pre_evaled_options='${builtins.toJSON (builtins.attrNames self.lib.options)}' + export pre_evaled_types='${builtins.toJSON (builtins.attrNames self.lib.types)}' + cog -r "$1" + ''; + } + ); + }; + }; }; }); diff --git a/lib/default.nix b/lib/default.nix index ac474ee..0b2e270 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -8,39 +8,151 @@ let inherit (import ./toplevel/lib.nix { inherit lib; }) mkLib; in -mkLib "delib" ( - delib: - { - _callLibArgs = { - inherit nixpkgs home-manager nix-darwin; - }; - - fixedPoints = delib._callLib ./toplevel/fixed-points.nix; - inherit (delib.fixedPoints) - fix - fixWithUnfix - recursivelyExtends - recursivelyComposeExtensions - recursivelyComposeManyExtensions - makeRecursivelyExtensible - makeRecursivelyExtensibleWithCustomName - ; - - inherit (delib._callLib ./toplevel/lib.nix) mkLib; - - modules = delib._callLib ./modules; - inherit (delib.modules) - denixConfiguration - declareFunctionArgs - callDenixModule - compileModule - ; - - attrset = delib._callLib ./attrset.nix; - inherit (delib.attrset) getAttrByStrPath setAttrByStrPath hasAttrs; - - options = delib._callLib ./options.nix; - } +mkLib "delib" (delib: { + _callLibArgs = { + inherit nixpkgs home-manager nix-darwin; + }; + + fixedPoints = delib._callLib ./toplevel/fixed-points.nix; + inherit (delib.fixedPoints) + fix + fixWithUnfix + recursivelyExtends + recursivelyComposeExtensions + recursivelyComposeManyExtensions + makeRecursivelyExtensible + makeRecursivelyExtensibleWithCustomName + ; + + inherit (delib._callLib ./toplevel/lib.nix) mkLib; + + modules = delib._callLib ./modules; + inherit (delib.modules) + denixConfiguration + callDenixModule + compileModule + ; + + attrset = delib._callLib ./attrset.nix; + inherit (delib.attrset) getAttrByStrPath setAttrByStrPath hasAttrs; + + options = delib._callLib ./options.nix; + + types = delib._callLib ./types.nix; + + # Generated inherits. # After implementing https://github.com/NixOS/nix/issues/4090 it will be possible to use `// delib.options` (to inherit all) - // (import ./options.nix) { inherit lib delib; } -) + + #[[[cog + # import cog + # import subprocess + # import json + # import os + # + # def nix_attr_names(attr): + # out = subprocess.run( + # ["nix", "eval", f".#lib.{attr}", + # "--apply", "builtins.attrNames", + # "--quiet", "--json", "--no-pretty"], + # capture_output=True, text=True, check=False + # ).stdout or os.environ[f"pre_evaled_{attr}"] + # return json.loads(out) + # + # for group in ["options", "types"]: + # cog.outl(f"inherit (delib.{group})") + # for name in nix_attr_names(group): + # cog.outl(f" {name}") + # cog.outl(" ;") + #]]] + inherit (delib.options) + allowAnything + allowAttrs + allowAttrsLegacy + allowAttrsOf + allowBool + allowCoercedTo + allowEnum + allowFloat + allowFunction + allowFunctionTo + allowInt + allowIntBetween + allowLazyAttrs + allowLazyAttrsOf + allowList + allowListOf + allowNull + allowNumber + allowOneOf + allowPackage + allowPath + allowPort + allowSingleLineStr + allowStr + allowSubmodule + allowSubmoduleWith + anythingOption + apply + attrsLegacyOption + attrsOfOption + attrsOption + boolOption + coercedToOption + defaultText + description + enumOption + example + floatOption + functionOption + functionToOption + intBetweenOption + intOption + internal + lazyAttrsOfOption + lazyAttrsOption + listOfOption + listOption + nullOption + numberOption + oneOfOption + packageOption + pathOption + portOption + readOnly + relatedPackages + singleLineStrOption + strOption + submoduleOption + submoduleWithOption + visible + ; + inherit (delib.types) + anything + attrs + attrsLegacy + attrsOf + bool + coercedTo + enum + float + function + functionTo + int + intBetween + lazyAttrs + lazyAttrsOf + list + listOf + null + number + oneOf + package + path + port + singleLineStr + str + submodule + submoduleWith + ; + #[[[end]]] +}) diff --git a/lib/modules/config/moduleSystems/myconfig.nix b/lib/modules/config/moduleSystems/myconfig.nix index c13f3a1..f131e41 100644 --- a/lib/modules/config/moduleSystems/myconfig.nix +++ b/lib/modules/config/moduleSystems/myconfig.nix @@ -18,8 +18,8 @@ { config, ... }@args: let mkMyConfigPrefix = myconfigPrefix: lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; - applied = value args; - unified = lib.unifyModuleSyntax ./default.nix "somekey" applied; + called = value args; + unified = lib.unifyModuleSyntax ./default.nix "somekey" called; in { always = { diff --git a/lib/options.nix b/lib/options.nix index 6dd84f3..2607eee 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -1,84 +1,6 @@ { delib, lib, ... }: let - genOptions = f: lib.listToAttrs (map f (lib.attrsToList types)); - - types = { - inherit (lib.types) - anything - attrsOf - bool - coercedTo - enum - float - int - oneOf - listOf - number - package - path - port - singleLineStr - str - submodule - submoduleWith - lazyAttrsOf - ; - attrs = delib.options.attrsOf delib.options.anything; - attrsLegacy = lib.types.attrs; - lazyAttrs = delib.options.lazyAttrsOf delib.options.anything; - # FIX https://github.com/NixOS/nixpkgs/issues/438933 - functionTo = - elemType: - lib.mkOptionType { - name = "functionTo"; - description = "function that evaluates to a(n) ${ - lib.types.optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType - }"; - descriptionClass = "composite"; - check = lib.isFunction; - merge = loc: defs: { - # An argument attribute has a default when it has a default in all definitions - __functionArgs = lib.zipAttrsWith (_: lib.all (x: x)) ( - lib.map (fn: lib.functionArgs fn.value) defs - ); - __functor = - _: callerArgs: - (lib.mergeDefinitions loc elemType ( - map (fn: { - inherit (fn) file; - value = fn.value callerArgs; - }) defs - )).mergedValue; - }; - getSubOptions = prefix: elemType.getSubOptions prefix; - getSubModules = elemType.getSubModules; - substSubModules = m: delib.options.functionTo (elemType.substSubModules m); - functor = lib.defaultFunctor "functionTo" // { - type = payload: types.functionTo payload.elemType; - payload.elemType = elemType; - binOp = - a: b: - let - merged = a.elemType.typeMerge b.elemType.functor; - in - if merged == null then null else { elemType = merged; }; - }; - nestedTypes.elemType = elemType; - }; - function = delib.options.functionTo delib.options.anything; - list = delib.options.listOf delib.options.anything; - intBetween = lib.types.ints.between; - null = lib.mkOptionType { - name = "null"; - description = "null"; - descriptionClass = "noun"; - check = x: x == null; - merge = lib.mergeEqualOption; - emptyValue = { - value = null; - }; - }; - }; + genOptions = f: lib.listToAttrs (map f (lib.attrsToList delib.types)); functorForType = type: { __functor = @@ -118,35 +40,34 @@ let }; } ); -in -types -// typeOptions -// allowTypeOptions -// { - readOnly = - option: - option - // { - readOnly = true; - __functor = self: readOnly: self // { inherit readOnly; }; - }; - internal = - option: - option - // { - internal = true; - __functor = self: internal: self // { inherit internal; }; - }; - visible = - option: visible: - option - // { - inherit visible; - }; - defaultText = option: defaultText: option // { inherit defaultText; }; - example = option: example: option // { inherit example; }; - description = option: description: option // { inherit description; }; - relatedPackages = option: relatedPackages: option // { inherit relatedPackages; }; - apply = option: apply: option // { inherit apply; }; -} + optionModifiers = { + readOnly = + option: + option + // { + readOnly = true; + __functor = self: readOnly: self // { inherit readOnly; }; + }; + internal = + option: + option + // { + internal = true; + __functor = self: internal: self // { inherit internal; }; + }; + visible = + option: visible: + option + // { + inherit visible; + }; + + defaultText = option: defaultText: option // { inherit defaultText; }; + example = option: example: option // { inherit example; }; + description = option: description: option // { inherit description; }; + relatedPackages = option: relatedPackages: option // { inherit relatedPackages; }; + apply = option: apply: option // { inherit apply; }; + }; +in +typeOptions // allowTypeOptions // optionModifiers diff --git a/lib/types.nix b/lib/types.nix new file mode 100644 index 0000000..5288857 --- /dev/null +++ b/lib/types.nix @@ -0,0 +1,90 @@ +{ delib, lib, ... }: +{ + inherit (lib.types) + # keep-sorted start case=no + anything + attrsOf + bool + coercedTo + enum + float + int + lazyAttrsOf + listOf + number + oneOf + package + path + port + singleLineStr + str + submodule + submoduleWith + # keep-sorted end + ; + + # keep-sorted start case=no block=yes newline_separated=yes + attrs = delib.types.attrsOf delib.types.anything; + + attrsLegacy = lib.types.attrs; + + function = delib.types.functionTo delib.types.anything; + + # FIX https://github.com/NixOS/nixpkgs/issues/438933 + functionTo = + elemType: + lib.mkOptionType { + name = "functionTo"; + description = "function that evaluates to a(n) ${ + lib.types.optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType + }"; + descriptionClass = "composite"; + check = lib.isFunction; + merge = loc: defs: { + # An argument attribute has a default when it has a default in all definitions + __functionArgs = lib.zipAttrsWith (_: lib.all (x: x)) ( + lib.map (fn: lib.functionArgs fn.value) defs + ); + __functor = + _: callerArgs: + (lib.mergeDefinitions loc elemType ( + map (fn: { + inherit (fn) file; + value = fn.value callerArgs; + }) defs + )).mergedValue; + }; + getSubOptions = prefix: elemType.getSubOptions prefix; + getSubModules = elemType.getSubModules; + substSubModules = m: delib.types.functionTo (elemType.substSubModules m); + functor = lib.defaultFunctor "functionTo" // { + type = payload: delib.types.functionTo payload.elemType; + payload.elemType = elemType; + binOp = + a: b: + let + merged = a.elemType.typeMerge b.elemType.functor; + in + if merged == null then null else { elemType = merged; }; + }; + nestedTypes.elemType = elemType; + }; + + intBetween = lib.types.ints.between; + + lazyAttrs = delib.types.lazyAttrsOf delib.types.anything; + + list = delib.types.listOf delib.types.anything; + + null = lib.mkOptionType { + name = "null"; + description = "null"; + descriptionClass = "noun"; + check = x: x == null; + merge = lib.mergeEqualOption; + emptyValue = { + value = null; + }; + }; + # keep-sorted end +} From 80c278efb4bc93fc4bdaa8e84de5123b4a4ab08c Mon Sep 17 00:00:00 2001 From: yunfachi Date: Sun, 7 Sep 2025 11:51:01 +0300 Subject: [PATCH 03/21] fix cog hook --- flake.nix | 2 +- lib/default.nix | 18 ++++++++++++------ lib/types.nix | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index 5451a8a..54f2c3b 100644 --- a/flake.nix +++ b/flake.nix @@ -79,7 +79,7 @@ text = '' export pre_evaled_options='${builtins.toJSON (builtins.attrNames self.lib.options)}' export pre_evaled_types='${builtins.toJSON (builtins.attrNames self.lib.types)}' - cog -r "$1" + cog -r "$@" ''; } ); diff --git a/lib/default.nix b/lib/default.nix index 0b2e270..91e7e6b 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -50,12 +50,15 @@ mkLib "delib" (delib: { # import os # # def nix_attr_names(attr): - # out = subprocess.run( - # ["nix", "eval", f".#lib.{attr}", - # "--apply", "builtins.attrNames", - # "--quiet", "--json", "--no-pretty"], - # capture_output=True, text=True, check=False - # ).stdout or os.environ[f"pre_evaled_{attr}"] + # try: + # out = subprocess.run( + # ["nix", "eval", f".#lib.{attr}", + # "--apply", "builtins.attrNames", + # "--quiet", "--json", "--no-pretty"], + # capture_output=True, text=True, check=True + # ).stdout + # except subprocess.CalledProcessError: + # out = os.environ[f"pre_evaled_{attr}"] # return json.loads(out) # # for group in ["options", "types"]: @@ -91,6 +94,7 @@ mkLib "delib" (delib: { allowStr allowSubmodule allowSubmoduleWith + allowUnspecified anythingOption apply attrsLegacyOption @@ -124,6 +128,7 @@ mkLib "delib" (delib: { strOption submoduleOption submoduleWithOption + unspecifiedOption visible ; inherit (delib.types) @@ -153,6 +158,7 @@ mkLib "delib" (delib: { str submodule submoduleWith + unspecified ; #[[[end]]] }) diff --git a/lib/types.nix b/lib/types.nix index 5288857..47ace1b 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -20,6 +20,7 @@ str submodule submoduleWith + unspecified # keep-sorted end ; From 259e95105912c074fe56154900759afac1f12b15 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Sun, 7 Sep 2025 13:29:16 +0300 Subject: [PATCH 04/21] update git-hooks to upstream --- flake.lock | 8 ++++---- flake.nix | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index c9cff97..6fbbda5 100644 --- a/flake.lock +++ b/flake.lock @@ -23,15 +23,15 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1757191023, + "lastModified": 1757239681, "narHash": "sha256-E9spYi9lxm2f1zWQLQ7xQt8Xs2nWgr1T4QM7ZjLFphM=", - "owner": "yunfachi", + "owner": "cachix", "repo": "git-hooks.nix", - "rev": "57e70dd1e97d57fdb2bcf16add926628272a716c", + "rev": "ab82ab08d6bf74085bd328de2a8722c12d97bd9d", "type": "github" }, "original": { - "owner": "yunfachi", + "owner": "cachix", "repo": "git-hooks.nix", "type": "github" } diff --git a/flake.nix b/flake.nix index 54f2c3b..4ea062f 100644 --- a/flake.nix +++ b/flake.nix @@ -4,8 +4,7 @@ inputs = { #nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; nixpkgs-lib.url = "github:yunfachi/nixpkgs/patch-2?dir=lib"; - #git-hooks.url = "github:cachix/git-hooks.nix"; - git-hooks.url = "github:yunfachi/git-hooks.nix"; + git-hooks.url = "github:cachix/git-hooks.nix"; /** The reason for separating nixpkgs and nixpkgs-lib is that nixpkgs, home-manager, From 63e46677bf26aa5e83fd4d1ce37b7c3079377366 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Sat, 13 Sep 2025 14:42:25 +0300 Subject: [PATCH 05/21] lib/types: use unspecified instead of anything, add steppedInt and steppedIntBetween --- lib/default.nix | 6 ++++++ lib/types.nix | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index 91e7e6b..b40e407 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -91,6 +91,8 @@ mkLib "delib" (delib: { allowPath allowPort allowSingleLineStr + allowSteppedInt + allowSteppedIntBetween allowStr allowSubmodule allowSubmoduleWith @@ -125,6 +127,8 @@ mkLib "delib" (delib: { readOnly relatedPackages singleLineStrOption + steppedIntBetweenOption + steppedIntOption strOption submoduleOption submoduleWithOption @@ -155,6 +159,8 @@ mkLib "delib" (delib: { path port singleLineStr + steppedInt + steppedIntBetween str submodule submoduleWith diff --git a/lib/types.nix b/lib/types.nix index 47ace1b..542956d 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -25,11 +25,11 @@ ; # keep-sorted start case=no block=yes newline_separated=yes - attrs = delib.types.attrsOf delib.types.anything; + attrs = delib.types.attrsOf delib.types.unspecified; attrsLegacy = lib.types.attrs; - function = delib.types.functionTo delib.types.anything; + function = delib.types.functionTo delib.types.unspecified; # FIX https://github.com/NixOS/nixpkgs/issues/438933 functionTo = @@ -71,11 +71,18 @@ nestedTypes.elemType = elemType; }; - intBetween = lib.types.ints.between; + intBetween = + lowest: highest: + assert lib.assertMsg (lowest <= highest) "intBetween: lowest must be smaller than highest"; + lib.types.addCheck delib.types.int (x: x >= lowest && x <= highest) + // { + name = "intBetween"; + description = "integer between ${toString lowest} and ${toString highest} (both inclusive)"; + }; - lazyAttrs = delib.types.lazyAttrsOf delib.types.anything; + lazyAttrs = delib.types.lazyAttrsOf delib.types.unspecified; - list = delib.types.listOf delib.types.anything; + list = delib.types.listOf delib.types.unspecified; null = lib.mkOptionType { name = "null"; @@ -87,5 +94,24 @@ value = null; }; }; + + steppedInt = + step: + assert lib.assertMsg (builtins.isInt step) "steppedInt: step must be an integer"; + lib.types.addCheck delib.types.int (x: x == x / step * step) + // { + name = "steppedInt"; + description = "integer that is a multiple of ${step}"; + }; + + steppedIntBetween = + lowest: highest: step: + assert lib.assertMsg (builtins.isInt step) "steppedInt: step must be an integer"; + assert lib.assertMsg (lowest <= highest) "intBetween: lowest must be smaller than highest"; + lib.types.addCheck delib.types.int (x: x >= lowest && x <= highest && x == x / step * step) + // { + name = "steppedIntBetween"; + description = "integer between ${toString lowest} and ${toString highest} (inclusive) that is a multiple of ${step}"; + }; # keep-sorted end } From 9fa2f4facd5ebcac6f67763126208298d48dca04 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Mon, 22 Sep 2025 15:14:44 +0300 Subject: [PATCH 06/21] lib/modules/config/moduleSystems: add missing myconfig to imports --- lib/modules/config/moduleSystems/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/modules/config/moduleSystems/default.nix b/lib/modules/config/moduleSystems/default.nix index cef0cfa..4ae8aaa 100644 --- a/lib/modules/config/moduleSystems/default.nix +++ b/lib/modules/config/moduleSystems/default.nix @@ -11,6 +11,7 @@ in imports = [ ./darwin.nix ./home.nix + ./myconfig.nix ./nixos.nix ]; From 8017a9002668bad27ad847b67385021a3ac91449 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 23 Oct 2025 20:43:12 +0300 Subject: [PATCH 07/21] WIP: working prototype --- examples/module/flake.lock | 118 ++++----- examples/module/flake.nix | 22 +- examples/module/module.nix | 25 +- examples/system/flake.lock | 180 +++++++++++++ examples/system/flake.nix | 30 +++ examples/system/host1.nix | 5 + examples/system/module1.nix | 10 + flake.lock | 58 ++--- flake.nix | 8 +- lib/attrset.nix | 8 +- lib/default.nix | 20 +- lib/modules/config/abstractions/default.nix | 6 + lib/modules/config/abstractions/hosts.nix | 103 ++++++++ lib/modules/config/abstractions/modules.nix | 115 ++++++++ lib/modules/config/denix.nix | 57 +--- lib/modules/config/moduleSystems/darwin.nix | 12 +- lib/modules/config/moduleSystems/default.nix | 52 +--- lib/modules/config/moduleSystems/home.nix | 12 +- lib/modules/config/moduleSystems/myconfig.nix | 55 +--- lib/modules/config/moduleSystems/nixos.nix | 12 +- lib/modules/config/moduleSystems/options.nix | 18 ++ lib/modules/default.nix | 245 +++++++++++------- lib/modules/helpers.nix | 124 +++++++++ lib/toplevel/lib.nix | 6 +- lib/types.nix | 46 +--- lib/umport.nix | 56 ++++ 26 files changed, 979 insertions(+), 424 deletions(-) create mode 100644 examples/system/flake.lock create mode 100644 examples/system/flake.nix create mode 100644 examples/system/host1.nix create mode 100644 examples/system/module1.nix create mode 100644 lib/modules/config/abstractions/default.nix create mode 100644 lib/modules/config/abstractions/hosts.nix create mode 100644 lib/modules/config/abstractions/modules.nix create mode 100644 lib/modules/config/moduleSystems/options.nix create mode 100644 lib/modules/helpers.nix create mode 100644 lib/umport.nix diff --git a/examples/module/flake.lock b/examples/module/flake.lock index 9fb6730..2471ab5 100644 --- a/examples/module/flake.lock +++ b/examples/module/flake.lock @@ -2,11 +2,11 @@ "nodes": { "denix": { "inputs": { + "git-hooks": "git-hooks", "home-manager": "home-manager", "nix-darwin": "nix-darwin", - "nixpkgs": "nixpkgs", - "nixpkgs-lib": "nixpkgs-lib", - "pre-commit-hooks": "pre-commit-hooks" + "nixpkgs": "nixpkgs_2", + "nixpkgs-lib": "nixpkgs-lib" }, "locked": { "path": "../../.", @@ -34,11 +34,31 @@ "type": "github" } }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1759523803, + "narHash": "sha256-PTod9NG+i3XbbnBKMl/e5uHDBYpwIWivQ3gOWSEuIEM=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "cfc9f7bb163ad8542029d303e599c0f7eee09835", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "gitignore": { "inputs": { "nixpkgs": [ "denix", - "pre-commit-hooks", + "git-hooks", "nixpkgs" ] }, @@ -64,11 +84,11 @@ ] }, "locked": { - "lastModified": 1754613544, - "narHash": "sha256-ueR1mGX4I4DWfDRRxxMphbKDNisDeMPMusN72VV1+cc=", + "lastModified": 1759573136, + "narHash": "sha256-ILSPD0Dm8p0w0fCVzOx98ZH8yFDrR75GmwmH3fS2VnE=", "owner": "nix-community", "repo": "home-manager", - "rev": "cc2fa2331aebf9661d22bb507d362b39852ac73f", + "rev": "5f06ceafc6c9b773a776b9195c3f47bbe1defa43", "type": "github" }, "original": { @@ -86,11 +106,11 @@ ] }, "locked": { - "lastModified": 1751313918, - "narHash": "sha256-HsJM3XLa43WpG+665aGEh8iS8AfEwOIQWk3Mke3e7nk=", + "lastModified": 1758805352, + "narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "e04a388232d9a6ba56967ce5b53a8a6f713cdfcf", + "rev": "c48e963a5558eb1c3827d59d21c5193622a1477c", "type": "github" }, "original": { @@ -101,42 +121,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1754498491, - "narHash": "sha256-erbiH2agUTD0Z30xcVSFcDHzkRvkRXOQ3lb887bcVrs=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "c2ae88e026f9525daf89587f3cbee584b92b6134", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1754184128, - "narHash": "sha256-AjhoyBL4eSyXf01Bmc6DiuaMrJRNdWopmdnMY0Pa/M0=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "02e72200e6d56494f4a7c0da8118760736e41b60", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1754340878, - "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", + "lastModified": 1759070547, + "narHash": "sha256-JVZl8NaVRYb0+381nl7LvPE+A774/dRpif01FKLrYFQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "cab778239e705082fe97bb4990e0d24c50924c04", + "rev": "647e5c14cbd5067f44ac86b74f014962df460840", "type": "github" }, "original": { @@ -146,44 +135,33 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs-lib": { "locked": { - "lastModified": 1756159630, - "narHash": "sha256-ohMvsjtSVdT/bruXf5ClBh8ZYXRmD4krmjKrXhEvwMg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "84c256e42600cb0fdf25763b48d28df2f25a0c8b", - "type": "github" + "lastModified": 1759652833, + "narHash": "sha256-wTPGkIxVbJrZobKNCNhC5a0XB8Lknuta340ShA00LV4=", + "path": "/home/yunfachi/files/desktop/git/nixpkgs/lib", + "type": "path" }, "original": { - "id": "nixpkgs", - "type": "indirect" + "path": "/home/yunfachi/files/desktop/git/nixpkgs/lib", + "type": "path" } }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": "nixpkgs_2" - }, + "nixpkgs_2": { "locked": { - "lastModified": 1754416808, - "narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864", - "type": "github" + "lastModified": 1759652833, + "narHash": "sha256-GUDAlrlI/3RXDqIrwI2JFzczNNOpsxvKTIECS+OE/0I=", + "path": "/home/yunfachi/files/desktop/git/nixpkgs", + "type": "path" }, "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" + "path": "/home/yunfachi/files/desktop/git/nixpkgs", + "type": "path" } }, "root": { "inputs": { - "denix": "denix", - "nixpkgs": "nixpkgs_3" + "denix": "denix" } } }, diff --git a/examples/module/flake.nix b/examples/module/flake.nix index 4f51159..2575758 100644 --- a/examples/module/flake.nix +++ b/examples/module/flake.nix @@ -1,8 +1,6 @@ { inputs = { - #nixpkgs.url = "/home/yunfachi/files/desktop/git/nixpkgs"; denix.url = "../../."; - #denix.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = @@ -13,27 +11,17 @@ }: let delib = denix.lib; + modules = delib.genModules { + configuration = self.denixConfiguration; + }; in { denixConfiguration = delib.denixConfiguration { modules = [ ./module.nix ]; }; - nixosModules.default = delib.compileModule { - moduleSystem = "nixos"; - configuration = self.denixConfiguration; - }; + nixosModules.default = modules.nixos; - homeModules.default = delib.compileModule { - moduleSystem = "home"; - configuration = self.denixConfiguration; - /* - applyMyConfig = - { myconfig, ... }: - { - imports = myconfig.type.getSubModules; - }; - */ - }; + homeModules.default = modules.home; }; } diff --git a/examples/module/module.nix b/examples/module/module.nix index bebc842..ea39b66 100644 --- a/examples/module/module.nix +++ b/examples/module/module.nix @@ -4,14 +4,29 @@ options = with delib; { enable = boolOption true; test = intOption 0; + asd = intOption 1; }; - myconfig.ifEnabled = { - programs.module.test = 213; - }; + myconfig.always = + { config, ... }: + { + #programs.module.test = config.myconfig.programs.module.asd; + }; + + #myconfig.ifEnabled.programs.module.test = 999; + + nixos.ifEnabled = + { test, ... }: + { + #nixpkgs.hostPlatform = "x86_64-linux"; + _module.args.test = 123; + myconfig.programs.module.test = test; + }; + }; - nixos.ifEnabled = { - nixpkgs.hostPlatform = "x86_64-linux"; + hosts."keka" = { + myconfig.ifDisabled = { + programs.module.enable = false; }; }; } diff --git a/examples/system/flake.lock b/examples/system/flake.lock new file mode 100644 index 0000000..1257c5d --- /dev/null +++ b/examples/system/flake.lock @@ -0,0 +1,180 @@ +{ + "nodes": { + "denix": { + "inputs": { + "git-hooks": "git-hooks", + "home-manager": "home-manager", + "nix-darwin": "nix-darwin", + "nixpkgs": "nixpkgs_2", + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "path": "../../.", + "type": "path" + }, + "original": { + "path": "../../.", + "type": "path" + }, + "parent": [] + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1757239681, + "narHash": "sha256-E9spYi9lxm2f1zWQLQ7xQt8Xs2nWgr1T4QM7ZjLFphM=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "ab82ab08d6bf74085bd328de2a8722c12d97bd9d", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "denix", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "denix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1757075491, + "narHash": "sha256-a+NMGl5tcvm+hyfSG2DlVPa8nZLpsumuRj1FfcKb2mQ=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "f56bf065f9abedc7bc15e1f2454aa5c8edabaacf", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "master", + "repo": "home-manager", + "type": "github" + } + }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "denix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1757130842, + "narHash": "sha256-4i7KKuXesSZGUv0cLPLfxbmF1S72Gf/3aSypgvVkwuA=", + "owner": "nix-darwin", + "repo": "nix-darwin", + "rev": "15f067638e2887c58c4b6ba1bdb65a0b61dc58c5", + "type": "github" + }, + "original": { + "owner": "nix-darwin", + "repo": "nix-darwin", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1754340878, + "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cab778239e705082fe97bb4990e0d24c50924c04", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1759431872, + "narHash": "sha256-udV7H1CXdx7xqTheYsFblnBmaBDF3SrFhXrfHK3/pFI=", + "owner": "yunfachi", + "repo": "nixpkgs", + "rev": "0e623418081b847aaad7b975fcadc2ea4c04369c", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "yunfachi", + "ref": "feat/extensible-option-types", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1756478791, + "narHash": "sha256-F2fHTBUA/S99Kwv99k51Xb990LIihlK2Ys29rrTfMoE=", + "owner": "yunfachi", + "repo": "nixpkgs", + "rev": "da2a71835653a4d11bbe3738830d90f048ae9d30", + "type": "github" + }, + "original": { + "owner": "yunfachi", + "ref": "patch-2", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "denix": "denix" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/examples/system/flake.nix b/examples/system/flake.nix new file mode 100644 index 0000000..1e0d13f --- /dev/null +++ b/examples/system/flake.nix @@ -0,0 +1,30 @@ +{ + inputs = { + #nixpkgs.url = "/home/yunfachi/files/desktop/git/nixpkgs"; + denix.url = "../../."; + #denix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + { + denix, + self, + ... + }: + let + delib = denix.lib; + in + { + denixConfiguration = delib.denixConfiguration { + modules = [ + ./module1.nix + ./host1.nix + ]; + }; + + nixosConfigurations = self.denixConfiguration.genSystem { + moduleSystem = "nixos"; + forEachHost = true; + }; + }; +} diff --git a/examples/system/host1.nix b/examples/system/host1.nix new file mode 100644 index 0000000..840beec --- /dev/null +++ b/examples/system/host1.nix @@ -0,0 +1,5 @@ +{ + hosts.host1 = { + nixos.ifEnabled.nixpkgs.hostPlatform = "x86_64-linux"; + }; +} diff --git a/examples/system/module1.nix b/examples/system/module1.nix new file mode 100644 index 0000000..9d06c0a --- /dev/null +++ b/examples/system/module1.nix @@ -0,0 +1,10 @@ +{ delib, ... }: +{ + modules."programs.git" = { + options = { + enable = delib.boolOption false; + }; + + nixos.ifEnabled.programs.git.enable = true; + }; +} diff --git a/flake.lock b/flake.lock index 6fbbda5..64c75f8 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1757239681, - "narHash": "sha256-E9spYi9lxm2f1zWQLQ7xQt8Xs2nWgr1T4QM7ZjLFphM=", + "lastModified": 1759523803, + "narHash": "sha256-PTod9NG+i3XbbnBKMl/e5uHDBYpwIWivQ3gOWSEuIEM=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "ab82ab08d6bf74085bd328de2a8722c12d97bd9d", + "rev": "cfc9f7bb163ad8542029d303e599c0f7eee09835", "type": "github" }, "original": { @@ -64,11 +64,11 @@ ] }, "locked": { - "lastModified": 1757075491, - "narHash": "sha256-a+NMGl5tcvm+hyfSG2DlVPa8nZLpsumuRj1FfcKb2mQ=", + "lastModified": 1759573136, + "narHash": "sha256-ILSPD0Dm8p0w0fCVzOx98ZH8yFDrR75GmwmH3fS2VnE=", "owner": "nix-community", "repo": "home-manager", - "rev": "f56bf065f9abedc7bc15e1f2454aa5c8edabaacf", + "rev": "5f06ceafc6c9b773a776b9195c3f47bbe1defa43", "type": "github" }, "original": { @@ -85,11 +85,11 @@ ] }, "locked": { - "lastModified": 1757130842, - "narHash": "sha256-4i7KKuXesSZGUv0cLPLfxbmF1S72Gf/3aSypgvVkwuA=", + "lastModified": 1758805352, + "narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "15f067638e2887c58c4b6ba1bdb65a0b61dc58c5", + "rev": "c48e963a5558eb1c3827d59d21c5193622a1477c", "type": "github" }, "original": { @@ -100,11 +100,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1754340878, - "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", + "lastModified": 1759070547, + "narHash": "sha256-JVZl8NaVRYb0+381nl7LvPE+A774/dRpif01FKLrYFQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "cab778239e705082fe97bb4990e0d24c50924c04", + "rev": "647e5c14cbd5067f44ac86b74f014962df460840", "type": "github" }, "original": { @@ -116,36 +116,26 @@ }, "nixpkgs-lib": { "locked": { - "dir": "lib", - "lastModified": 1756478791, - "narHash": "sha256-F2fHTBUA/S99Kwv99k51Xb990LIihlK2Ys29rrTfMoE=", - "owner": "yunfachi", - "repo": "nixpkgs", - "rev": "da2a71835653a4d11bbe3738830d90f048ae9d30", - "type": "github" + "lastModified": 1759652833, + "narHash": "sha256-wTPGkIxVbJrZobKNCNhC5a0XB8Lknuta340ShA00LV4=", + "path": "/home/yunfachi/files/desktop/git/nixpkgs/lib", + "type": "path" }, "original": { - "dir": "lib", - "owner": "yunfachi", - "ref": "patch-2", - "repo": "nixpkgs", - "type": "github" + "path": "/home/yunfachi/files/desktop/git/nixpkgs/lib", + "type": "path" } }, "nixpkgs_2": { "locked": { - "lastModified": 1756478791, - "narHash": "sha256-F2fHTBUA/S99Kwv99k51Xb990LIihlK2Ys29rrTfMoE=", - "owner": "yunfachi", - "repo": "nixpkgs", - "rev": "da2a71835653a4d11bbe3738830d90f048ae9d30", - "type": "github" + "lastModified": 1759652833, + "narHash": "sha256-GUDAlrlI/3RXDqIrwI2JFzczNNOpsxvKTIECS+OE/0I=", + "path": "/home/yunfachi/files/desktop/git/nixpkgs", + "type": "path" }, "original": { - "owner": "yunfachi", - "ref": "patch-2", - "repo": "nixpkgs", - "type": "github" + "path": "/home/yunfachi/files/desktop/git/nixpkgs", + "type": "path" } }, "root": { diff --git a/flake.nix b/flake.nix index 4ea062f..ece88a5 100644 --- a/flake.nix +++ b/flake.nix @@ -1,9 +1,8 @@ { - description = "Nix library for creating scalable NixOS, Home Manager, and Nix-Darwin configurations with modules, hosts, and rices."; + description = "Nix library for creating scalable configurations, modules, and libraries."; inputs = { - #nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; - nixpkgs-lib.url = "github:yunfachi/nixpkgs/patch-2?dir=lib"; + nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; git-hooks.url = "github:cachix/git-hooks.nix"; /** @@ -13,8 +12,7 @@ to their own channel, while nixpkgs-lib is a library used by Denix, and it should not be overridden by the user without a special reason. */ - #nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - nixpkgs.url = "github:yunfachi/nixpkgs/patch-2"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; home-manager = { url = "github:nix-community/home-manager/master"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/lib/attrset.nix b/lib/attrset.nix index b97d445..5ab9269 100644 --- a/lib/attrset.nix +++ b/lib/attrset.nix @@ -4,8 +4,14 @@ set: strPath: default: lib.attrByPath (lib.splitString "." strPath) default set; - setAttrByStrPath = value: strPath: lib.setAttrByPath (lib.splitString "." strPath) value; + setAttrByStrPath = + value: strPath: + if strPath != null then lib.setAttrByPath (lib.splitString "." strPath) value else value; hasAttrs = set: attrs: if attrs != [ ] then builtins.any (attr: builtins.hasAttr attr set) attrs else true; + + keepAttrs = + attrs: names: + removeAttrs attrs (builtins.filter (name: !builtins.elem name names) (builtins.attrNames attrs)); } diff --git a/lib/default.nix b/lib/default.nix index b40e407..32287a1 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -29,21 +29,30 @@ mkLib "delib" (delib: { modules = delib._callLib ./modules; inherit (delib.modules) denixConfiguration - callDenixModule - compileModule + genModule + genSystem ; attrset = delib._callLib ./attrset.nix; - inherit (delib.attrset) getAttrByStrPath setAttrByStrPath hasAttrs; + inherit (delib.attrset) + getAttrByStrPath + setAttrByStrPath + hasAttrs + keepAttrs + ; options = delib._callLib ./options.nix; types = delib._callLib ./types.nix; + inherit (delib._callLib ./umport.nix) umport; + # Generated inherits. # After implementing https://github.com/NixOS/nix/issues/4090 it will be possible to use `// delib.options` (to inherit all) #[[[cog + # groups = ["options", "types"] + # # import cog # import subprocess # import json @@ -61,7 +70,7 @@ mkLib "delib" (delib: { # out = os.environ[f"pre_evaled_{attr}"] # return json.loads(out) # - # for group in ["options", "types"]: + # for group in groups: # cog.outl(f"inherit (delib.{group})") # for name in nix_attr_names(group): # cog.outl(f" {name}") @@ -74,6 +83,7 @@ mkLib "delib" (delib: { allowAttrsOf allowBool allowCoercedTo + allowEither allowEnum allowFloat allowFunction @@ -106,6 +116,7 @@ mkLib "delib" (delib: { coercedToOption defaultText description + eitherOption enumOption example floatOption @@ -142,6 +153,7 @@ mkLib "delib" (delib: { attrsOf bool coercedTo + either enum float function diff --git a/lib/modules/config/abstractions/default.nix b/lib/modules/config/abstractions/default.nix new file mode 100644 index 0000000..4680d73 --- /dev/null +++ b/lib/modules/config/abstractions/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./hosts.nix + ./modules.nix + ]; +} diff --git a/lib/modules/config/abstractions/hosts.nix b/lib/modules/config/abstractions/hosts.nix new file mode 100644 index 0000000..f6e880d --- /dev/null +++ b/lib/modules/config/abstractions/hosts.nix @@ -0,0 +1,103 @@ +{ + delib, + lib, + config, + ... +}: +let + toDenixHostArgsFunctor = functor: { + _type = "denixHostArgsFunctor"; + __functor = + self: + { + name, + }@args: + functor args; + }; + + isDenixHostArgsFunctor = x: x._type or null == "denixHostArgsFunctor"; + + callDenixHostArgsFunctor = x: args: if isDenixHostArgsFunctor x then x args else x; + + inheritFunctionArgs = + f: g: + let + fArgs = lib.functionArgs f; + gArgs = lib.functionArgs g; + in + lib.setFunctionArgs g (fArgs // gArgs); + + mapItem = + hostName: moduleSystemName: myconfigPrefix: pathSuffix: contentFn: index: entry: + let + keyAttrs.key = "denix.hosts.'${hostName}'.'${moduleSystemName}'${pathSuffix}-${toString index}"; + in + if !lib.isFunction entry && !lib.isFunction (contentFn entry) then + keyAttrs // (contentFn entry) + else + let + fakeCalled = callDenixHostArgsFunctor entry { + name = hostName; + }; + in + inheritFunctionArgs (lib.toFunction fakeCalled) ( + { config, options, ... }@args: + let + called = callDenixHostArgsFunctor entry { + name = hostName; + }; + calledFn = (lib.toFunction called) args; + in + keyAttrs // calledFn + ); +in +{ + options = with delib; { + host = allowNull ( + coercedToOption (enum (builtins.attrNames config.hosts)) ( + hostName: if hostName == null then null else config.hosts.${hostName} + ) (enum (builtins.attrValues config.hosts)) null + ); + + hosts = attrsOfOption (delib.modules.denixModuleType { + moduleSystems = builtins.removeAttrs config.moduleSystems [ "options" ]; + fakeCall = + host: + lib.fix ( + self: + host { + inherit (self) name; + } + ); + toFunctor = toDenixHostArgsFunctor; + }) { }; + }; + + config.rawModules = lib.mapAttrs ( + moduleSystemName: moduleSystem: + let + myconfigPrefix = lib.optionalString ( + moduleSystem.myconfigPrefix != null + ) "${moduleSystem.myconfigPrefix}."; + in + lib.concatLists ( + lib.mapAttrsToList ( + hostName: host: + let + contentAlways = entry: entry; + contentIfEnabled = entry: if config.host.name or null == hostName then entry else { }; + contentIfDisabled = entry: if config.host.name or null != hostName then entry else { }; + in + lib.imap1 (mapItem hostName moduleSystemName myconfigPrefix ".always" + contentAlways + ) host.${moduleSystemName}.always + ++ lib.imap1 (mapItem hostName moduleSystemName myconfigPrefix ".ifEnabled" + contentIfEnabled + ) host.${moduleSystemName}.ifEnabled + ++ lib.imap1 (mapItem hostName moduleSystemName myconfigPrefix ".ifDisabled" + contentIfDisabled + ) host.${moduleSystemName}.ifDisabled + ) config.hosts + ) + ) (builtins.removeAttrs config.moduleSystems [ "options" ]); +} diff --git a/lib/modules/config/abstractions/modules.nix b/lib/modules/config/abstractions/modules.nix new file mode 100644 index 0000000..b9f9436 --- /dev/null +++ b/lib/modules/config/abstractions/modules.nix @@ -0,0 +1,115 @@ +{ + delib, + lib, + config, + ... +}: +let + toDenixModuleArgsFunctor = functor: { + _type = "denixModuleArgsFunctor"; + __functor = + self: + { + name, + cfg, + opt, + }@args: + functor args; + }; + + isDenixModuleArgsFunctor = x: x._type or null == "denixModuleArgsFunctor"; + + callDenixModuleArgsFunctor = x: args: if isDenixModuleArgsFunctor x then x args else x; + + inheritFunctionArgs = + f: g: + let + fArgs = lib.functionArgs f; + gArgs = lib.functionArgs g; + in + lib.setFunctionArgs g (fArgs // gArgs); + + mapItem = + moduleName: moduleSystemName: myconfigPrefix: pathSuffix: contentFn: index: entry: + let + keyAttrs.key = "denix.modules.'${moduleName}'.'${moduleSystemName}'${pathSuffix}-${toString index}"; + in + if !lib.isFunction entry && !lib.isFunction (contentFn entry) then + keyAttrs // (contentFn entry) + else + let + fakeCalled = callDenixModuleArgsFunctor entry { + name = moduleName; + cfg = { }; + opt = { }; + }; + in + inheritFunctionArgs (lib.toFunction fakeCalled) ( + { config, options, ... }@args: + let + called = callDenixModuleArgsFunctor entry { + name = moduleName; + cfg = delib.getAttrByStrPath config "${myconfigPrefix}${moduleName}" { }; + opt = delib.getAttrByStrPath options "${myconfigPrefix}${moduleName}" { }; + }; + calledFn = (lib.toFunction called) args; + withOptionalConfig = lib.toFunction calledFn; + in + keyAttrs // (withOptionalConfig config) + ); +in +{ + options = with delib; { + modules = attrsOfOption (delib.modules.denixModuleType { + moduleSystems = config.moduleSystems; + fakeCall = + module: + lib.fix ( + self: + module { + inherit (self) name; + cfg = { }; + opt = { }; + } + ); + toFunctor = toDenixModuleArgsFunctor; + }) { }; + }; + + config.rawModules = lib.mapAttrs ( + moduleSystemName: moduleSystem: + let + myconfigPrefix = lib.optionalString ( + moduleSystem.myconfigPrefix != null + ) "${moduleSystem.myconfigPrefix}."; + in + lib.concatLists ( + lib.mapAttrsToList ( + moduleName: module: + let + contentOptions = entry: { options = delib.setAttrByStrPath entry moduleName; }; + contentAlways = entry: entry; + contentIfEnabled = + entry: config: + lib.mkIf (delib.getAttrByStrPath config "${myconfigPrefix}${moduleName}.enable" false) entry; + contentIfDisabled = + entry: config: + lib.mkIf (!(delib.getAttrByStrPath config "${myconfigPrefix}${moduleName}.enable" true)) entry; + + in + if moduleSystemName == "options" then + lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix "" contentOptions) module.options + else + lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix ".always" + contentAlways + ) module.${moduleSystemName}.always + ++ lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix ".ifEnabled" + contentIfEnabled + ) module.${moduleSystemName}.ifEnabled + ++ lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix ".ifDisabled" + contentIfDisabled + ) module.${moduleSystemName}.ifDisabled + ) config.modules + ) + ) config.moduleSystems; +} diff --git a/lib/modules/config/denix.nix b/lib/modules/config/denix.nix index 1c3ff1a..9ebec9a 100644 --- a/lib/modules/config/denix.nix +++ b/lib/modules/config/denix.nix @@ -6,58 +6,15 @@ }: { imports = [ + ./abstractions/default.nix ./moduleSystems/default.nix ]; - options = - with delib; - let - modulesOption = lib.mkOption { - type = lib.mkOptionType { - name = "modules"; - check = with lib; x: !(isFunction x && isPath x && isAttrs x && isList x); - merge = - loc: defs: - lib.concatLists ( - map ( - def: - lib.toList ( - if lib.isFunction def.value then - lib.setFunctionArgs def.value (lib.functionArgs def.value) - else - def.value - ) - ) defs - ); - }; - default = [ ]; - }; - in - { - myconfigPrefix = allowNull (strOption "myconfig"); + options = with delib; { + myconfigPrefix = allowNull (strOption "myconfig"); - modules = attrsOfOption ( - functionTo (submoduleWith { - # NOTE: requires https://github.com/NixOS/nixpkgs/pull/437972 - onlyDefinesConfig = true; - modules = [ - ( - { name, ... }: - { - options = { - name = readOnly (strOption name) true; - - options = modulesOption; - } - // builtins.mapAttrs (name: value: { - always = modulesOption; - ifEnabled = modulesOption; - ifDisabled = modulesOption; - }) config.moduleSystems; - } - ) - ]; - }) - ); - }; + rawModules = lib.mapAttrs ( + moduleSystemName: moduleSystem: modules.listOfModulesOption + ) config.moduleSystems; + }; } diff --git a/lib/modules/config/moduleSystems/darwin.nix b/lib/modules/config/moduleSystems/darwin.nix index d694a53..292ab6a 100644 --- a/lib/modules/config/moduleSystems/darwin.nix +++ b/lib/modules/config/moduleSystems/darwin.nix @@ -1,3 +1,13 @@ +{ nix-darwin, ... }: { - moduleSystems.darwin = { }; + moduleSystems.darwin = { + makeSystem = + { modules, extraArgs, ... }: + nix-darwin.lib.darwinSystem ( + { + inherit modules; + } + // extraArgs + ); + }; } diff --git a/lib/modules/config/moduleSystems/default.nix b/lib/modules/config/moduleSystems/default.nix index 4ae8aaa..5618592 100644 --- a/lib/modules/config/moduleSystems/default.nix +++ b/lib/modules/config/moduleSystems/default.nix @@ -4,74 +4,34 @@ config, ... }: -let - myconfigPrefixDefault = config.myconfigPrefix; -in { imports = [ ./darwin.nix ./home.nix ./myconfig.nix ./nixos.nix + ./options.nix ]; options = with delib; { moduleSystems = lazyAttrsOfOption (submoduleWith { modules = [ ( - { config, name, ... }: - let - mkMyConfigPrefix = myconfigPrefix: lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; - in + { name, ... }: { options = { name = readOnly (strOption name); - myconfigPrefix = allowNull (strOption myconfigPrefixDefault); + myconfigPrefix = allowNull (strOption config.myconfigPrefix); - applyOptions = functionToOption attrs ( - { - myconfigPrefix, - moduleName, - value, - }: - { - imports = [ - (lib.setFunctionArgs (args: { - options = delib.setAttrByStrPath (value args) ((mkMyConfigPrefix myconfigPrefix) + moduleName); - }) (lib.functionArgs value)) - ]; - } - ); + makeSystem = allowNull (functionOption null); - applyModuleSystemsConfig = functionToOption attrs ( + applyConfigForModuleSystem = functionToOption list ( { - myconfigPrefix, moduleSystem, - moduleName, value, - type, }: - lib.optionalAttrs (moduleSystem == name) { - imports = [ - { - always = value; - ifEnabled = lib.setFunctionArgs ( - { config, ... }@args: - lib.mkIf (delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" - false - ) (value args) - ) ({ config = false; } // (lib.functionArgs value)); - ifDisabled = lib.setFunctionArgs ( - { config, ... }@args: - lib.mkIf ( - !(delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" true) - ) (value args) - ) ({ config = false; } // (lib.functionArgs value)); - } - .${type} - ]; - } + lib.optional (moduleSystem == name) value ); }; } diff --git a/lib/modules/config/moduleSystems/home.nix b/lib/modules/config/moduleSystems/home.nix index 7fda68c..77993c0 100644 --- a/lib/modules/config/moduleSystems/home.nix +++ b/lib/modules/config/moduleSystems/home.nix @@ -1,3 +1,13 @@ +{ home-manager, ... }: { - moduleSystems.home = { }; + moduleSystems.home = { + makeSystem = + { modules, extraArgs, ... }: + home-manager.lib.homeManagerConfiguration ( + { + inherit modules; + } + // extraArgs + ); + }; } diff --git a/lib/modules/config/moduleSystems/myconfig.nix b/lib/modules/config/moduleSystems/myconfig.nix index f131e41..c8b4ff4 100644 --- a/lib/modules/config/moduleSystems/myconfig.nix +++ b/lib/modules/config/moduleSystems/myconfig.nix @@ -1,55 +1,18 @@ -{ delib, ... }: +{ delib, lib, ... }: { moduleSystems.myconfig = - with delib; - { name, ... }: + { name, config, ... }: { - applyModuleSystemsConfig = + applyConfigForModuleSystem = { - myconfigPrefix, moduleSystem, - moduleName, value, - type, }: - { - imports = [ - (lib.setFunctionArgs ( - { config, ... }@args: - let - mkMyConfigPrefix = myconfigPrefix: lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; - called = value args; - unified = lib.unifyModuleSyntax ./default.nix "somekey" called; - in - { - always = { - config = delib.setAttrByStrPath unified.config myconfigPrefix; - options = delib.setAttrByStrPath unified.options myconfigPrefix; - }; - - ifEnabled = { - config = lib.mkIf (delib.getAttrByStrPath config - "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" - false - ) (delib.setAttrByStrPath unified.config myconfigPrefix); - options = lib.mkIf (delib.getAttrByStrPath config - "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" - false - ) (delib.setAttrByStrPath unified.options myconfigPrefix); - }; - - ifDisabled = { - config = lib.mkIf ( - !(delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" true) - ) (delib.setAttrByStrPath unified.config myconfigPrefix); - options = lib.mkIf ( - !(delib.getAttrByStrPath config "${mkMyConfigPrefix myconfigPrefix}${moduleName}.enable" true) - ) (delib.setAttrByStrPath unified.options myconfigPrefix); - }; - } - .${type} - ) (lib.getFunctionArgs value)) - ]; - }; + let + addPrefixToModule = delib.modules.addPrefixToModule (lib.splitString "." config.myconfigPrefix); + in + [ + (if lib.isFunction value then args: addPrefixToModule (value args) else addPrefixToModule value) + ]; }; } diff --git a/lib/modules/config/moduleSystems/nixos.nix b/lib/modules/config/moduleSystems/nixos.nix index 10cf243..723dafb 100644 --- a/lib/modules/config/moduleSystems/nixos.nix +++ b/lib/modules/config/moduleSystems/nixos.nix @@ -1,3 +1,13 @@ +{ nixpkgs, ... }: { - moduleSystems.nixos = { }; + moduleSystems.nixos = { + makeSystem = + { modules, extraArgs, ... }: + nixpkgs.lib.nixosSystem ( + { + inherit modules; + } + // extraArgs + ); + }; } diff --git a/lib/modules/config/moduleSystems/options.nix b/lib/modules/config/moduleSystems/options.nix new file mode 100644 index 0000000..baf7f79 --- /dev/null +++ b/lib/modules/config/moduleSystems/options.nix @@ -0,0 +1,18 @@ +{ delib, lib, ... }: +{ + moduleSystems.options = + { name, config, ... }: + { + applyConfigForModuleSystem = + { + moduleSystem, + value, + }: + let + addPrefixToModule = delib.modules.addPrefixToModule (lib.splitString "." config.myconfigPrefix); + in + [ + (if lib.isFunction value then args: addPrefixToModule (value args) else addPrefixToModule value) + ]; + }; +} diff --git a/lib/modules/default.nix b/lib/modules/default.nix index a5b2444..f2c9f68 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -6,114 +6,165 @@ nix-darwin, ... }: -{ +delib._callLib ./helpers.nix +// { denixConfiguration = { modules ? [ ], specialArgs ? { }, }: - lib.evalModules { - modules = [ ./config/denix.nix ] ++ modules; + let + evaledModules = lib.evalModules { + modules = [ ./config/denix.nix ] ++ modules; - specialArgs = { - inherit nixpkgs home-manager nix-darwin; - } - // lib.recursiveUpdate { - inherit delib; - } specialArgs; - }; + specialArgs = { + inherit nixpkgs home-manager nix-darwin; + # `specialArgs.modulesPath` is used as the base path for `disabledModules`. + modulesPath = ./config; + } + // lib.recursiveUpdate { + inherit delib; + } specialArgs; + }; + + withExtraAttrs = + configuration: + configuration + // { + genModule = + { + moduleSystem ? null, + forEachModuleSystem ? false, + host ? null, + forEachHost ? false, + }@args: + delib.genModule ({ inherit configuration; } // args); - callDenixModule = - { module, myconfigPrefix }: - { config, options, ... }: - delib.fix ( - self: - let - modulePath = lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}." + self.name; - in - module { - inherit (self) name; - cfg = delib.getAttrByStrPath config modulePath { }; - opt = delib.getAttrByStrPath options modulePath { }; - } - ); + genSystem = + { + extraArgs ? { }, + moduleSystem ? null, + forEachModuleSystem ? false, + host ? null, + forEachHost ? false, + }@args: + delib.genSystem ({ inherit configuration; } // args); - compileModule = + extendModules = args: withExtraAttrs (configuration.extendModules args); + }; + in + withExtraAttrs evaledModules; + + genModule' = { configuration, moduleSystem, - myconfigPrefix ? configuration.config.moduleSystems.${moduleSystem}.myconfigPrefix, - applyModuleSystemsConfig ? - configuration.config.moduleSystems.${moduleSystem}.applyModuleSystemsConfig, - applyOptions ? configuration.config.moduleSystems.${moduleSystem}.applyOptions, - applyMyConfig ? configuration.config.moduleSystems.${moduleSystem}.applyMyConfig, - }: - ( - let - allModules = lib.attrValues configuration.config.modules; - allModuleSystems = lib.attrNames configuration.config.moduleSystems; - in - { - imports = lib.concatMap ( - module: - let - fakeCalled = delib.callDenixModule { inherit module myconfigPrefix; } { - config = { }; - options = { }; + host ? null, + }@args: + let + configuration = + if host == null then + args.configuration + else + args.configuration.extendModules { + modules = lib.singleton { + config.host = host; }; - genModulesWithCalled = - y: - lib.genList ( - index: - { config, options, ... }@args: - let - called = delib.callDenixModule { inherit module myconfigPrefix; } args; - in - y index called - ); - in - genModulesWithCalled ( - index: called: - applyOptions { - inherit myconfigPrefix; - moduleName = called.name; - value = lib.elemAt called.options index; + }; + in + { + key = "denix.genModule { moduleSystem = ${moduleSystem}; }"; + + imports = lib.concatLists ( + lib.mapAttrsToList ( + moduleSystemName: rawModules: + lib.concatMap ( + value: + configuration.config.moduleSystems.${moduleSystemName}.applyConfigForModuleSystem { + inherit moduleSystem value; + } + ) rawModules + ) configuration.config.rawModules + ); + }; + + genModule = + { + configuration, + moduleSystem ? null, + forEachModuleSystem ? false, + host ? null, + forEachHost ? false, + }: + let + genSingle = + moduleSystem: host: + delib.modules.genModule' { + inherit + configuration + moduleSystem + host + ; + }; + + processHosts = + moduleSystem: + if forEachHost then + builtins.mapAttrs (host: _: genSingle moduleSystem host) configuration.config.hosts + else + genSingle moduleSystem host; + + processModuleSystems = + if forEachModuleSystem then + builtins.mapAttrs (moduleSystem: _: processHosts moduleSystem) configuration.config.moduleSystems + else + processHosts moduleSystem; + in + processModuleSystems; + + genSystem = + { + configuration, + extraArgs ? { }, + moduleSystem ? null, + forEachModuleSystem ? false, + host ? null, + forEachHost ? false, + }: + assert lib.assertMsg ( + moduleSystem == null || configuration.config.moduleSystems.${moduleSystem}.makeSystem != null + ) "moduleSystem with name '${moduleSystem}' does not support makeSystem."; + let + + genSingle = + moduleSystem: host: + configuration.config.moduleSystems.${moduleSystem}.makeSystem { + inherit extraArgs; + modules = lib.singleton ( + delib.modules.genModule' { + inherit + configuration + moduleSystem + host + ; } - ) (lib.length fakeCalled.options) - ++ lib.concatMap ( - moduleSystem': - genModulesWithCalled ( - index: called: - applyModuleSystemsConfig { - inherit myconfigPrefix; - moduleSystem = moduleSystem'; - moduleName = called.name; - value = lib.elemAt called.${moduleSystem'}.always index; - type = "always"; - } - ) (lib.length fakeCalled.${moduleSystem'}.always) - ++ genModulesWithCalled ( - index: called: - applyModuleSystemsConfig { - inherit myconfigPrefix; - moduleSystem = moduleSystem'; - moduleName = called.name; - value = lib.elemAt called.${moduleSystem'}.ifEnabled index; - type = "ifEnabled"; - } - ) (lib.length fakeCalled.${moduleSystem'}.ifEnabled) - ++ genModulesWithCalled ( - index: called: - applyModuleSystemsConfig { - inherit myconfigPrefix; - moduleSystem = moduleSystem'; - moduleName = called.name; - value = lib.elemAt called.${moduleSystem'}.ifDisabled index; - type = "ifDisabled"; - } - ) (lib.length fakeCalled.${moduleSystem'}.ifDisabled) - ) allModuleSystems - ) allModules; - } - ); + ); + }; + + processHosts = + moduleSystem: + if forEachHost then + builtins.mapAttrs (host: _: genSingle moduleSystem host) configuration.config.hosts + else + genSingle moduleSystem host; + + processModuleSystems = + if forEachModuleSystem then + builtins.mapAttrs (moduleSystem: _: processHosts moduleSystem) ( + lib.filterAttrs (name: value: value.makeSystem != null) configuration.config.moduleSystems + ) + else + processHosts moduleSystem; + in + processModuleSystems; } diff --git a/lib/modules/helpers.nix b/lib/modules/helpers.nix new file mode 100644 index 0000000..33aa5d8 --- /dev/null +++ b/lib/modules/helpers.nix @@ -0,0 +1,124 @@ +{ delib, lib, ... }: +{ + addPrefixToModule = + prefix: m: + let + type = m._type or "module"; + addPrefix = lib.setAttrByPath prefix; + in + if type == "module" && (m ? config || m ? options) then + m + // lib.optionalAttrs ((m.options or { }) != { }) { + options = addPrefix m.options; + } + // lib.optionalAttrs ((m.config or { }) != { }) { + config = addPrefix m.config; + } + else if type == "module" then + let + names = [ + "_class" + "_file" + "key" + "disabledModules" + "require" + "imports" + "freeformType" + ]; + in + delib.keepAttrs m names + // lib.optionalAttrs (builtins.removeAttrs m names != { }) { + config = addPrefix (builtins.removeAttrs m names); + } + else if type == "merge" then + m + // lib.optionalAttrs ((m.contents or [ ]) != [ ]) { + contents = map (delib.modules.addPrefixToModule prefix) m.contents; + } + else if type == "if" || type == "override" then + m + // lib.optionalAttrs ((m.content or { }) != { }) { + content = addPrefix m.content; + } + else + throw "denix.lib.modules.addPrefixToModule: passed module does not look like a module."; + + listOfModules = lib.mkOptionType { + name = "listOfModules"; + check = x: lib.isList x || lib.isAttrs x || lib.isFunction x || lib.path.check x; + merge = loc: defs: lib.concatMap (def: lib.toList def.value) defs; + emptyValue.value = [ ]; + }; + + listOfModulesOption = lib.mkOption { + type = delib.modules.listOfModules; + default = [ ]; + }; + + denixModuleType = + { + moduleSystems, + extraOptions ? name: { }, + fakeCall ? module: module { }, + toFunctor, + }: + with delib; + coercedTo (either (functionTo attrs) attrs) + (module: { + config = + if (!lib.isFunction module) then + module + else + let + called = fakeCall module; + + definedModuleSystems = lib.intersectLists (builtins.attrNames called) ( + builtins.attrNames moduleSystems + ); + + addDenixModuleArgsFunctor = + fn: + if builtins.isList (fn called) then + lib.imap0 (index: value: toFunctor (args: builtins.elemAt (fn (module args)) index)) (fn called) + else + toFunctor (args: fn (module args)); + + in + called + // lib.genAttrs definedModuleSystems ( + moduleSystem: + called.${moduleSystem} + // lib.genAttrs (lib.intersectLists (builtins.attrNames called.${moduleSystem}) [ + "always" + "ifEnabled" + "ifDisabled" + ]) (condition: addDenixModuleArgsFunctor (x: x.${moduleSystem}.${condition})) + ) + // lib.optionalAttrs (called ? options) { + options = addDenixModuleArgsFunctor (x: x.options); + }; + }) + (submoduleWith { + modules = [ + ( + { name, ... }: + { + options = + builtins.mapAttrs (name: value: { + always = delib.modules.listOfModulesOption; + ifEnabled = delib.modules.listOfModulesOption; + ifDisabled = delib.modules.listOfModulesOption; + }) moduleSystems + // lib.optionalAttrs (moduleSystems ? options) { + options = delib.modules.listOfModulesOption; + } + // { + name = readOnly (strOption name); + __toString = readOnly (functionToOption str (self: self.name)); + } + // extraOptions name; + } + ) + ]; + }); +} diff --git a/lib/toplevel/lib.nix b/lib/toplevel/lib.nix index 2766bc9..5722c90 100644 --- a/lib/toplevel/lib.nix +++ b/lib/toplevel/lib.nix @@ -39,7 +39,6 @@ in libName: ext: let extensible = fixedPoints.makeRecursivelyExtensible (self: { - /** Arguments passed to library parts called via `_callLib`. @@ -130,10 +129,9 @@ in _callLib = target: let - maybeFunction = if builtins.isPath target then import target else target; - callable = if lib.isFunction maybeFunction then maybeFunction else _: maybeFunction; + importedTarget = if builtins.isPath target then import target else target; in - callable self._callLibArgs; + (lib.toFunction importedTarget) self._callLibArgs; }); in extensible.recursivelyExtend (fixedPoints.toExtensionWithFinalFirst ext); diff --git a/lib/types.nix b/lib/types.nix index 542956d..82d46bc 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -6,8 +6,10 @@ attrsOf bool coercedTo + either enum float + functionTo int lazyAttrsOf listOf @@ -31,46 +33,6 @@ function = delib.types.functionTo delib.types.unspecified; - # FIX https://github.com/NixOS/nixpkgs/issues/438933 - functionTo = - elemType: - lib.mkOptionType { - name = "functionTo"; - description = "function that evaluates to a(n) ${ - lib.types.optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType - }"; - descriptionClass = "composite"; - check = lib.isFunction; - merge = loc: defs: { - # An argument attribute has a default when it has a default in all definitions - __functionArgs = lib.zipAttrsWith (_: lib.all (x: x)) ( - lib.map (fn: lib.functionArgs fn.value) defs - ); - __functor = - _: callerArgs: - (lib.mergeDefinitions loc elemType ( - map (fn: { - inherit (fn) file; - value = fn.value callerArgs; - }) defs - )).mergedValue; - }; - getSubOptions = prefix: elemType.getSubOptions prefix; - getSubModules = elemType.getSubModules; - substSubModules = m: delib.types.functionTo (elemType.substSubModules m); - functor = lib.defaultFunctor "functionTo" // { - type = payload: delib.types.functionTo payload.elemType; - payload.elemType = elemType; - binOp = - a: b: - let - merged = a.elemType.typeMerge b.elemType.functor; - in - if merged == null then null else { elemType = merged; }; - }; - nestedTypes.elemType = elemType; - }; - intBetween = lowest: highest: assert lib.assertMsg (lowest <= highest) "intBetween: lowest must be smaller than highest"; @@ -106,8 +68,8 @@ steppedIntBetween = lowest: highest: step: - assert lib.assertMsg (builtins.isInt step) "steppedInt: step must be an integer"; - assert lib.assertMsg (lowest <= highest) "intBetween: lowest must be smaller than highest"; + assert lib.assertMsg (builtins.isInt step) "steppedIntBetween: step must be an integer"; + assert lib.assertMsg (lowest <= highest) "steppedIntBetween: lowest must be smaller than highest"; lib.types.addCheck delib.types.int (x: x >= lowest && x <= highest && x == x / step * step) // { name = "steppedIntBetween"; diff --git a/lib/umport.nix b/lib/umport.nix new file mode 100644 index 0000000..ceff2a9 --- /dev/null +++ b/lib/umport.nix @@ -0,0 +1,56 @@ +# This function is copied from: +# https://github.com/yunfachi/nypkgs/blob/master/lib/umport.nix +# +# !!! REMOVING THIS NOTICE VIOLATES THE MIT LICENSE OF THE UMPORT PROJECT !!! +# This notice must be retained in all copies of this function, including modified versions! +# The MIT License can be found here: +# https://github.com/yunfachi/nypkgs/blob/master/LICENSE +{ lib, ... }: +{ + umport = + { + path ? null, + paths ? [ ], + include ? [ ], + exclude ? [ ], + recursive ? true, + }: + let + recursively = + let + inherit (lib.fileset) + unions + union + difference + fileFilter + toList + ; + nixOnly = paths: unions (map (fileFilter (file: file.hasExt "nix")) paths); + + pathsFs = nixOnly (paths ++ lib.optionals (path != null) [ path ]); + includeFs = nixOnly include; + excludeFs = nixOnly exclude; + + excluded = difference pathsFs excludeFs; + included = union excluded includeFs; + in + toList included; + + nonRecursively = + let + isNotExcluded = path: lib.all (x: !lib.path.hasPrefix x path) exclude; + readDirs = builtins.concatMap ( + path: map (x: path + "/${x}") (builtins.attrNames (builtins.readDir path)) + ); + + pathsList = readDirs (paths ++ lib.optionals (path != null) [ path ]); + includeList = readDirs include; + + excluded = lib.filter isNotExcluded pathsList; + included = lib.unique (excluded ++ includeList); + nixOnly = lib.filter (file: lib.pathIsDirectory file || lib.hasSuffix ".nix" file) included; + in + nixOnly; + in + if recursive then recursively else nonRecursively; +} From abdb26b7067d456f63a19f5751f5985ee1d7c10b Mon Sep 17 00:00:00 2001 From: yunfachi Date: Fri, 24 Oct 2025 10:51:42 +0300 Subject: [PATCH 08/21] lib/modules/default: add asserts --- lib/modules/default.nix | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/modules/default.nix b/lib/modules/default.nix index f2c9f68..ff7103c 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -96,6 +96,12 @@ delib._callLib ./helpers.nix host ? null, forEachHost ? false, }: + assert lib.assertMsg ( + forEachModuleSystem != (moduleSystem != null) + ) "'forEachModuleSystem' must be true or 'moduleSystem' must be set, but not both."; + assert lib.assertMsg ( + !(forEachHost && host != null) + ) "'forEachHost' must not be true when 'host' is set."; let genSingle = moduleSystem: host: @@ -131,11 +137,16 @@ delib._callLib ./helpers.nix host ? null, forEachHost ? false, }: + assert lib.assertMsg ( + forEachModuleSystem != (moduleSystem != null) + ) "'forEachModuleSystem' must be true or 'moduleSystem' must be set, but not both."; + assert lib.assertMsg ( + !(forEachHost && host != null) + ) "'forEachHost' must not be true when 'host' is set."; assert lib.assertMsg ( moduleSystem == null || configuration.config.moduleSystems.${moduleSystem}.makeSystem != null - ) "moduleSystem with name '${moduleSystem}' does not support makeSystem."; + ) "The selected module system '${moduleSystem}' does not support making systems."; let - genSingle = moduleSystem: host: configuration.config.moduleSystems.${moduleSystem}.makeSystem { From 087e4dfdadec3455c43fe9d4a0861c49d55aff04 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Fri, 24 Oct 2025 14:00:24 +0300 Subject: [PATCH 09/21] add wrappers --- examples/system/flake.nix | 2 ++ examples/system/host2.nix | 6 ++++++ examples/system/module2.nix | 10 ++++++++++ lib/default.nix | 2 ++ lib/modules/default.nix | 15 ++++++++------- lib/modules/wrappers.nix | 13 +++++++++++++ 6 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 examples/system/host2.nix create mode 100644 examples/system/module2.nix create mode 100644 lib/modules/wrappers.nix diff --git a/examples/system/flake.nix b/examples/system/flake.nix index 1e0d13f..c074601 100644 --- a/examples/system/flake.nix +++ b/examples/system/flake.nix @@ -18,7 +18,9 @@ denixConfiguration = delib.denixConfiguration { modules = [ ./module1.nix + ./module2.nix ./host1.nix + ./host2.nix ]; }; diff --git a/examples/system/host2.nix b/examples/system/host2.nix new file mode 100644 index 0000000..659afe0 --- /dev/null +++ b/examples/system/host2.nix @@ -0,0 +1,6 @@ +{ delib, ... }: +delib.host { + name = "host2"; + + nixos.ifEnabled.nixpkgs.hostPlatform = "x86_64-linux"; +} diff --git a/examples/system/module2.nix b/examples/system/module2.nix new file mode 100644 index 0000000..ab52ff6 --- /dev/null +++ b/examples/system/module2.nix @@ -0,0 +1,10 @@ +{ delib, ... }: +delib.module { + name = "programs.bash"; + options = { + enable = delib.boolOption false; + }; + + nixos.ifEnabled.programs.bash.enable = true; + nixos.ifDisabled.programs.bash.enable = false; +} diff --git a/lib/default.nix b/lib/default.nix index 32287a1..f8adb1e 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -31,6 +31,8 @@ mkLib "delib" (delib: { denixConfiguration genModule genSystem + module + host ; attrset = delib._callLib ./attrset.nix; diff --git a/lib/modules/default.nix b/lib/modules/default.nix index ff7103c..174dbea 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -6,7 +6,8 @@ nix-darwin, ... }: -delib._callLib ./helpers.nix +delib._callLib ./wrappers.nix +// delib._callLib ./helpers.nix // { denixConfiguration = { @@ -60,13 +61,13 @@ delib._callLib ./helpers.nix configuration, moduleSystem, host ? null, - }@args: + }: let - configuration = + configurationWithModules = if host == null then - args.configuration + configuration else - args.configuration.extendModules { + configuration.extendModules { modules = lib.singleton { config.host = host; }; @@ -80,11 +81,11 @@ delib._callLib ./helpers.nix moduleSystemName: rawModules: lib.concatMap ( value: - configuration.config.moduleSystems.${moduleSystemName}.applyConfigForModuleSystem { + configurationWithModules.config.moduleSystems.${moduleSystemName}.applyConfigForModuleSystem { inherit moduleSystem value; } ) rawModules - ) configuration.config.rawModules + ) configurationWithModules.config.rawModules ); }; diff --git a/lib/modules/wrappers.nix b/lib/modules/wrappers.nix new file mode 100644 index 0000000..7d864f5 --- /dev/null +++ b/lib/modules/wrappers.nix @@ -0,0 +1,13 @@ +{ + host = + { name, ... }@args: + { + config.hosts.${name} = builtins.removeAttrs args [ "name" ]; + }; + + module = + { name, ... }@args: + { + config.modules.${name} = builtins.removeAttrs args [ "name" ]; + }; +} From 0c066f51b509ff140305a327e8b4abb20e1fc14c Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 30 Oct 2025 16:50:09 +0300 Subject: [PATCH 10/21] lib/functions: init --- lib/default.nix | 9 +++++++++ lib/functions.nix | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 lib/functions.nix diff --git a/lib/default.nix b/lib/default.nix index f8adb1e..560c2b4 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -43,6 +43,15 @@ mkLib "delib" (delib: { keepAttrs ; + functions = delib._callLib ./functions.nix; + inherit (delib.functions) + functionArgs + setFunctionArgs + mirrorFunctionArgs + inheritFunctionArgs + callWithMocks + ; + options = delib._callLib ./options.nix; types = delib._callLib ./types.nix; diff --git a/lib/functions.nix b/lib/functions.nix new file mode 100644 index 0000000..00b3485 --- /dev/null +++ b/lib/functions.nix @@ -0,0 +1,40 @@ +{ delib, lib, ... }: +{ + functionArgs = + f: + if f ? __functor then + f.__functionArgs or (delib.functionArgs (f.__functor f)) + else + builtins.functionArgs f; + + setFunctionArgs = + f: args: + if lib.isAttrs f then + f + // { + __functionArgs = args; + } + else + { + __functor = self: f; + __functionArgs = args; + }; + + mirrorFunctionArgs = + f: + let + fArgs = delib.functionArgs f; + in + g: delib.setFunctionArgs g fArgs; + + # TODO: https://github.com/NixOS/nixpkgs/pull/453578 + inheritFunctionArgs = + f: g: + let + fArgs = delib.functionArgs f; + gArgs = delib.functionArgs g; + in + delib.setFunctionArgs g (fArgs // gArgs); + + callWithMocks = f: f (delib.functionArgs f); +} From 78d7127f11dbeec402550b1a2b7482f818647905 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 30 Oct 2025 16:51:28 +0300 Subject: [PATCH 11/21] lib/attrset/strictMergeAttrs: init --- lib/attrset.nix | 10 ++++++++++ lib/default.nix | 1 + 2 files changed, 11 insertions(+) diff --git a/lib/attrset.nix b/lib/attrset.nix index 5ab9269..e9c219c 100644 --- a/lib/attrset.nix +++ b/lib/attrset.nix @@ -14,4 +14,14 @@ keepAttrs = attrs: names: removeAttrs attrs (builtins.filter (name: !builtins.elem name names) (builtins.attrNames attrs)); + + strictMergeAttrs = + left: right: + let + conflicts = builtins.attrNames (builtins.intersectAttrs left right); + in + if conflicts != [ ] then + builtins.throw "strictMergeAttrs: conflicting keys: ${builtins.concatStringsSep ", " conflicts}" + else + left // right; } diff --git a/lib/default.nix b/lib/default.nix index 560c2b4..0cc6245 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -41,6 +41,7 @@ mkLib "delib" (delib: { setAttrByStrPath hasAttrs keepAttrs + strictMergeAttrs ; functions = delib._callLib ./functions.nix; From 5fa204d0dcd74a4ad05bf8bd9457f0d51f8914ff Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 30 Oct 2025 16:54:14 +0300 Subject: [PATCH 12/21] rework inputs --- flake.nix | 6 ++---- lib/default.nix | 6 ++---- lib/modules/config/moduleSystems/darwin.nix | 4 ++-- lib/modules/config/moduleSystems/home.nix | 4 ++-- lib/modules/config/moduleSystems/nixos.nix | 4 ++-- lib/modules/default.nix | 10 ++++++---- 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/flake.nix b/flake.nix index ece88a5..7e50937 100644 --- a/flake.nix +++ b/flake.nix @@ -27,10 +27,8 @@ { self, nixpkgs-lib, - git-hooks, nixpkgs, - home-manager, - nix-darwin, + git-hooks, ... }: let @@ -46,7 +44,7 @@ { lib = import ./lib { inherit (nixpkgs-lib) lib; - inherit home-manager nix-darwin nixpkgs; + inherit (self) inputs; }; checks = forAllSystems (system: { diff --git a/lib/default.nix b/lib/default.nix index 0cc6245..5bd3168 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,8 +1,6 @@ { lib, - nixpkgs, - home-manager, - nix-darwin, + inputs, ... }: let @@ -10,7 +8,7 @@ let in mkLib "delib" (delib: { _callLibArgs = { - inherit nixpkgs home-manager nix-darwin; + inherit inputs; }; fixedPoints = delib._callLib ./toplevel/fixed-points.nix; diff --git a/lib/modules/config/moduleSystems/darwin.nix b/lib/modules/config/moduleSystems/darwin.nix index 292ab6a..0e2dd71 100644 --- a/lib/modules/config/moduleSystems/darwin.nix +++ b/lib/modules/config/moduleSystems/darwin.nix @@ -1,9 +1,9 @@ -{ nix-darwin, ... }: +{ inputs, ... }: { moduleSystems.darwin = { makeSystem = { modules, extraArgs, ... }: - nix-darwin.lib.darwinSystem ( + inputs.nix-darwin.lib.darwinSystem ( { inherit modules; } diff --git a/lib/modules/config/moduleSystems/home.nix b/lib/modules/config/moduleSystems/home.nix index 77993c0..ec98760 100644 --- a/lib/modules/config/moduleSystems/home.nix +++ b/lib/modules/config/moduleSystems/home.nix @@ -1,9 +1,9 @@ -{ home-manager, ... }: +{ inputs, ... }: { moduleSystems.home = { makeSystem = { modules, extraArgs, ... }: - home-manager.lib.homeManagerConfiguration ( + inputs.home-manager.lib.homeManagerConfiguration ( { inherit modules; } diff --git a/lib/modules/config/moduleSystems/nixos.nix b/lib/modules/config/moduleSystems/nixos.nix index 723dafb..921a9e3 100644 --- a/lib/modules/config/moduleSystems/nixos.nix +++ b/lib/modules/config/moduleSystems/nixos.nix @@ -1,9 +1,9 @@ -{ nixpkgs, ... }: +{ inputs, ... }: { moduleSystems.nixos = { makeSystem = { modules, extraArgs, ... }: - nixpkgs.lib.nixosSystem ( + inputs.nixpkgs.lib.nixosSystem ( { inherit modules; } diff --git a/lib/modules/default.nix b/lib/modules/default.nix index 174dbea..ad81d8b 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -1,11 +1,12 @@ { delib, lib, - nixpkgs, - home-manager, - nix-darwin, + inputs, ... }: +let + denixInputs = inputs; +in delib._callLib ./wrappers.nix // delib._callLib ./helpers.nix // { @@ -13,13 +14,14 @@ delib._callLib ./wrappers.nix { modules ? [ ], specialArgs ? { }, + inputs ? { }, }: let evaledModules = lib.evalModules { modules = [ ./config/denix.nix ] ++ modules; specialArgs = { - inherit nixpkgs home-manager nix-darwin; + inputs = denixInputs // inputs; # `specialArgs.modulesPath` is used as the base path for `disabledModules`. modulesPath = ./config; } From 618edb72e047148835b26656baa892fcd1b6c300 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 30 Oct 2025 16:54:33 +0300 Subject: [PATCH 13/21] lib/modules/wrappers: fix for lambdas --- lib/modules/wrappers.nix | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/modules/wrappers.nix b/lib/modules/wrappers.nix index 7d864f5..d2063ff 100644 --- a/lib/modules/wrappers.nix +++ b/lib/modules/wrappers.nix @@ -1,13 +1,19 @@ +{ delib, lib, ... }: +let + mkWrapper = + field: obj: + if lib.isFunction obj then + { + config.${field}.${(delib.callWithMocks obj).name} = builtins.trace (lib.functionArgs obj) ( + lib.mirrorFunctionArgs obj (args: builtins.removeAttrs (obj args) [ "name" ]) + ); + } + else + { + config.${field}.${obj.name} = builtins.removeAttrs obj [ "name" ]; + }; +in { - host = - { name, ... }@args: - { - config.hosts.${name} = builtins.removeAttrs args [ "name" ]; - }; - - module = - { name, ... }@args: - { - config.modules.${name} = builtins.removeAttrs args [ "name" ]; - }; + module = mkWrapper "modules"; + host = mkWrapper "hosts"; } From 039a1946f38ea01a339a3dc16ae7f9b7dd169f0a Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 30 Oct 2025 16:59:08 +0300 Subject: [PATCH 14/21] rework modules --- lib/default.nix | 5 ++ lib/modules/config/moduleSystems/default.nix | 14 ++-- lib/modules/config/moduleSystems/myconfig.nix | 5 +- lib/modules/config/moduleSystems/options.nix | 5 +- lib/modules/default.nix | 82 ++++++++++++------- lib/modules/helpers.nix | 46 +++++++---- 6 files changed, 100 insertions(+), 57 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index 5bd3168..ba7f61e 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -28,9 +28,14 @@ mkLib "delib" (delib: { inherit (delib.modules) denixConfiguration genModule + genModules genSystem + genSystems module host + toDenixArgs + isDenixArgs + callIfDenixArgs ; attrset = delib._callLib ./attrset.nix; diff --git a/lib/modules/config/moduleSystems/default.nix b/lib/modules/config/moduleSystems/default.nix index 5618592..6ea73f9 100644 --- a/lib/modules/config/moduleSystems/default.nix +++ b/lib/modules/config/moduleSystems/default.nix @@ -14,6 +14,13 @@ ]; options = with delib; { + moduleSystem = allowNull ( + coercedToOption (enum (builtins.attrNames config.moduleSystems)) ( + moduleSystemName: + if moduleSystemName == null then null else config.moduleSystems.${moduleSystemName} + ) (enum (builtins.attrValues config.moduleSystems)) null + ); + moduleSystems = lazyAttrsOfOption (submoduleWith { modules = [ ( @@ -21,17 +28,14 @@ { options = { name = readOnly (strOption name); + __toString = readOnly (functionToOption str (self: self.name)); myconfigPrefix = allowNull (strOption config.myconfigPrefix); makeSystem = allowNull (functionOption null); applyConfigForModuleSystem = functionToOption list ( - { - moduleSystem, - value, - }: - lib.optional (moduleSystem == name) value + value: lib.optional (config.moduleSystem == name) value ); }; } diff --git a/lib/modules/config/moduleSystems/myconfig.nix b/lib/modules/config/moduleSystems/myconfig.nix index c8b4ff4..5798596 100644 --- a/lib/modules/config/moduleSystems/myconfig.nix +++ b/lib/modules/config/moduleSystems/myconfig.nix @@ -4,10 +4,7 @@ { name, config, ... }: { applyConfigForModuleSystem = - { - moduleSystem, - value, - }: + value: let addPrefixToModule = delib.modules.addPrefixToModule (lib.splitString "." config.myconfigPrefix); in diff --git a/lib/modules/config/moduleSystems/options.nix b/lib/modules/config/moduleSystems/options.nix index baf7f79..20ad4af 100644 --- a/lib/modules/config/moduleSystems/options.nix +++ b/lib/modules/config/moduleSystems/options.nix @@ -4,10 +4,7 @@ { name, config, ... }: { applyConfigForModuleSystem = - { - moduleSystem, - value, - }: + value: let addPrefixToModule = delib.modules.addPrefixToModule (lib.splitString "." config.myconfigPrefix); in diff --git a/lib/modules/default.nix b/lib/modules/default.nix index ad81d8b..8501af8 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -58,42 +58,39 @@ delib._callLib ./wrappers.nix in withExtraAttrs evaledModules; - genModule' = + genModule = { configuration, + moduleSystem, host ? null, }: let - configurationWithModules = - if host == null then - configuration - else - configuration.extendModules { - modules = lib.singleton { - config.host = host; - }; + configurationWithModules = configuration.extendModules { + modules = lib.singleton { + config = { + inherit moduleSystem host; }; + }; + }; in { - key = "denix.genModule { moduleSystem = ${moduleSystem}; }"; + key = "denix.genModule"; imports = lib.concatLists ( lib.mapAttrsToList ( moduleSystemName: rawModules: - lib.concatMap ( - value: - configurationWithModules.config.moduleSystems.${moduleSystemName}.applyConfigForModuleSystem { - inherit moduleSystem value; - } - ) rawModules + lib.concatMap + configurationWithModules.config.moduleSystems.${moduleSystemName}.applyConfigForModuleSystem + rawModules ) configurationWithModules.config.rawModules ); }; - genModule = + genModules = { configuration, + moduleSystem ? null, forEachModuleSystem ? false, host ? null, @@ -108,7 +105,7 @@ delib._callLib ./wrappers.nix let genSingle = moduleSystem: host: - delib.modules.genModule' { + delib.modules.genModule { inherit configuration moduleSystem @@ -134,7 +131,37 @@ delib._callLib ./wrappers.nix genSystem = { configuration, + + extraArgs ? { }, + extraModules ? [ ], + + moduleSystem ? null, + host ? null, + }: + configuration.config.moduleSystems.${moduleSystem}.makeSystem { + inherit extraArgs; + modules = + lib.singleton ( + delib.modules.genModule { + inherit + configuration + moduleSystem + host + ; + } + ) + ++ extraModules; + }; + + genSystems = + { + configuration, + extraArgs ? { }, + extraArgsByModuleSystem ? { }, + extraModules ? [ ], + extraModulesByModuleSystem ? { }, + moduleSystem ? null, forEachModuleSystem ? false, host ? null, @@ -152,17 +179,14 @@ delib._callLib ./wrappers.nix let genSingle = moduleSystem: host: - configuration.config.moduleSystems.${moduleSystem}.makeSystem { - inherit extraArgs; - modules = lib.singleton ( - delib.modules.genModule' { - inherit - configuration - moduleSystem - host - ; - } - ); + delib.modules.genSystem { + inherit + configuration + moduleSystem + host + ; + extraArgs = extraArgs // extraArgsByModuleSystem.${moduleSystem} or { }; + extraModules = extraModules ++ extraModulesByModuleSystem.${moduleSystem} or [ ]; }; processHosts = diff --git a/lib/modules/helpers.nix b/lib/modules/helpers.nix index 33aa5d8..588d06e 100644 --- a/lib/modules/helpers.nix +++ b/lib/modules/helpers.nix @@ -1,5 +1,20 @@ { delib, lib, ... }: { + toDenixArgs = + function: + if !delib.isDenixArgs function then + { + _type = "denixAbstractionArgsFunctor"; + __functor = self: function; + __functionArgs = builtins.trace (delib.functionArgs function) (delib.functionArgs function); + } + else + function; + + isDenixArgs = x: x._type or null == "denixAbstractionArgsFunctor"; + + callIfDenixArgs = x: args: if delib.isDenixArgs x then x args else x; + addPrefixToModule = prefix: m: let @@ -59,43 +74,44 @@ { moduleSystems, extraOptions ? name: { }, - fakeCall ? module: module { }, - toFunctor, }: with delib; coercedTo (either (functionTo attrs) attrs) (module: { config = - if (!lib.isFunction module) then + if !lib.isFunction module then module else let - called = fakeCall module; + calledWithMocks = delib.callWithMocks module; - definedModuleSystems = lib.intersectLists (builtins.attrNames called) ( + definedModuleSystems = lib.intersectLists (builtins.attrNames calledWithMocks) ( builtins.attrNames moduleSystems ); - addDenixModuleArgsFunctor = + eachToDenixArgs = fn: - if builtins.isList (fn called) then - lib.imap0 (index: value: toFunctor (args: builtins.elemAt (fn (module args)) index)) (fn called) + if builtins.isList (fn calledWithMocks) then + lib.imap0 ( + index: value: + delib.toDenixArgs (delib.mirrorFunctionArgs module (args: builtins.elemAt (fn (module args)) index)) + ) (fn calledWithMocks) else - toFunctor (args: fn (module args)); + delib.toDenixArgs (delib.mirrorFunctionArgs module (args: fn (module args))); in - called + calledWithMocks // lib.genAttrs definedModuleSystems ( moduleSystem: - called.${moduleSystem} - // lib.genAttrs (lib.intersectLists (builtins.attrNames called.${moduleSystem}) [ + calledWithMocks.${moduleSystem} + // lib.genAttrs (lib.intersectLists (builtins.attrNames calledWithMocks.${moduleSystem}) [ "always" "ifEnabled" "ifDisabled" - ]) (condition: addDenixModuleArgsFunctor (x: x.${moduleSystem}.${condition})) + ]) (condition: eachToDenixArgs (x: x.${moduleSystem}.${condition})) ) - // lib.optionalAttrs (called ? options) { - options = addDenixModuleArgsFunctor (x: x.options); + // lib.optionalAttrs (calledWithMocks ? options) { + options = eachToDenixArgs (x: x.options); }; }) (submoduleWith { From 39e7d741a3e25b8b7e019b61a178decdb2466b64 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Thu, 30 Oct 2025 16:59:34 +0300 Subject: [PATCH 15/21] abstractions: use shared functions --- lib/modules/config/abstractions/hosts.nix | 56 +++------------ lib/modules/config/abstractions/modules.nix | 77 ++++++--------------- 2 files changed, 29 insertions(+), 104 deletions(-) diff --git a/lib/modules/config/abstractions/hosts.nix b/lib/modules/config/abstractions/hosts.nix index f6e880d..5822049 100644 --- a/lib/modules/config/abstractions/hosts.nix +++ b/lib/modules/config/abstractions/hosts.nix @@ -5,50 +5,24 @@ ... }: let - toDenixHostArgsFunctor = functor: { - _type = "denixHostArgsFunctor"; - __functor = - self: - { - name, - }@args: - functor args; - }; - - isDenixHostArgsFunctor = x: x._type or null == "denixHostArgsFunctor"; - - callDenixHostArgsFunctor = x: args: if isDenixHostArgsFunctor x then x args else x; - - inheritFunctionArgs = - f: g: - let - fArgs = lib.functionArgs f; - gArgs = lib.functionArgs g; - in - lib.setFunctionArgs g (fArgs // gArgs); - mapItem = hostName: moduleSystemName: myconfigPrefix: pathSuffix: contentFn: index: entry: let + #myconfigPrefixWithDot = lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; keyAttrs.key = "denix.hosts.'${hostName}'.'${moduleSystemName}'${pathSuffix}-${toString index}"; in if !lib.isFunction entry && !lib.isFunction (contentFn entry) then - keyAttrs // (contentFn entry) + keyAttrs // contentFn entry else - let - fakeCalled = callDenixHostArgsFunctor entry { - name = hostName; - }; - in - inheritFunctionArgs (lib.toFunction fakeCalled) ( + delib.inheritFunctionArgs (lib.toFunction (delib.callWithMocks (lib.toFunction entry))) ( { config, options, ... }@args: let - called = callDenixHostArgsFunctor entry { + called = delib.callIfDenixArgs entry { name = hostName; }; calledFn = (lib.toFunction called) args; in - keyAttrs // calledFn + keyAttrs // contentFn calledFn ); in { @@ -61,25 +35,11 @@ in hosts = attrsOfOption (delib.modules.denixModuleType { moduleSystems = builtins.removeAttrs config.moduleSystems [ "options" ]; - fakeCall = - host: - lib.fix ( - self: - host { - inherit (self) name; - } - ); - toFunctor = toDenixHostArgsFunctor; }) { }; }; config.rawModules = lib.mapAttrs ( moduleSystemName: moduleSystem: - let - myconfigPrefix = lib.optionalString ( - moduleSystem.myconfigPrefix != null - ) "${moduleSystem.myconfigPrefix}."; - in lib.concatLists ( lib.mapAttrsToList ( hostName: host: @@ -88,13 +48,13 @@ in contentIfEnabled = entry: if config.host.name or null == hostName then entry else { }; contentIfDisabled = entry: if config.host.name or null != hostName then entry else { }; in - lib.imap1 (mapItem hostName moduleSystemName myconfigPrefix ".always" + lib.imap1 (mapItem hostName moduleSystemName moduleSystem.myconfigPrefix ".always" contentAlways ) host.${moduleSystemName}.always - ++ lib.imap1 (mapItem hostName moduleSystemName myconfigPrefix ".ifEnabled" + ++ lib.imap1 (mapItem hostName moduleSystemName moduleSystem.myconfigPrefix ".ifEnabled" contentIfEnabled ) host.${moduleSystemName}.ifEnabled - ++ lib.imap1 (mapItem hostName moduleSystemName myconfigPrefix ".ifDisabled" + ++ lib.imap1 (mapItem hostName moduleSystemName moduleSystem.myconfigPrefix ".ifDisabled" contentIfDisabled ) host.${moduleSystemName}.ifDisabled ) config.hosts diff --git a/lib/modules/config/abstractions/modules.nix b/lib/modules/config/abstractions/modules.nix index b9f9436..50cd368 100644 --- a/lib/modules/config/abstractions/modules.nix +++ b/lib/modules/config/abstractions/modules.nix @@ -5,81 +5,42 @@ ... }: let - toDenixModuleArgsFunctor = functor: { - _type = "denixModuleArgsFunctor"; - __functor = - self: - { - name, - cfg, - opt, - }@args: - functor args; - }; - - isDenixModuleArgsFunctor = x: x._type or null == "denixModuleArgsFunctor"; - - callDenixModuleArgsFunctor = x: args: if isDenixModuleArgsFunctor x then x args else x; - - inheritFunctionArgs = - f: g: - let - fArgs = lib.functionArgs f; - gArgs = lib.functionArgs g; - in - lib.setFunctionArgs g (fArgs // gArgs); - mapItem = moduleName: moduleSystemName: myconfigPrefix: pathSuffix: contentFn: index: entry: let + myconfigPrefixWithDot = lib.optionalString (myconfigPrefix != null) "${myconfigPrefix}."; keyAttrs.key = "denix.modules.'${moduleName}'.'${moduleSystemName}'${pathSuffix}-${toString index}"; in if !lib.isFunction entry && !lib.isFunction (contentFn entry) then - keyAttrs // (contentFn entry) + keyAttrs // contentFn entry else - let - fakeCalled = callDenixModuleArgsFunctor entry { - name = moduleName; - cfg = { }; - opt = { }; - }; - in - inheritFunctionArgs (lib.toFunction fakeCalled) ( + delib.inheritFunctionArgs (lib.toFunction (delib.callWithMocks (lib.toFunction entry))) ( { config, options, ... }@args: let - called = callDenixModuleArgsFunctor entry { + called = delib.callIfDenixArgs entry { name = moduleName; - cfg = delib.getAttrByStrPath config "${myconfigPrefix}${moduleName}" { }; - opt = delib.getAttrByStrPath options "${myconfigPrefix}${moduleName}" { }; + myconfig = delib.getAttrByStrPath config myconfigPrefix { }; + myoptions = delib.getAttrByStrPath options myconfigPrefix { }; + cfg = delib.getAttrByStrPath config "${myconfigPrefixWithDot}${moduleName}" { }; + opt = delib.getAttrByStrPath options "${myconfigPrefixWithDot}${moduleName}" { }; }; calledFn = (lib.toFunction called) args; withOptionalConfig = lib.toFunction calledFn; in - keyAttrs // (withOptionalConfig config) + keyAttrs // (lib.toFunction (contentFn (withOptionalConfig config))) config ); in { options = with delib; { modules = attrsOfOption (delib.modules.denixModuleType { moduleSystems = config.moduleSystems; - fakeCall = - module: - lib.fix ( - self: - module { - inherit (self) name; - cfg = { }; - opt = { }; - } - ); - toFunctor = toDenixModuleArgsFunctor; }) { }; }; config.rawModules = lib.mapAttrs ( moduleSystemName: moduleSystem: let - myconfigPrefix = lib.optionalString ( + myconfigPrefixWithDot = lib.optionalString ( moduleSystem.myconfigPrefix != null ) "${moduleSystem.myconfigPrefix}."; in @@ -87,26 +48,30 @@ in lib.mapAttrsToList ( moduleName: module: let - contentOptions = entry: { options = delib.setAttrByStrPath entry moduleName; }; + contentOptions = entry: { + options = delib.setAttrByStrPath entry moduleName; + }; contentAlways = entry: entry; contentIfEnabled = entry: config: - lib.mkIf (delib.getAttrByStrPath config "${myconfigPrefix}${moduleName}.enable" false) entry; + lib.mkIf (delib.getAttrByStrPath config "${myconfigPrefixWithDot}${moduleName}.enable" false) entry; contentIfDisabled = entry: config: - lib.mkIf (!(delib.getAttrByStrPath config "${myconfigPrefix}${moduleName}.enable" true)) entry; + lib.mkIf (!delib.getAttrByStrPath config "${myconfigPrefixWithDot}${moduleName}.enable" true) entry; in if moduleSystemName == "options" then - lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix "" contentOptions) module.options + lib.imap1 (mapItem moduleName moduleSystemName moduleSystem.myconfigPrefix "" + contentOptions + ) module.options else - lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix ".always" + lib.imap1 (mapItem moduleName moduleSystemName moduleSystem.myconfigPrefix ".always" contentAlways ) module.${moduleSystemName}.always - ++ lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix ".ifEnabled" + ++ lib.imap1 (mapItem moduleName moduleSystemName moduleSystem.myconfigPrefix ".ifEnabled" contentIfEnabled ) module.${moduleSystemName}.ifEnabled - ++ lib.imap1 (mapItem moduleName moduleSystemName myconfigPrefix ".ifDisabled" + ++ lib.imap1 (mapItem moduleName moduleSystemName moduleSystem.myconfigPrefix ".ifDisabled" contentIfDisabled ) module.${moduleSystemName}.ifDisabled ) config.modules From cdf81b1dd667eca93d96a4f7d4348af41cc00a4a Mon Sep 17 00:00:00 2001 From: yunfachi Date: Tue, 4 Nov 2025 14:52:58 +0300 Subject: [PATCH 16/21] abstractions: add extraHostSubmodules, extraModuleSubmodules and fix logic --- lib/default.nix | 1 + lib/modules/config/abstractions/hosts.nix | 11 +++++++---- lib/modules/config/abstractions/modules.nix | 12 +++++++----- lib/modules/helpers.nix | 9 +++++---- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/lib/default.nix b/lib/default.nix index ba7f61e..199fc87 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -36,6 +36,7 @@ mkLib "delib" (delib: { toDenixArgs isDenixArgs callIfDenixArgs + callWithMocksIfDenixArgs ; attrset = delib._callLib ./attrset.nix; diff --git a/lib/modules/config/abstractions/hosts.nix b/lib/modules/config/abstractions/hosts.nix index 5822049..8430563 100644 --- a/lib/modules/config/abstractions/hosts.nix +++ b/lib/modules/config/abstractions/hosts.nix @@ -14,15 +14,15 @@ let if !lib.isFunction entry && !lib.isFunction (contentFn entry) then keyAttrs // contentFn entry else - delib.inheritFunctionArgs (lib.toFunction (delib.callWithMocks (lib.toFunction entry))) ( + delib.inheritFunctionArgs (lib.toFunction (delib.callWithMocksIfDenixArgs entry)) ( { config, options, ... }@args: let - called = delib.callIfDenixArgs entry { + calledWithDenixArgs = delib.callIfDenixArgs entry { name = hostName; }; - calledFn = (lib.toFunction called) args; + result = lib.toFunction calledWithDenixArgs args; in - keyAttrs // contentFn calledFn + keyAttrs // lib.toFunction (lib.toFunction contentFn result) config ); in { @@ -33,8 +33,11 @@ in ) (enum (builtins.attrValues config.hosts)) null ); + extraHostSubmodules = listOption [ ]; + hosts = attrsOfOption (delib.modules.denixModuleType { moduleSystems = builtins.removeAttrs config.moduleSystems [ "options" ]; + extraModules = config.extraHostSubmodules; }) { }; }; diff --git a/lib/modules/config/abstractions/modules.nix b/lib/modules/config/abstractions/modules.nix index 50cd368..e834d3c 100644 --- a/lib/modules/config/abstractions/modules.nix +++ b/lib/modules/config/abstractions/modules.nix @@ -14,26 +14,28 @@ let if !lib.isFunction entry && !lib.isFunction (contentFn entry) then keyAttrs // contentFn entry else - delib.inheritFunctionArgs (lib.toFunction (delib.callWithMocks (lib.toFunction entry))) ( + delib.inheritFunctionArgs (lib.toFunction (delib.callWithMocksIfDenixArgs entry)) ( { config, options, ... }@args: let - called = delib.callIfDenixArgs entry { + calledWithDenixArgs = delib.callIfDenixArgs entry { name = moduleName; myconfig = delib.getAttrByStrPath config myconfigPrefix { }; myoptions = delib.getAttrByStrPath options myconfigPrefix { }; cfg = delib.getAttrByStrPath config "${myconfigPrefixWithDot}${moduleName}" { }; opt = delib.getAttrByStrPath options "${myconfigPrefixWithDot}${moduleName}" { }; }; - calledFn = (lib.toFunction called) args; - withOptionalConfig = lib.toFunction calledFn; + result = lib.toFunction called args; in - keyAttrs // (lib.toFunction (contentFn (withOptionalConfig config))) config + keyAttrs // lib.toFunction (lib.toFunction contentFn result) config ); in { options = with delib; { + extraModuleSubmodules = listOption [ ]; + modules = attrsOfOption (delib.modules.denixModuleType { moduleSystems = config.moduleSystems; + extraModules = config.extraModuleSubmodules; }) { }; }; diff --git a/lib/modules/helpers.nix b/lib/modules/helpers.nix index 588d06e..c71e716 100644 --- a/lib/modules/helpers.nix +++ b/lib/modules/helpers.nix @@ -15,6 +15,8 @@ callIfDenixArgs = x: args: if delib.isDenixArgs x then x args else x; + callWithMocksIfDenixArgs = x: if delib.isDenixArgs x then delib.callWithMocks x else x; + addPrefixToModule = prefix: m: let @@ -73,7 +75,7 @@ denixModuleType = { moduleSystems, - extraOptions ? name: { }, + extraModules ? [ ], }: with delib; coercedTo (either (functionTo attrs) attrs) @@ -115,7 +117,7 @@ }; }) (submoduleWith { - modules = [ + modules = extraModules ++ [ ( { name, ... }: { @@ -131,8 +133,7 @@ // { name = readOnly (strOption name); __toString = readOnly (functionToOption str (self: self.name)); - } - // extraOptions name; + }; } ) ]; From 8c5bbceb72a009fef6a7b0f42379d76e0aeb6cce Mon Sep 17 00:00:00 2001 From: yunfachi Date: Tue, 4 Nov 2025 14:54:32 +0300 Subject: [PATCH 17/21] moduleSystems/options: fix args and addPrefixToModule --- lib/modules/config/moduleSystems/options.nix | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/modules/config/moduleSystems/options.nix b/lib/modules/config/moduleSystems/options.nix index 20ad4af..be1e665 100644 --- a/lib/modules/config/moduleSystems/options.nix +++ b/lib/modules/config/moduleSystems/options.nix @@ -6,10 +6,19 @@ applyConfigForModuleSystem = value: let - addPrefixToModule = delib.modules.addPrefixToModule (lib.splitString "." config.myconfigPrefix); + addPrefixToModule = + if config.myconfigPrefix != null then + delib.modules.addPrefixToModule (lib.splitString "." config.myconfigPrefix) + else + lib.id; in [ - (if lib.isFunction value then args: addPrefixToModule (value args) else addPrefixToModule value) + ( + if lib.isFunction value then + delib.mirrorFunctionArgs value (args: addPrefixToModule (value args)) + else + addPrefixToModule value + ) ]; }; } From 5c654d8566e9d4ae8fdae348bbe41057350aa350 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Tue, 4 Nov 2025 14:56:18 +0300 Subject: [PATCH 18/21] moduleSystems/default: fix config usage --- lib/modules/config/moduleSystems/default.nix | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/modules/config/moduleSystems/default.nix b/lib/modules/config/moduleSystems/default.nix index 6ea73f9..ee861c0 100644 --- a/lib/modules/config/moduleSystems/default.nix +++ b/lib/modules/config/moduleSystems/default.nix @@ -3,7 +3,10 @@ lib, config, ... -}: +}: let + defaultMyconfigPrefix = config.myconfigPrefix; + selectedModuleSystem = config.moduleSystem; +in { imports = [ ./darwin.nix @@ -30,12 +33,12 @@ name = readOnly (strOption name); __toString = readOnly (functionToOption str (self: self.name)); - myconfigPrefix = allowNull (strOption config.myconfigPrefix); + myconfigPrefix = allowNull (strOption defaultMyconfigPrefix); makeSystem = allowNull (functionOption null); applyConfigForModuleSystem = functionToOption list ( - value: lib.optional (config.moduleSystem == name) value + value: lib.optional (selectedModuleSystem.name == config.name) value ); }; } From 33e68809e6abfd18f10821ddd7bdcabbe7bd1a40 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Tue, 4 Nov 2025 14:58:12 +0300 Subject: [PATCH 19/21] lib/modules/default/genModule: make moduleSystem optional --- lib/modules/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/default.nix b/lib/modules/default.nix index 8501af8..c013bcc 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -62,7 +62,7 @@ delib._callLib ./wrappers.nix { configuration, - moduleSystem, + moduleSystem ? null, host ? null, }: let From 47bc71b81eda443db6a89b88104eac32d52e9056 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Tue, 4 Nov 2025 15:40:07 +0300 Subject: [PATCH 20/21] lib/modules/default: rework --- lib/modules/default.nix | 114 +++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 49 deletions(-) diff --git a/lib/modules/default.nix b/lib/modules/default.nix index c013bcc..d11f282 100644 --- a/lib/modules/default.nix +++ b/lib/modules/default.nix @@ -87,14 +87,47 @@ delib._callLib ./wrappers.nix ); }; + genSystem = + { + configuration, + + moduleSystem, + host ? null, + + extraArgs ? { }, + extraModules ? [ ], + }: + let + makeSystem = configuration.config.moduleSystems.${moduleSystem}.makeSystem; + in + assert lib.assertMsg (makeSystem != null) + "The selected module system '${moduleSystem}' does not support making systems. See its 'makeSystem' option."; + makeSystem { + inherit extraArgs; + modules = extraModules ++ [ + (delib.modules.genModule { + inherit + configuration + moduleSystem + host + ; + }) + ]; + }; + genModules = { configuration, moduleSystem ? null, - forEachModuleSystem ? false, host ? null, + + forEachModuleSystem ? false, + moduleSystems ? builtins.attrNames ( + lib.filterAttrs (_: value: value.flakeOutputs.modules != null) configuration.config.moduleSystems + ), forEachHost ? false, + hosts ? builtins.attrNames configuration.config.hosts, }: assert lib.assertMsg ( forEachModuleSystem != (moduleSystem != null) @@ -113,59 +146,47 @@ delib._callLib ./wrappers.nix ; }; - processHosts = - moduleSystem: - if forEachHost then - builtins.mapAttrs (host: _: genSingle moduleSystem host) configuration.config.hosts - else - genSingle moduleSystem host; - processModuleSystems = if forEachModuleSystem then - builtins.mapAttrs (moduleSystem: _: processHosts moduleSystem) configuration.config.moduleSystems + lib.genAttrs' (moduleSystem: { + name = + let + flakeOutput = configuration.config.moduleSystems.${moduleSystem}.flakeOutputs.modules; + in + lib.throwIf (flakeOutput == null) + "The selected module system '${moduleSystem}' option 'flakeOutputs.modules' cannot be null." + flakeOutput; + value = processHosts moduleSystem; + }) moduleSystems else processHosts moduleSystem; + + processHosts = + moduleSystem: + if forEachHost then lib.genAttrs (genSingle moduleSystem) hosts else genSingle moduleSystem host; in processModuleSystems; - genSystem = + genSystems = { configuration, - extraArgs ? { }, - extraModules ? [ ], - moduleSystem ? null, host ? null, - }: - configuration.config.moduleSystems.${moduleSystem}.makeSystem { - inherit extraArgs; - modules = - lib.singleton ( - delib.modules.genModule { - inherit - configuration - moduleSystem - host - ; - } - ) - ++ extraModules; - }; - genSystems = - { - configuration, + forEachModuleSystem ? false, + moduleSystems ? builtins.attrNames ( + lib.filterAttrs ( + _: value: value.flakeOutputs.systems != null && value.makeSystem != null + ) configuration.config.moduleSystems + ), + forEachHost ? false, + hosts ? builtins.attrNames configuration.config.hosts, extraArgs ? { }, extraArgsByModuleSystem ? { }, extraModules ? [ ], extraModulesByModuleSystem ? { }, - - moduleSystem ? null, - forEachModuleSystem ? false, - host ? null, - forEachHost ? false, }: assert lib.assertMsg ( forEachModuleSystem != (moduleSystem != null) @@ -173,9 +194,6 @@ delib._callLib ./wrappers.nix assert lib.assertMsg ( !(forEachHost && host != null) ) "'forEachHost' must not be true when 'host' is set."; - assert lib.assertMsg ( - moduleSystem == null || configuration.config.moduleSystems.${moduleSystem}.makeSystem != null - ) "The selected module system '${moduleSystem}' does not support making systems."; let genSingle = moduleSystem: host: @@ -189,20 +207,18 @@ delib._callLib ./wrappers.nix extraModules = extraModules ++ extraModulesByModuleSystem.${moduleSystem} or [ ]; }; - processHosts = - moduleSystem: - if forEachHost then - builtins.mapAttrs (host: _: genSingle moduleSystem host) configuration.config.hosts - else - genSingle moduleSystem host; - processModuleSystems = if forEachModuleSystem then - builtins.mapAttrs (moduleSystem: _: processHosts moduleSystem) ( - lib.filterAttrs (name: value: value.makeSystem != null) configuration.config.moduleSystems - ) + lib.genAttrs' (moduleSystem: { + name = moduleSystem.flakeOutputs.systems; + value = processHosts moduleSystem; + }) moduleSystems else processHosts moduleSystem; + + processHosts = + moduleSystem: + if forEachHost then lib.genAttrs (genSingle moduleSystem) hosts else genSingle moduleSystem host; in processModuleSystems; } From 5947fa087db5962c09a77bc205379674903b7093 Mon Sep 17 00:00:00 2001 From: yunfachi Date: Tue, 4 Nov 2025 16:41:16 +0300 Subject: [PATCH 21/21] abstractions modules fix typo --- lib/modules/config/abstractions/modules.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/config/abstractions/modules.nix b/lib/modules/config/abstractions/modules.nix index e834d3c..ecfab93 100644 --- a/lib/modules/config/abstractions/modules.nix +++ b/lib/modules/config/abstractions/modules.nix @@ -24,7 +24,7 @@ let cfg = delib.getAttrByStrPath config "${myconfigPrefixWithDot}${moduleName}" { }; opt = delib.getAttrByStrPath options "${myconfigPrefixWithDot}${moduleName}" { }; }; - result = lib.toFunction called args; + result = lib.toFunction calledWithDenixArgs args; in keyAttrs // lib.toFunction (lib.toFunction contentFn result) config );