Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ den.oeiuwq.com
configurations den dendritic nix aspect oriented

exercise namespaces and angle-brackets in default template. (#79)

split into several files, more dendritic.

authored by oeiuwq.com and committed by

GitHub 594ba47c 19e00ef7

+237 -201
+2 -1
nix/den-brackets.nix
··· 27 27 readFromAspects = lib.getAttrFromPath path config.den.aspects; 28 28 29 29 headIsDenful = lib.hasAttrByPath [ "ful" head ] config.den; 30 - readFromDenful = lib.getAttrFromPath tail config.den.ful; 30 + denfulTail = if lib.head tail == "provides" then lib.tail tail else tail; 31 + readFromDenful = lib.getAttrFromPath ([ head ] ++ denfulTail) config.den.ful; 31 32 32 33 found = 33 34 if headIsDen then
+35
templates/default/README.md
··· 1 + # Getting Started Guide 2 + 3 + Steps you can follow after cloning this template: 4 + 5 + - Be sure to read the [den documentation](https://vic.github.io/den) 6 + 7 + - Update den input. 8 + 9 + ```console 10 + nix flake update den 11 + ``` 12 + 13 + - Run checks to test everything works. 14 + 15 + ```console 16 + nix flake check 17 + ``` 18 + 19 + - Read [modules/den.nix](modules/den.nix) where hosts and homes definitions are for this example. 20 + 21 + - Read [modules/namespace.nix](modules/namespace.nix) where a new `eg` (an example) aspects namespace is created. 22 + 23 + - Read [modules/aspects/igloo.nix](modules/aspects/igloo.nix) where the `igloo` host is configured. 24 + 25 + - Read [modules/aspects/alice.nix](modules/aspects/alice.nix) where the `alice` user is configured. 26 + 27 + - Run the VM. 28 + 29 + ```console 30 + nix run .#vm 31 + ``` 32 + 33 + - Edit and run VM loop. 34 + 35 + Feel free to add more aspects, organize things to your liking.
+29
templates/default/modules/aspects/alice.nix
··· 1 + { den, eg, ... }: 2 + { 3 + den.aspects.alice = { 4 + # You can include other aspects, in this case some 5 + # den included batteries that provide common configs. 6 + includes = [ 7 + eg.autologin 8 + den.provides.primary-user # alice is admin always. 9 + (den.provides.user-shell "fish") # default user shell 10 + ]; 11 + 12 + # Alice configures NixOS hosts it lives on. 13 + nixos = 14 + { pkgs, ... }: 15 + { 16 + users.users.alice = { 17 + description = "Alice Cooper"; 18 + packages = [ pkgs.vim ]; 19 + }; 20 + }; 21 + 22 + # Alice home-manager. 23 + homeManager = 24 + { pkgs, ... }: 25 + { 26 + home.packages = [ pkgs.htop ]; 27 + }; 28 + }; 29 + }
+44
templates/default/modules/aspects/defaults.nix
··· 1 + { 2 + config, 3 + # deadnix: skip # enable <den/brackets> syntax for demo. 4 + __findFile ? __findFile, 5 + den, 6 + ... 7 + }: 8 + { 9 + # Lets also configure some defaults using aspects. 10 + # These are global static settings. 11 + den.default = { 12 + darwin.system.stateVersion = 6; 13 + nixos.system.stateVersion = "25.05"; 14 + homeManager.home.stateVersion = "25.05"; 15 + }; 16 + 17 + # These are functions that produce configs 18 + den.default.includes = [ 19 + # Enable home-manager on all hosts. 20 + <den/home-manager> 21 + 22 + # Automatically create the user on host. 23 + <den/define-user> 24 + 25 + # Disable booting when running on CI on all NixOS hosts. 26 + (if config ? _module.args.CI then <eg/ci-no-boot> else { }) 27 + 28 + # NOTE: be cautious when adding fully parametric functions to defaults. 29 + # defaults are included on EVERY host/user/home, and IF you are not careful 30 + # you could be duplicating config values. For example: 31 + # 32 + # # This will append 42 into foo option for the {host} and for EVERY {host,user} 33 + # ({ host, ... }: { nixos.foo = [ 42 ]; }) # DO-NOT-DO-THIS. 34 + # 35 + # # Instead try to be explicit if a function is intended for ONLY { host }. 36 + (den.lib.take.exactly ( 37 + { host }: 38 + { 39 + nixos.networking.hostName = host.hostName; 40 + } 41 + )) 42 + 43 + ]; 44 + }
+15
templates/default/modules/aspects/eg/autologin.nix
··· 1 + { 2 + # autologin is context-aware, parametric aspect. 3 + # it applies only if the context has at least { user } 4 + # meaning that has access to user data 5 + eg.autologin = 6 + { user, ... }: 7 + { 8 + nixos = 9 + { config, lib, ... }: 10 + lib.mkIf config.services.displayManager.enable { 11 + services.displayManager.autoLogin.enable = true; 12 + services.displayManager.autoLogin.user = user.userName; 13 + }; 14 + }; 15 + }
+9
templates/default/modules/aspects/eg/ci-no-boot.nix
··· 1 + { 2 + eg.ci-no-boot = { 3 + description = "Disables booting during CI"; 4 + nixos = { 5 + boot.loader.grub.enable = false; 6 + fileSystems."/".device = "/dev/null"; 7 + }; 8 + }; 9 + }
+8
templates/default/modules/aspects/eg/vm-bootable.nix
··· 1 + { 2 + # make USB/VM installers. 3 + eg.vm-bootable.nixos = 4 + { modulesPath, ... }: 5 + { 6 + imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-graphical-base.nix") ]; 7 + }; 8 + }
+19
templates/default/modules/aspects/eg/xfce-desktop.nix
··· 1 + { 2 + eg.xfce-desktop.nixos = 3 + { lib, ... }: 4 + { 5 + # https://gist.github.com/nat-418/1101881371c9a7b419ba5f944a7118b0 6 + services.xserver = { 7 + enable = true; 8 + desktopManager = { 9 + xterm.enable = false; 10 + xfce.enable = true; 11 + }; 12 + }; 13 + 14 + services.displayManager = { 15 + defaultSession = lib.mkDefault "xfce"; 16 + enable = true; 17 + }; 18 + }; 19 + }
+20
templates/default/modules/aspects/igloo.nix
··· 1 + { eg, ... }: 2 + { 3 + den.aspects.igloo = { 4 + # igloo host provides some home-manager defaults to its users. 5 + homeManager.programs.direnv.enable = true; 6 + 7 + # NixOS configuration for igloo. 8 + nixos = 9 + { pkgs, ... }: 10 + { 11 + environment.systemPackages = [ pkgs.hello ]; 12 + }; 13 + 14 + # Include aspects from the eg namespace 15 + includes = [ 16 + eg.vm-bootable 17 + eg.xfce-desktop 18 + ]; 19 + }; 20 + }
+1 -158
templates/default/modules/den.nix
··· 1 - # The best practice is to split this file into several modules, 2 - # creating a directory structure inside `modules/` that makes sense to you. 3 - # See: https://vic.github.io/dendrix/Dendritic.html#no-file-organization-restrictions 4 - { den, config, ... }: 5 1 { 6 - 7 - # First, lets define a NixOS, a nix-darwin and standalone home-manager. 8 - # Feel free to remove, rename or add any other definition. 9 - # NOTE: for nix-darwin/home-manager to work we added dependencies at dendritic.nix. 10 - 11 - # both hosts `igloo` and `apple` have a single user in this setup. 12 - # since user aspect `alice` is the same, they share home configurations. 13 2 den.hosts.x86_64-linux.igloo.users.alice = { }; 14 3 den.hosts.aarch64-darwin.apple.users.alice = { }; 15 - 16 - # an standalone home-manager configuration sharing `alice` aspect. 17 - # den.homes.aarch64-darwin.alice = { }; 18 - 19 - # Now, lets create some aspects and later include them in our host and user aspects. 20 - # 21 - # Aspects can be defined on let-bindings, or be part of `den.aspects` tree. 22 - # Use let bindings for SMALL one-shot aspects, and an aspect tree for more 23 - # complex and re-usable ones. 24 - 25 - # We define this one inside the `common.provides` aspect tree. 26 - # Please organize your aspects with names that make sense to you 27 - # and on their own directories and modules. 28 - den.aspects.common.provides = { 29 - 30 - # xfce-desktop is a non-parametric aspect. it does not uses context 31 - # for how to behave, it must be included explicitly on a host. 32 - xfce-desktop.nixos = 33 - { lib, ... }: 34 - { 35 - # https://gist.github.com/nat-418/1101881371c9a7b419ba5f944a7118b0 36 - services.xserver = { 37 - enable = true; 38 - desktopManager = { 39 - xterm.enable = false; 40 - xfce.enable = true; 41 - }; 42 - }; 43 - 44 - services.displayManager = { 45 - defaultSession = lib.mkDefault "xfce"; 46 - enable = true; 47 - }; 48 - }; 49 - 50 - # autologin is context-aware, parametric aspect. 51 - # it applies only if the context has at least { user } 52 - # meaning that has access to user data 53 - autologin = 54 - { user, ... }: 55 - { 56 - nixos = 57 - { config, lib, ... }: 58 - lib.mkIf config.services.displayManager.enable { 59 - services.displayManager.autoLogin.enable = true; 60 - services.displayManager.autoLogin.user = user.userName; 61 - }; 62 - }; 63 - 64 - # This one can be included on a host to make USB/VM installers. 65 - vm-bootable = 66 - { ... }: 67 - { 68 - nixos = 69 - { modulesPath, ... }: 70 - { 71 - imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-graphical-base.nix") ]; 72 - }; 73 - }; 74 - }; 75 - 76 - den.aspects.igloo.includes = [ 77 - den.aspects.common._.vm-bootable 78 - den.aspects.common._.xfce-desktop 79 - ]; 80 - 81 - # NixOS configuration for igloo. 82 - den.aspects.igloo.nixos = 83 - { pkgs, ... }: 84 - { 85 - environment.systemPackages = [ pkgs.hello ]; 86 - }; 87 - 88 - # igloo host provides some home-manager defaults to its users. 89 - den.aspects.igloo.homeManager.programs.direnv.enable = true; 90 - 91 - den.aspects.alice = { 92 - # You can include other aspects, in this case some 93 - # den included batteries that provide common configs. 94 - includes = [ 95 - den.aspects.common._.autologin 96 - den.provides.primary-user # alice is admin always. 97 - (den.provides.user-shell "fish") # default user shell 98 - ]; 99 - 100 - # Alice configures NixOS hosts it lives on. 101 - nixos = 102 - { pkgs, ... }: 103 - { 104 - users.users.alice = { 105 - description = "Alice Cooper"; 106 - packages = [ pkgs.vim ]; 107 - }; 108 - }; 109 - 110 - # Alice home-manager. 111 - homeManager = 112 - { pkgs, ... }: 113 - { 114 - home.packages = [ pkgs.htop ]; 115 - }; 116 - }; 117 - 118 - # Lets also configure some defaults using aspects. 119 - # These are global static settings. 120 - den.default = { 121 - darwin.system.stateVersion = 6; 122 - nixos.system.stateVersion = "25.05"; 123 - homeManager.home.stateVersion = "25.05"; 124 - }; 125 - 126 - # These are functions that produce configs 127 - den.default.includes = [ 128 - # Enable home-manager on all hosts. 129 - den.provides.home-manager 130 - 131 - # Automatically create the user on host. 132 - den.provides.define-user 133 - 134 - # Disable booting when running on CI on all NixOS hosts. 135 - (if config ? _module.args.CI then den.aspects.ci-no-boot else { }) 136 - 137 - # NOTE: be cautious when adding fully parametric functions to defaults. 138 - # defaults are included on EVERY host/user/home, and IF you are not careful 139 - # you could be duplicating config values. For example: 140 - # 141 - # # This will append 42 into foo option for the {host} and for EVERY {host,user} 142 - # ({ host, ... }: { nixos.foo = [ 42 ]; }) # DO-NOT-DO-THIS. 143 - # 144 - # # Instead try to be explicit if a function is intended for ONLY { host }. 145 - (den.lib.take.exactly ( 146 - { host }: 147 - { 148 - nixos.networking.hostName = host.hostName; 149 - } 150 - )) 151 - 152 - ]; 153 - 154 - den.aspects.ci-no-boot = { 155 - description = "Disables booting during CI"; 156 - nixos = { 157 - boot.loader.grub.enable = false; 158 - fileSystems."/".device = "/dev/null"; 159 - }; 160 - }; 161 - 4 + den.homes.x86_64-linux.alice = { }; 162 5 }
+4 -42
templates/default/modules/dendritic.nix
··· 1 - # This repo was generated with github:vic/flake-file#dendritic template. 2 - # Run `nix run .#write-flake` after changing any input. 3 - # 4 - # Inputs can be placed in any module, the best practice is to have them 5 - # as close as possible to their actual usage. 6 - # See: https://vic.github.io/dendrix/Dendritic.html#minimal-and-focused-flakenix 7 - # 8 - # For our template, we enable home-manager and nix-darwin by default, but 9 - # you are free to remove them if not being used by you. 10 - { inputs, lib, ... }: 1 + { inputs, ... }: 11 2 { 12 - 13 - # DO-NOT-REMOVE this line unless you know what you are doing. 14 - imports = [ (inputs.flake-file.flakeModules.dendritic or { }) ]; 15 - 16 - flake-file.inputs = { 17 - 18 - # DO-NOT-REMOVE this line unless you know what you are doing. 19 - flake-file.url = lib.mkDefault "github:vic/flake-file"; 20 - 21 - home-manager = { 22 - url = "github:nix-community/home-manager"; 23 - inputs.nixpkgs.follows = "nixpkgs"; 24 - }; 25 - 26 - darwin = { 27 - url = "github:nix-darwin/nix-darwin"; 28 - inputs.nixpkgs.follows = "nixpkgs"; 29 - }; 30 - 31 - ## these stable inputs are for wsl 32 - #nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05"; 33 - #home-manager-stable.url = "github:nix-community/home-manager/release-25.05"; 34 - #home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable"; 35 - 36 - #nixos-wsl = { 37 - # url = "github:nix-community/nixos-wsl"; 38 - # inputs.nixpkgs.follows = "nixpkgs-stable"; 39 - # inputs.flake-compat.follows = ""; 40 - #}; 41 - 42 - }; 43 - 3 + imports = [ 4 + inputs.flake-file.flakeModules.dendritic 5 + ]; 44 6 }
+37
templates/default/modules/inputs.nix
··· 1 + # This repo was generated with github:vic/flake-file#dendritic template. 2 + # Run `nix run .#write-flake` after changing any input. 3 + # 4 + # Inputs can be placed in any module, the best practice is to have them 5 + # as close as possible to their actual usage. 6 + # See: https://vic.github.io/dendrix/Dendritic.html#minimal-and-focused-flakenix 7 + # 8 + # For our template, we enable home-manager and nix-darwin by default, but 9 + # you are free to remove them if not being used by you. 10 + { inputs, ... }: 11 + { 12 + 13 + flake-file.inputs = { 14 + home-manager = { 15 + url = "github:nix-community/home-manager"; 16 + inputs.nixpkgs.follows = "nixpkgs"; 17 + }; 18 + 19 + darwin = { 20 + url = "github:nix-darwin/nix-darwin"; 21 + inputs.nixpkgs.follows = "nixpkgs"; 22 + }; 23 + 24 + ## these stable inputs are for wsl 25 + #nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05"; 26 + #home-manager-stable.url = "github:nix-community/home-manager/release-25.05"; 27 + #home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable"; 28 + 29 + #nixos-wsl = { 30 + # url = "github:nix-community/nixos-wsl"; 31 + # inputs.nixpkgs.follows = "nixpkgs-stable"; 32 + # inputs.flake-compat.follows = ""; 33 + #}; 34 + 35 + }; 36 + 37 + }
+14
templates/default/modules/namespace.nix
··· 1 + { inputs, den, ... }: 2 + { 3 + # create an `eg` (example!) namespace. 4 + imports = [ (inputs.den.namespace "eg" false) ]; 5 + 6 + # you can have more than one namespace, create yours. 7 + # imports = [ (inputs.den.namespace "yours" true) ]; 8 + 9 + # you can also import namespaces from remote flakes. 10 + # imports = [ (inputs.den.namespace "ours" inputs.theirs) ]; 11 + 12 + # this line enables den angle brackets syntax in modules. 13 + _module.args.__findFile = den.lib.__findFile; 14 + }