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

Compare changes

Choose any two refs to compare.

+2796 -2453
+42 -1
.github/workflows/test.yml
··· 28 28 - uses: DeterminateSystems/magic-nix-cache-action@v13 29 29 - uses: actions/checkout@v4 30 30 - run: sed -i 's@# den.outPath@den.outPath@' templates/noflake/with-inputs.nix 31 + - run: | 32 + cat <<-EOF > templates/noflake/modules/ci-runtime.nix 33 + { 34 + _module.args.CI = true; 35 + } 36 + EOF 37 + git add templates/noflake/modules/ci-runtime.nix 31 38 - run: cd templates/noflake && nix-build -A nixosConfigurations.igloo.config.system.build.toplevel 39 + minimal: 40 + needs: [non-draft] 41 + name: minimal 42 + runs-on: ubuntu-latest 43 + steps: 44 + - uses: wimpysworld/nothing-but-nix@main 45 + - uses: cachix/install-nix-action@v31 46 + - uses: DeterminateSystems/magic-nix-cache-action@v13 47 + - uses: actions/checkout@v4 48 + - run: | 49 + cat <<-EOF > templates/minimal/modules/ci-runtime.nix 50 + { 51 + _module.args.CI = true; 52 + } 53 + EOF 54 + git add templates/minimal/modules/ci-runtime.nix 55 + - run: nix flake check ./templates/minimal --override-input den github:$GITHUB_REPOSITORY/$GITHUB_SHA 56 + bogus: 57 + needs: [non-draft] 58 + name: bogus 59 + runs-on: ubuntu-latest 60 + steps: 61 + - uses: wimpysworld/nothing-but-nix@main 62 + - uses: cachix/install-nix-action@v31 63 + - uses: DeterminateSystems/magic-nix-cache-action@v13 64 + - uses: actions/checkout@v4 65 + - run: | 66 + cat <<-EOF > templates/bogus/modules/ci-runtime.nix 67 + { 68 + _module.args.CI = true; 69 + } 70 + EOF 71 + git add templates/bogus/modules/ci-runtime.nix 72 + - run: nix flake check ./templates/bogus --override-input den github:$GITHUB_REPOSITORY/$GITHUB_SHA 32 73 template: 33 74 needs: [non-draft] 34 75 strategy: 35 76 matrix: 36 77 os: [ubuntu-latest, macos-latest] 37 - template: [default, bogus, examples] 78 + template: [default, ci, example] 38 79 name: Check template ${{matrix.template}} ${{matrix.os}} 39 80 runs-on: ${{matrix.os}} 40 81 steps:
+80 -21
README.md
··· 22 22 23 23 - [Dendritic](https://github.com/mightyiam/dendritic): **same** concern across **different** Nix classes. 24 24 25 - - Create [DRY](modules/aspects/provides/unfree.nix) & [`class`-generic](modules/aspects/provides/primary-user.nix) modules. 25 + - [Flake optional](templates/noflake). Works with _stable_/_unstable_ Nix and with/without flake-parts. 26 + 27 + - Create [DRY](modules/aspects/provides/unfree/unfree.nix) & [`class`-generic](modules/aspects/provides/primary-user.nix) modules. 26 28 27 29 - [Parametric](modules/aspects/provides/define-user.nix) over `host`/`home`/`user`. 28 30 29 - - Context-aware [dependencies](modules/aspects/dependencies.nix): user/host contributions. 31 + - Context-aware [dependencies](modules/aspects/dependencies.nix): user\<->host bidirectional contributions. 30 32 31 - - [templates/noflake](templates/noflake). Works with stable Nix (no-flakes) and needs no flake-parts. 32 - 33 - - [Share](templates/default/modules/namespace.nix) aspects across systems & repos. 33 + - [Share](templates/example/modules/namespace.nix) aspects across systems & repos. 34 34 35 - - [Routable](templates/default/modules/aspects/eg/routes.nix) configurations. 35 + - [Routable](templates/example/modules/aspects/eg/routes.nix) configurations. 36 36 37 - - Custom factories for any Nix `class`. 37 + - Custom [factories](https://github.com/vic/den/blob/f5c44098e4855e07bf5cbcec00509e75ddde4220/templates/ci/modules/homes.nix#L20) for any Nix `class`. 38 38 39 39 - Use `stable`/`unstable` channels per config. 40 40 41 - - Freeform `host`/`user`/`home` [schemas](modules/_types.nix) (no `specialArgs`) with base modules. 41 + - Freeform `host`/`user`/`home` [schemas](modules/_types.nix) (no `specialArgs`) with [base](https://github.com/vic/den/pull/119) modules. 42 42 43 43 - Multi-platform, multi-tenant hosts. 44 44 ··· 46 46 47 47 - Opt-in [`<angle/brackets>`](https://vic.github.io/den/angle-brackets.html) aspect resolution. 48 48 49 - - Templates [tested](templates/default/modules/tests.nix) along [examples](templates/examples/modules/_example/ci). 49 + - Features [tested](templates/ci). 50 50 51 - - Concepts [documented](https://vic.github.io/den). 51 + - REPL [friendly](https://github.com/vic/den/blob/f5c44098e4855e07bf5cbcec00509e75ddde4220/templates/bogus/modules/bug.nix#L34) [debugging](https://den.oeiuwq.com/debugging.html). 52 52 53 53 Need more **batteries**? See [vic/denful](https://github.com/vic/denful). 54 54 ··· 77 77 **Available templates** 78 78 79 79 - [`default`](templates/default) batteries-included layout. 80 - - [`minimal`](templates/minimal) truly minimalistic start. 81 - - [`examples`](templates/examples) tests for all features. 80 + - [`minimal`](templates/minimal) minimalistic flake. 81 + - [`noflake`](templates/noflake) no flakes, no flake-parts, user nix-maid. 82 + - [`example`](templates/example) examples. 83 + - [`ci`](templates/ci) tests for all features. 82 84 - [`bogus`](templates/bogus) reproduce and report bugs. 83 85 84 86 </div> 85 87 </td> 86 88 <td> 87 89 88 - ๐Ÿ  Define [Hosts, Users](templates/examples/modules/_example/hosts.nix) & [Homes](templates/examples/modules/_example/homes.nix) concisely. 90 + ### Den fundamental idea 91 + 92 + > Configurations that can be applied to multiple host/user combinations. 93 + > The [`__functor`](https://den.oeiuwq.com/functor.html) pattern makes aspects parametric. 94 + 95 + <details> 96 + 97 + <summary> 98 + Den is about propagating context to produce configs. 99 + </summary> 100 + 101 + ```nix 102 + # context => aspect 103 + { host, user, ... }@context: { 104 + # any Nix configuration classes 105 + nixos = { }; 106 + darwin = { }; 107 + homeManager = { }; 108 + # supports conditional includes that inspect context 109 + # unlike nix-module imports 110 + includes = [ ]; 111 + } 112 + ``` 113 + 114 + You first define which [Hosts, Users](templates/ci/modules/hosts.nix) 115 + and [Homes](templates/ci/modules/homes.nix) exist 116 + using freeform-attributes or base-modules. 117 + 118 + ```nix 119 + { 120 + # isWarm or any other freeform attr 121 + den.hosts.x86_64-linux.igloo.isWarm = true; 122 + } 123 + ``` 89 124 90 - See schema in [`_types.nix`](modules/_types.nix). 125 + Then, you write functions from context `host`/`user` to configs. 126 + 127 + ```nix 128 + { 129 + den.aspects.heating = { host, user, ... }: { 130 + nixos = { ... }; # depends on host.isWarm, etc. 131 + homeManager = { ... }; 132 + }; 133 + 134 + # previous aspect can be included on any host 135 + # den.aspects.igloo.includes = [ den.aspects.heating ]; 136 + # or by default in all of them 137 + # den.default.includes = [ den.aspects.heating ]; 138 + } 139 + ``` 140 + 141 + This way, configurations are truly re-usable, 142 + as they are nothing more than functions of the 143 + particularities of the host or its users. 144 + 145 + </details> 146 + 147 + ### Code example 148 + 149 + Schema based hosts/users/homes entities (see [`_types.nix`](modules/_types.nix)). 91 150 92 151 ```nix 93 152 # modules/hosts.nix 94 153 { 95 - # same home-manager vic configuration 96 - # over laptop, macbook and standalone-hm 154 + # same vic home-manager aspect shared 155 + # on laptop, macbook and standalone-hm 97 156 den.hosts.x86_64-linux.lap.users.vic = {}; 98 157 den.hosts.aarch64-darwin.mac.users.vic = {}; 99 158 den.homes.aarch64-darwin.vic = {}; ··· 106 165 $ home-manager switch --flake .#vic 107 166 ``` 108 167 109 - ๐Ÿงฉ [Aspect-oriented](https://github.com/vic/flake-aspects) incremental features. ([example](templates/default/modules/den.nix)) 110 - 111 - Any module can contribute configurations to aspects. 168 + Any module can contribute configurations to [aspects](https://github.com/vic/flake-aspects). 112 169 113 170 ```nix 114 171 # modules/my-laptop.nix ··· 154 211 155 212 }; 156 213 } 214 + ``` 157 215 216 + ```nix 158 217 # modules/vic.nix 159 218 { den, ... }: { 160 219 den.aspects.vic = { ··· 165 224 }; 166 225 includes = [ 167 226 den.aspects.tiling-wm 168 - den._.primary-user 227 + den.provides.primary-user 169 228 ]; 170 229 }; 171 230 } ··· 177 236 178 237 You are done! You know everything to start creating configurations with `den`. 179 238 180 - Feel free to to **explore** the codebase, particularly our [included batteries](modules/aspects/provides) and [tests](templates/examples/modules/_example/ci). 239 + Feel free to to **explore** the codebase, particularly our [included batteries](modules/aspects/provides) and [tests](templates/ci). 181 240 182 241 ## Learn more at our [documentation website](https://vic.github.io/den) 183 242
+9
modules/aspects/provides/ci-noboot.nix
··· 1 + { config, lib, ... }: 2 + { 3 + den.default.includes = lib.optionals (config ? _module.args.CI) [ 4 + { 5 + nixos.fileSystems."/".device = lib.mkDefault "/dev/noroot"; 6 + nixos.boot.loader.grub.enable = lib.mkDefault false; 7 + } 8 + ]; 9 + }
+1 -2
modules/aspects/provides/home-manager/hm-dependencies.nix
··· 22 22 includes = [ 23 23 (owned den.default) 24 24 (statics den.default) 25 - (owned HM-OS-USER.HM) 26 - (statics HM-OS-USER.HM) 27 25 (parametric.fixedTo HM-OS-USER HM-OS-USER.OS) 26 + (parametric.fixedTo HM-OS-USER HM-OS-USER.HM) 28 27 ]; 29 28 }; 30 29
+11
modules/output.nix
··· 1 + { inputs, lib, ... }: 2 + if inputs ? flake-parts then 3 + { } 4 + else 5 + { 6 + # NOTE: Currently Den needs a top-level attribute where to place configurations, 7 + # by default it is the `flake` attribute, even if Den uses no flake-parts at all. 8 + options.flake = lib.mkOption { 9 + type = lib.types.submodule { freeformType = lib.types.anything; }; 10 + }; 11 + }
+5 -3
nix/default.nix
··· 8 8 modules.flake = flakeModules; 9 9 templates = { 10 10 default.path = ../templates/default; 11 - default.description = "Batteries included"; 11 + default.description = "Default template"; 12 12 minimal.path = ../templates/minimal; 13 13 minimal.description = "Minimalistic den"; 14 - examples.path = ../templates/examples; 15 - examples.description = "API examples and CI"; 14 + example.path = ../templates/example; 15 + example.description = "Example"; 16 + ci.path = ../templates/ci; 17 + ci.description = "Feature Tests"; 16 18 bogus.path = ../templates/bogus; 17 19 bogus.description = "For bug reproduction"; 18 20 };
+1 -1
nix/template-packages.nix
··· 5 5 url = "https://github.com/edolstra/flake-compat/archive/${rev}.tar.gz"; 6 6 sha256 = narHash; 7 7 }; 8 - flake = import compat { src = ../templates/default; }; 8 + flake = import compat { src = ../templates/example; }; 9 9 pkgs = flake.outputs.packages; 10 10 in 11 11 {
+2 -2
templates/bogus/.github/workflows/test.yml
··· 8 8 flake-check: 9 9 strategy: 10 10 matrix: 11 - os: [ubuntu-latest, macos-latest] 11 + os: [ubuntu-latest] 12 12 name: Nix flake check 13 13 runs-on: ${{matrix.os}} 14 14 steps: 15 15 - uses: wimpysworld/nothing-but-nix@main 16 16 if: matrix.os == 'ubuntu-latest' 17 17 - uses: cachix/install-nix-action@v31 18 - - uses: DeterminateSystems/magic-nix-cache-action@13 18 + - uses: DeterminateSystems/magic-nix-cache-action@v13 19 19 - uses: actions/checkout@v5 20 20 - run: nix flake metadata 21 21 - run: nix flake check
+13 -4
templates/bogus/README.md
··· 4 4 5 5 Create a **minimal** bug reproduction at [`modules/bug.nix`](modules/bug.nix) 6 6 7 + See also [Den debugging tips](https://den.oeiuwq.com/debugging.html) 8 + 7 9 Then run tests: 8 10 9 - ```console 11 + ```shell 10 12 nix flake check 11 13 ``` 12 14 13 - Format code with: 15 + Please share a link to your reproduction repo, showing the CI step and the 16 + error at CI build. 17 + 18 + ## Fixing Den 19 + 20 + If you are contributing a bug-fix PR, you can use the following command to 21 + use your local den checkout. 14 22 15 - ```console 16 - nix fmt 23 + ```shell 24 + cd <den-working-copy> 25 + nix flake check --override-input den . ./templates/bogus 17 26 ```
+45 -79
templates/bogus/flake.lock
··· 1 1 { 2 2 "nodes": { 3 - "darwin": { 4 - "inputs": { 5 - "nixpkgs": [ 6 - "nixpkgs" 7 - ] 8 - }, 9 - "locked": { 10 - "lastModified": 1763505477, 11 - "narHash": "sha256-nJRd4LY2kT3OELfHqdgWjvToNZ4w+zKCMzS2R6z4sXE=", 12 - "owner": "nix-darwin", 13 - "repo": "nix-darwin", 14 - "rev": "3bda9f6b14161becbd07b3c56411f1670e19b9b5", 15 - "type": "github" 16 - }, 17 - "original": { 18 - "owner": "nix-darwin", 19 - "repo": "nix-darwin", 20 - "type": "github" 21 - } 22 - }, 23 3 "den": { 24 4 "locked": { 25 - "lastModified": 1763707606, 26 - "narHash": "sha256-l9v3NNdKj3GJvV5LhzsWDs4Sl2bg0tuKNFFkMeFvUWo=", 5 + "lastModified": 1770400943, 6 + "narHash": "sha256-73eh5R6UQOP6B04dxot7Jdxmc/nd3n9fe1XX8vp8l3Q=", 27 7 "owner": "vic", 28 8 "repo": "den", 29 - "rev": "8164e0d89c59839d67757bc9a1fb61770dc6e8b7", 9 + "rev": "b07ef22d338ef765e4e296fb3223ba3cf4e9ae82", 30 10 "type": "github" 31 11 }, 32 12 "original": { 33 13 "owner": "vic", 34 - "ref": "main", 35 14 "repo": "den", 36 15 "type": "github" 37 16 } 38 17 }, 39 18 "flake-aspects": { 40 19 "locked": { 41 - "lastModified": 1769717274, 20 + "lastModified": 1769723924, 42 21 "narHash": "sha256-U15OaMr9AcJiB1wW2uCFzFO+DnQ3jJSvln+ZR/+Q0vE=", 43 22 "owner": "vic", 44 23 "repo": "flake-aspects", 45 - "rev": "a35ed5efc9a629694d659d606230ba18a76cefaa", 24 + "rev": "61524836788ef6991a82e7d34ebb0ccc05d374ed", 46 25 "type": "github" 47 26 }, 48 27 "original": { ··· 51 30 "type": "github" 52 31 } 53 32 }, 54 - "flake-file": { 55 - "locked": { 56 - "lastModified": 1763706734, 57 - "narHash": "sha256-kR1Rrh9evfiJaTb6ufWCSk6GMtrnPKFydqQUV0Bb4Eg=", 58 - "owner": "vic", 59 - "repo": "flake-file", 60 - "rev": "9af20d5e62c94b658b4d0671829393c1b8bb0b3e", 61 - "type": "github" 62 - }, 63 - "original": { 64 - "owner": "vic", 65 - "repo": "flake-file", 66 - "type": "github" 67 - } 68 - }, 69 33 "flake-parts": { 70 34 "inputs": { 71 35 "nixpkgs-lib": [ 72 - "nixpkgs-lib" 36 + "nixpkgs" 73 37 ] 74 38 }, 75 39 "locked": { 76 - "lastModified": 1762440070, 77 - "narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=", 40 + "lastModified": 1769996383, 41 + "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", 78 42 "owner": "hercules-ci", 79 43 "repo": "flake-parts", 80 - "rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8", 44 + "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", 81 45 "type": "github" 82 46 }, 83 47 "original": { ··· 93 57 ] 94 58 }, 95 59 "locked": { 96 - "lastModified": 1762463325, 97 - "narHash": "sha256-33YUsWpPyeBZEWrKQ2a1gkRZ7i0XCC/2MYpU6BVeQSU=", 60 + "lastModified": 1770491427, 61 + "narHash": "sha256-8b+0vixdqGnIIcgsPhjdX7EGPdzcVQqYxF+ujjex654=", 98 62 "owner": "nix-community", 99 63 "repo": "home-manager", 100 - "rev": "0562fef070a1027325dd4ea10813d64d2c967b39", 64 + "rev": "cbd8a72e5fe6af19d40e2741dc440d9227836860", 101 65 "type": "github" 102 66 }, 103 67 "original": { ··· 108 72 }, 109 73 "import-tree": { 110 74 "locked": { 111 - "lastModified": 1762327901, 112 - "narHash": "sha256-AJ96FNj50DU0bTyIzAPkPOjCZTHqjURVjok8qoXvmqM=", 75 + "lastModified": 1763762820, 76 + "narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=", 113 77 "owner": "vic", 114 78 "repo": "import-tree", 115 - "rev": "90fa129798be99cde036b78658e89475710966a1", 79 + "rev": "3c23749d8013ec6daa1d7255057590e9ca726646", 116 80 "type": "github" 117 81 }, 118 82 "original": { ··· 121 85 "type": "github" 122 86 } 123 87 }, 88 + "nix-github-actions": { 89 + "inputs": { 90 + "nixpkgs": [ 91 + "nix-unit", 92 + "nixpkgs" 93 + ] 94 + }, 95 + "locked": { 96 + "lastModified": 1737420293, 97 + "narHash": "sha256-F1G5ifvqTpJq7fdkT34e/Jy9VCyzd5XfJ9TO8fHhJWE=", 98 + "owner": "nix-community", 99 + "repo": "nix-github-actions", 100 + "rev": "f4158fa080ef4503c8f4c820967d946c2af31ec9", 101 + "type": "github" 102 + }, 103 + "original": { 104 + "owner": "nix-community", 105 + "repo": "nix-github-actions", 106 + "type": "github" 107 + } 108 + }, 124 109 "nix-unit": { 125 110 "inputs": { 126 111 "flake-parts": [ 127 112 "flake-parts" 128 113 ], 114 + "nix-github-actions": "nix-github-actions", 129 115 "nixpkgs": [ 130 116 "nixpkgs" 131 117 ], 132 118 "treefmt-nix": "treefmt-nix" 133 119 }, 134 120 "locked": { 135 - "lastModified": 1762507096, 136 - "narHash": "sha256-dE3CbZR8KRDdb3b4fhMnpvhEl6XB+UnrLezuFekQ2ME=", 121 + "lastModified": 1762774186, 122 + "narHash": "sha256-hRADkHjNt41+JUHw2EiSkMaL4owL83g5ZppjYUdF/Dc=", 137 123 "owner": "nix-community", 138 124 "repo": "nix-unit", 139 - "rev": "0d7230bc54783b812a5817398885aec660a93051", 125 + "rev": "1c9ab50554eed0b768f9e5b6f646d63c9673f0f7", 140 126 "type": "github" 141 127 }, 142 128 "original": { ··· 147 133 }, 148 134 "nixpkgs": { 149 135 "locked": { 150 - "lastModified": 1762361079, 151 - "narHash": "sha256-lz718rr1BDpZBYk7+G8cE6wee3PiBUpn8aomG/vLLiY=", 136 + "lastModified": 1770380644, 137 + "narHash": "sha256-P7dWMHRUWG5m4G+06jDyThXO7kwSk46C1kgjEWcybkE=", 152 138 "owner": "nixos", 153 139 "repo": "nixpkgs", 154 - "rev": "ffcdcf99d65c61956d882df249a9be53e5902ea5", 140 + "rev": "ae67888ff7ef9dff69b3cf0cc0fbfbcd3a722abe", 155 141 "type": "github" 156 142 }, 157 143 "original": { ··· 163 149 }, 164 150 "root": { 165 151 "inputs": { 166 - "darwin": "darwin", 167 152 "den": "den", 168 153 "flake-aspects": "flake-aspects", 169 - "flake-file": "flake-file", 170 154 "flake-parts": "flake-parts", 171 155 "home-manager": "home-manager", 172 156 "import-tree": "import-tree", 173 157 "nix-unit": "nix-unit", 174 - "nixpkgs": "nixpkgs", 175 - "nixpkgs-lib": [ 176 - "nixpkgs" 177 - ], 178 - "systems": "systems" 179 - } 180 - }, 181 - "systems": { 182 - "locked": { 183 - "lastModified": 1681028828, 184 - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 185 - "owner": "nix-systems", 186 - "repo": "default", 187 - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 188 - "type": "github" 189 - }, 190 - "original": { 191 - "owner": "nix-systems", 192 - "repo": "default", 193 - "type": "github" 158 + "nixpkgs": "nixpkgs" 194 159 } 195 160 }, 196 161 "treefmt-nix": { 197 162 "inputs": { 198 163 "nixpkgs": [ 164 + "nix-unit", 199 165 "nixpkgs" 200 166 ] 201 167 },
+13 -23
templates/bogus/flake.nix
··· 1 - # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 - # Use `nix run .#write-flake` to regenerate it. 3 1 { 4 - 5 2 outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 3 7 4 inputs = { 8 - darwin = { 9 - inputs.nixpkgs.follows = "nixpkgs"; 10 - url = "github:nix-darwin/nix-darwin"; 11 - }; 12 - den.url = "github:vic/den/main"; 5 + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 + import-tree.url = "github:vic/import-tree"; 13 7 flake-aspects.url = "github:vic/flake-aspects"; 14 - flake-file.url = "github:vic/flake-file"; 8 + den.url = "github:vic/den"; 9 + 15 10 flake-parts = { 16 - inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 17 11 url = "github:hercules-ci/flake-parts"; 18 - }; 19 - home-manager = { 20 - inputs.nixpkgs.follows = "nixpkgs"; 21 - url = "github:nix-community/home-manager"; 12 + inputs.nixpkgs-lib.follows = "nixpkgs"; 22 13 }; 23 - import-tree.url = "github:vic/import-tree"; 14 + 24 15 nix-unit = { 25 - inputs = { 26 - flake-parts.follows = "flake-parts"; 27 - nixpkgs.follows = "nixpkgs"; 28 - }; 29 16 url = "github:nix-community/nix-unit"; 17 + inputs.nixpkgs.follows = "nixpkgs"; 18 + inputs.flake-parts.follows = "flake-parts"; 30 19 }; 31 - nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 32 - nixpkgs-lib.follows = "nixpkgs"; 33 - systems.url = "github:nix-systems/default"; 20 + 21 + home-manager = { 22 + url = "github:nix-community/home-manager"; 23 + inputs.nixpkgs.follows = "nixpkgs"; 24 + }; 34 25 }; 35 - 36 26 }
+36 -14
templates/bogus/modules/bug.nix
··· 1 - { inputs, lib, ... }: 1 + { 2 + inputs, 3 + den, 4 + lib, 5 + ... 6 + }: 2 7 { 3 8 den.hosts.x86_64-linux.igloo.users.tux = { }; 4 - den.hosts.aarch64-darwin.apple.users.tim = { }; 5 9 10 + den.aspects.igloo.includes = [ den.aspects.testing ]; 6 11 # Use aspects to create a **minimal** bug reproduction 7 - den.aspects.igloo.nixos = 8 - { pkgs, ... }: 9 - { 10 - users.users.tux.packages = [ pkgs.hello ]; 12 + den.aspects.testing = 13 + { user, ... }@ctx: 14 + builtins.trace ctx.host.hostName { 15 + homeManager.programs.vim.enable = user.userName == "tux"; 11 16 }; 12 17 13 - # rename "it works", evidently it has bugs 14 - flake.tests."test it works" = 18 + # `nix-unit --flake .#.tests.systems` 19 + # `nix eval .#.tests.testItWorks` 20 + flake.tests.testItWorks = 15 21 let 16 - tux = inputs.self.nixosConfigurations.igloo.config.users.users.tux; 17 - 18 - expr.len = lib.length tux.packages; 19 - expr.names = map lib.getName tux.packages; 22 + igloo = inputs.self.nixosConfigurations.igloo.config; 23 + tux = igloo.home-manager.users.tux; 20 24 21 - expected.len = 1; 22 - expected.names = [ "hello" ]; 25 + expr = tux.programs.vim.enable; 26 + expected = true; 23 27 in 24 28 { 25 29 inherit expr expected; 26 30 }; 31 + 32 + # See [Debugging Tips](https://den.oeiuwq.com/debugging.html) 33 + flake.den = den; 34 + # `nix eval .#.value` 35 + flake.value = 36 + let 37 + aspect = den.aspects.testing { 38 + user.userName = "tux"; 39 + host.hostName = "fake"; 40 + }; 41 + modules = [ 42 + (aspect.resolve { class = "homeManager"; }) 43 + { options.programs = lib.mkOption { }; } 44 + ]; 45 + evaled = lib.evalModules { inherit modules; }; 46 + in 47 + evaled.config; 48 + 27 49 }
-9
templates/bogus/modules/dendritic.nix
··· 1 - { inputs, lib, ... }: 2 - { 3 - flake-file.inputs.flake-file.url = lib.mkDefault "github:vic/flake-file"; 4 - flake-file.inputs.den.url = lib.mkDefault "github:vic/den"; 5 - imports = [ 6 - (inputs.flake-file.flakeModules.dendritic or { }) 7 - (inputs.den.flakeModules.dendritic or { }) 8 - ]; 9 - }
-26
templates/bogus/modules/flakes.nix
··· 1 - # DO-NOT-CHANGE. Keep your reproduction minimalistic! 2 - # 3 - # try not adding new inputs 4 - # but if you have no options (pun intended) 5 - # here's the place. 6 - # 7 - # IF you make any change to this file, use: 8 - # `nix run .#write-flake` 9 - # 10 - # We provide nix-darwin and home-manager for common usage. 11 - { 12 - # change "main" with a commit where bug is present 13 - flake-file.inputs.den.url = "github:vic/den/main"; 14 - 15 - # included so we can test HM integrations. 16 - flake-file.inputs.home-manager = { 17 - url = "github:nix-community/home-manager"; 18 - inputs.nixpkgs.follows = "nixpkgs"; 19 - }; 20 - 21 - # included for testing darwin hosts. 22 - flake-file.inputs.darwin = { 23 - url = "github:nix-darwin/nix-darwin"; 24 - inputs.nixpkgs.follows = "nixpkgs"; 25 - }; 26 - }
-19
templates/bogus/modules/nix-unit.nix
··· 1 - # DO-NOT-EDIT: nix-unit configuration. 2 - { lib, inputs, ... }: 3 - { 4 - 5 - flake-file.inputs.nix-unit = { 6 - url = "github:nix-community/nix-unit"; 7 - inputs.nixpkgs.follows = "nixpkgs"; 8 - inputs.flake-parts.follows = "flake-parts"; 9 - }; 10 - 11 - imports = [ 12 - inputs.nix-unit.modules.flake.default 13 - ]; 14 - 15 - perSystem.nix-unit = { 16 - allowNetwork = lib.mkDefault true; 17 - inputs = lib.mkDefault inputs; 18 - }; 19 - }
+25 -8
templates/bogus/modules/test-base.nix
··· 1 - { den, ... }: 1 + # DO-NOT-EDIT unless necessary. Keep your reproduction repo minimal. 2 + { 3 + den, 4 + lib, 5 + inputs, 6 + ... 7 + }: 2 8 { 3 - den.default.nixos.system.stateVersion = "25.11"; 4 - den.default.homeManager.home.stateVersion = "25.11"; 5 - den.default.darwin.system.stateVersion = 6; 9 + imports = [ 10 + inputs.den.flakeModule 11 + inputs.nix-unit.modules.flake.default 12 + ]; 13 + 14 + systems = lib.attrNames den.hosts; 15 + 16 + den.default.nixos.system.stateVersion = "26.05"; 17 + den.default.homeManager.home.stateVersion = "26.05"; 6 18 7 19 den.default.includes = [ 8 - den._.home-manager 9 - den._.define-user 20 + den.provides.home-manager 21 + den.provides.define-user 10 22 den.aspects.no-boot 11 23 ]; 12 24 13 25 den.aspects.no-boot.nixos = { 14 - boot.loader.grub.enable = false; 15 - fileSystems."/".device = "/dev/fake"; 26 + boot.loader.grub.enable = lib.mkForce false; 27 + fileSystems."/".device = lib.mkForce "/dev/fake"; 28 + }; 29 + 30 + perSystem.nix-unit = { 31 + allowNetwork = lib.mkDefault true; 32 + inputs = lib.mkDefault inputs; 16 33 }; 17 34 }
+304
templates/ci/flake.lock
··· 1 + { 2 + "nodes": { 3 + "darwin": { 4 + "inputs": { 5 + "nixpkgs": [ 6 + "nixpkgs" 7 + ] 8 + }, 9 + "locked": { 10 + "lastModified": 1762039661, 11 + "narHash": "sha256-oM5BwAGE78IBLZn+AqxwH/saqwq3e926rNq5HmOulkc=", 12 + "owner": "nix-darwin", 13 + "repo": "nix-darwin", 14 + "rev": "c3c8c9f2a5ed43175ac4dc030308756620e6e4e4", 15 + "type": "github" 16 + }, 17 + "original": { 18 + "owner": "nix-darwin", 19 + "repo": "nix-darwin", 20 + "type": "github" 21 + } 22 + }, 23 + "den": { 24 + "locked": { 25 + "lastModified": 1767645236, 26 + "narHash": "sha256-VMrWett3fWRb0hQh9K1JUC3zV2OlV4zOajFZHGr1GPw=", 27 + "owner": "vic", 28 + "repo": "den", 29 + "rev": "e7837daa0ea0f03fba62a2653ce16314a7d9d1c8", 30 + "type": "github" 31 + }, 32 + "original": { 33 + "owner": "vic", 34 + "repo": "den", 35 + "type": "github" 36 + } 37 + }, 38 + "flake-aspects": { 39 + "locked": { 40 + "lastModified": 1769717274, 41 + "narHash": "sha256-U15OaMr9AcJiB1wW2uCFzFO+DnQ3jJSvln+ZR/+Q0vE=", 42 + "owner": "vic", 43 + "repo": "flake-aspects", 44 + "rev": "a35ed5efc9a629694d659d606230ba18a76cefaa", 45 + "type": "github" 46 + }, 47 + "original": { 48 + "owner": "vic", 49 + "repo": "flake-aspects", 50 + "type": "github" 51 + } 52 + }, 53 + "flake-file": { 54 + "locked": { 55 + "lastModified": 1763706734, 56 + "narHash": "sha256-kR1Rrh9evfiJaTb6ufWCSk6GMtrnPKFydqQUV0Bb4Eg=", 57 + "owner": "vic", 58 + "repo": "flake-file", 59 + "rev": "9af20d5e62c94b658b4d0671829393c1b8bb0b3e", 60 + "type": "github" 61 + }, 62 + "original": { 63 + "owner": "vic", 64 + "repo": "flake-file", 65 + "type": "github" 66 + } 67 + }, 68 + "flake-parts": { 69 + "inputs": { 70 + "nixpkgs-lib": [ 71 + "nixpkgs-lib" 72 + ] 73 + }, 74 + "locked": { 75 + "lastModified": 1762040540, 76 + "narHash": "sha256-z5PlZ47j50VNF3R+IMS9LmzI5fYRGY/Z5O5tol1c9I4=", 77 + "owner": "hercules-ci", 78 + "repo": "flake-parts", 79 + "rev": "0010412d62a25d959151790968765a70c436598b", 80 + "type": "github" 81 + }, 82 + "original": { 83 + "owner": "hercules-ci", 84 + "repo": "flake-parts", 85 + "type": "github" 86 + } 87 + }, 88 + "home-manager": { 89 + "inputs": { 90 + "nixpkgs": [ 91 + "nixpkgs" 92 + ] 93 + }, 94 + "locked": { 95 + "lastModified": 1762087455, 96 + "narHash": "sha256-hpbPma1eUKwLAmiVRoMgIHbHiIKFkcACobJLbDt6ABw=", 97 + "owner": "nix-community", 98 + "repo": "home-manager", 99 + "rev": "43e205606aeb253bfcee15fd8a4a01d8ce8384ca", 100 + "type": "github" 101 + }, 102 + "original": { 103 + "owner": "nix-community", 104 + "repo": "home-manager", 105 + "type": "github" 106 + } 107 + }, 108 + "home-manager-stable": { 109 + "inputs": { 110 + "nixpkgs": [ 111 + "nixpkgs-stable" 112 + ] 113 + }, 114 + "locked": { 115 + "lastModified": 1758463745, 116 + "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", 117 + "owner": "nix-community", 118 + "repo": "home-manager", 119 + "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", 120 + "type": "github" 121 + }, 122 + "original": { 123 + "owner": "nix-community", 124 + "ref": "release-25.05", 125 + "repo": "home-manager", 126 + "type": "github" 127 + } 128 + }, 129 + "import-tree": { 130 + "locked": { 131 + "lastModified": 1761120675, 132 + "narHash": "sha256-TEbh9zISiQcU82VwVoEbmXHnSGlUxTwvjJA9g9ErSDA=", 133 + "owner": "vic", 134 + "repo": "import-tree", 135 + "rev": "a037ed2a58fc0ebed9e93b9ef79b0646e648f719", 136 + "type": "github" 137 + }, 138 + "original": { 139 + "owner": "vic", 140 + "repo": "import-tree", 141 + "type": "github" 142 + } 143 + }, 144 + "neovim-nightly-overlay": { 145 + "inputs": { 146 + "flake-parts": [ 147 + "flake-parts" 148 + ], 149 + "neovim-src": "neovim-src", 150 + "nixpkgs": [ 151 + "nixpkgs" 152 + ] 153 + }, 154 + "locked": { 155 + "lastModified": 1766016290, 156 + "narHash": "sha256-YMf/PUyY4z7RlIe/Dzn1NnxZGS0Vp2eHxcMNWJM9q+A=", 157 + "owner": "nix-community", 158 + "repo": "neovim-nightly-overlay", 159 + "rev": "f7fbc4e3d4ccea45eaa5b187884592eb42dfdbbd", 160 + "type": "github" 161 + }, 162 + "original": { 163 + "owner": "nix-community", 164 + "repo": "neovim-nightly-overlay", 165 + "type": "github" 166 + } 167 + }, 168 + "neovim-src": { 169 + "flake": false, 170 + "locked": { 171 + "lastModified": 1766014002, 172 + "narHash": "sha256-KE/ufBGH8XFXTw3Vt1DrK1rQmAEp1Q+oyLQibX5UKO0=", 173 + "owner": "neovim", 174 + "repo": "neovim", 175 + "rev": "c172fd9f464d5766eab9071e8f4770504c920c05", 176 + "type": "github" 177 + }, 178 + "original": { 179 + "owner": "neovim", 180 + "repo": "neovim", 181 + "type": "github" 182 + } 183 + }, 184 + "nixos-wsl": { 185 + "inputs": { 186 + "flake-compat": [], 187 + "nixpkgs": [ 188 + "nixpkgs-stable" 189 + ] 190 + }, 191 + "locked": { 192 + "lastModified": 1761969132, 193 + "narHash": "sha256-0me4+e+1VxNuvySSw0voqMCWU/eUmTuth7f4+Q2jbUY=", 194 + "owner": "nix-community", 195 + "repo": "nixos-wsl", 196 + "rev": "761582d6ab431549fe1396d2cd681e3fe9376020", 197 + "type": "github" 198 + }, 199 + "original": { 200 + "owner": "nix-community", 201 + "repo": "nixos-wsl", 202 + "type": "github" 203 + } 204 + }, 205 + "nixpkgs": { 206 + "locked": { 207 + "lastModified": 1761880412, 208 + "narHash": "sha256-QoJjGd4NstnyOG4mm4KXF+weBzA2AH/7gn1Pmpfcb0A=", 209 + "owner": "nixos", 210 + "repo": "nixpkgs", 211 + "rev": "a7fc11be66bdfb5cdde611ee5ce381c183da8386", 212 + "type": "github" 213 + }, 214 + "original": { 215 + "owner": "nixos", 216 + "ref": "nixpkgs-unstable", 217 + "repo": "nixpkgs", 218 + "type": "github" 219 + } 220 + }, 221 + "nixpkgs-stable": { 222 + "locked": { 223 + "lastModified": 1762081535, 224 + "narHash": "sha256-+j+CUiaUoa87EhnSOqG5pwXdJWahP8vo6BE0ekssdzs=", 225 + "owner": "nixos", 226 + "repo": "nixpkgs", 227 + "rev": "2afc9d6e79b59ea9bcaf620d335623b0f7c2ce96", 228 + "type": "github" 229 + }, 230 + "original": { 231 + "owner": "nixos", 232 + "ref": "release-25.05", 233 + "repo": "nixpkgs", 234 + "type": "github" 235 + } 236 + }, 237 + "provider": { 238 + "inputs": { 239 + "den": [ 240 + "den" 241 + ], 242 + "flake-aspects": [ 243 + "flake-aspects" 244 + ], 245 + "flake-parts": [ 246 + "flake-parts" 247 + ], 248 + "import-tree": [ 249 + "import-tree" 250 + ], 251 + "nixpkgs": [ 252 + "nixpkgs" 253 + ] 254 + }, 255 + "locked": { 256 + "path": "./provider", 257 + "type": "path" 258 + }, 259 + "original": { 260 + "path": "./provider", 261 + "type": "path" 262 + }, 263 + "parent": [] 264 + }, 265 + "root": { 266 + "inputs": { 267 + "darwin": "darwin", 268 + "den": "den", 269 + "flake-aspects": "flake-aspects", 270 + "flake-file": "flake-file", 271 + "flake-parts": "flake-parts", 272 + "home-manager": "home-manager", 273 + "home-manager-stable": "home-manager-stable", 274 + "import-tree": "import-tree", 275 + "neovim-nightly-overlay": "neovim-nightly-overlay", 276 + "nixos-wsl": "nixos-wsl", 277 + "nixpkgs": "nixpkgs", 278 + "nixpkgs-lib": [ 279 + "nixpkgs" 280 + ], 281 + "nixpkgs-stable": "nixpkgs-stable", 282 + "provider": "provider", 283 + "systems": "systems" 284 + } 285 + }, 286 + "systems": { 287 + "locked": { 288 + "lastModified": 1681028828, 289 + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 290 + "owner": "nix-systems", 291 + "repo": "default", 292 + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 293 + "type": "github" 294 + }, 295 + "original": { 296 + "owner": "nix-systems", 297 + "repo": "default", 298 + "type": "github" 299 + } 300 + } 301 + }, 302 + "root": "root", 303 + "version": 7 304 + }
+58
templates/ci/flake.nix
··· 1 + # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 + # Use `nix run .#write-flake` to regenerate it. 3 + { 4 + 5 + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 + 7 + inputs = { 8 + darwin = { 9 + inputs.nixpkgs.follows = "nixpkgs"; 10 + url = "github:nix-darwin/nix-darwin"; 11 + }; 12 + den.url = "github:vic/den"; 13 + flake-aspects.url = "github:vic/flake-aspects"; 14 + flake-file.url = "github:vic/flake-file"; 15 + flake-parts = { 16 + inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 17 + url = "github:hercules-ci/flake-parts"; 18 + }; 19 + home-manager = { 20 + inputs.nixpkgs.follows = "nixpkgs"; 21 + url = "github:nix-community/home-manager"; 22 + }; 23 + home-manager-stable = { 24 + inputs.nixpkgs.follows = "nixpkgs-stable"; 25 + url = "github:nix-community/home-manager/release-25.05"; 26 + }; 27 + import-tree.url = "github:vic/import-tree"; 28 + neovim-nightly-overlay = { 29 + inputs = { 30 + flake-parts.follows = "flake-parts"; 31 + nixpkgs.follows = "nixpkgs"; 32 + }; 33 + url = "github:nix-community/neovim-nightly-overlay"; 34 + }; 35 + nixos-wsl = { 36 + inputs = { 37 + flake-compat.follows = ""; 38 + nixpkgs.follows = "nixpkgs-stable"; 39 + }; 40 + url = "github:nix-community/nixos-wsl"; 41 + }; 42 + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 43 + nixpkgs-lib.follows = "nixpkgs"; 44 + nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05"; 45 + provider = { 46 + inputs = { 47 + den.follows = "den"; 48 + flake-aspects.follows = "flake-aspects"; 49 + flake-parts.follows = "flake-parts"; 50 + import-tree.follows = "import-tree"; 51 + nixpkgs.follows = "nixpkgs"; 52 + }; 53 + url = "path:./provider"; 54 + }; 55 + systems.url = "github:nix-systems/default"; 56 + }; 57 + 58 + }
+81
templates/ci/modules/angle-bracket-deep.nix
··· 1 + { 2 + inputs, 3 + lib, 4 + ns, 5 + # deadnix: skip 6 + __findFile ? __findFile, 7 + ... 8 + }: 9 + let 10 + treeModule.nixos.options.tree = lib.mkOption { 11 + type = lib.types.listOf lib.types.str; 12 + }; 13 + inputX = { 14 + denful.ns.root = { 15 + nixos.tree = [ "X-root" ]; 16 + provides.branch.nixos.tree = [ "X-branch" ]; 17 + provides.branch.provides.leaf.nixos.tree = [ "X-leaf" ]; 18 + }; 19 + }; 20 + inputY = { 21 + denful.ns.root = { 22 + nixos.tree = [ "Y-root" ]; 23 + provides.branch.nixos.tree = [ "Y-branch" ]; 24 + provides.branch.provides.leaf.nixos.tree = [ "Y-leaf" ]; 25 + }; 26 + }; 27 + in 28 + { 29 + 30 + imports = [ 31 + (inputs.den.namespace "ns" [ 32 + true 33 + inputX 34 + inputY 35 + ]) 36 + ]; 37 + 38 + ns.root = { 39 + nixos.tree = [ "local-root" ]; 40 + provides.branch.nixos.tree = [ "local-branch" ]; 41 + provides.branch.provides.leaf.nixos.tree = [ "local-leaf" ]; 42 + }; 43 + 44 + den.aspects.rockhopper.includes = [ 45 + treeModule 46 + <ns/root> 47 + <ns/root/branch> 48 + <ns/root/branch/leaf> 49 + ]; 50 + 51 + perSystem = 52 + { checkCond, rockhopper, ... }: 53 + let 54 + vals = lib.sort (a: b: a < b) rockhopper.config.tree; 55 + in 56 + { 57 + checks.ns-angle-bracket-root = checkCond "angle-bracket access root" (<ns/root> == ns.root); 58 + 59 + checks.ns-angle-bracket-branch = checkCond "angle-bracket access branch" ( 60 + <ns/root/branch> == ns.root._.branch 61 + ); 62 + 63 + checks.ns-angle-bracket-leaf = checkCond "angle-bracket access leaf" ( 64 + <ns/root/branch/leaf> == ns.root._.branch._.leaf 65 + ); 66 + 67 + checks.ns-tree-all-levels-merged = checkCond "all tree levels merged" ( 68 + vals == [ 69 + "X-branch" 70 + "X-leaf" 71 + "X-root" 72 + "Y-branch" 73 + "Y-leaf" 74 + "Y-root" 75 + "local-branch" 76 + "local-leaf" 77 + "local-root" 78 + ] 79 + ); 80 + }; 81 + }
+28
templates/ci/modules/auto-imported.nix
··· 1 + # configures class-automatic module auto imports for hosts/users/homes. 2 + # See documentation at modules/aspects/provides/import-tree.nix 3 + { 4 + # deadnix: skip 5 + __findFile ? __findFile, 6 + ... 7 + }: 8 + { 9 + 10 + # alice imports non-dendritic <class> modules from ../non-dendritic/alice/_<class>/*.nix 11 + den.aspects.alice.includes = [ (<den/import-tree> ./../non-dendritic/alice) ]; 12 + 13 + # See the documentation at batteries/import-tree.nix 14 + den.default.includes = [ 15 + (<den/import-tree/host> ./../non-dendritic/hosts) 16 + (<den/import-tree/user> ./../non-dendritic/users) 17 + (<den/import-tree/home> ./../non-dendritic/homes) 18 + ]; 19 + 20 + # tests 21 + perSystem = 22 + { checkCond, rockhopper, ... }: 23 + { 24 + checks.import-tree = checkCond "auto-imported from rockhopper/_nixos" ( 25 + rockhopper.config.auto-imported 26 + ); 27 + }; 28 + }
+76
templates/ci/modules/base-conf-modules.nix
··· 1 + # tests for extending `den.base.*` modules with capabilities (options). 2 + # these allow you to expend all hosts/users/homes with custom option 3 + # that can later be used by aspects for providing features. 4 + # 5 + { lib, ... }: 6 + { 7 + 8 + # This module is base for all host configs. 9 + den.base.host = 10 + { host, ... }: 11 + { 12 + options.capabilities.ssh-server = lib.mkEnableOption "Does host ${host.name} provide ssh?"; 13 + }; 14 + 15 + # This module is base for all user configs. 16 + den.base.user = 17 + { user, ... }: 18 + { 19 + options.isAdmin = lib.mkOption { 20 + type = lib.types.bool; 21 + default = user.name == "alice"; # only alice is always admin 22 + }; 23 + }; 24 + 25 + # This module is base for all home configs. 26 + # den.base.home = { home, ... }: { }; 27 + 28 + # This one is included on each host/user/home 29 + # it cannot access host/user/home values since this conf is generic. 30 + den.base.conf = { 31 + options.foo = lib.mkOption { 32 + type = lib.types.str; 33 + default = "bar"; 34 + }; 35 + }; 36 + 37 + # Now hosts and users can set any option defined in base modules. 38 + den.hosts.x86_64-linux.rockhopper = { 39 + capabilities.ssh-server = true; 40 + foo = "boo"; 41 + users.alice = { 42 + # isAdmin = true; # alice is admin by default, nothing explicit here. 43 + foo = "moo"; 44 + }; 45 + }; 46 + 47 + den.aspects.rockhopper.includes = 48 + let 49 + # An aspect can make use of these options to provide configuration. 50 + sshCapable = 51 + { host, ... }: 52 + { 53 + nixos.services.sshd.enable = host.capabilities.ssh-server; 54 + homeManager.services.ssh-agent.enable = host.capabilities.ssh-server; 55 + }; 56 + in 57 + [ sshCapable ]; 58 + 59 + # CI checks 60 + perSystem = 61 + { 62 + checkCond, 63 + rockhopper, 64 + alice-at-rockhopper, 65 + ... 66 + }: 67 + { 68 + checks.host-conf-rockhopper-sshd = checkCond "sshd enabled" ( 69 + rockhopper.config.services.sshd.enable == true 70 + ); 71 + checks.host-conf-alice-sshd = checkCond "ssh-agent enabled" ( 72 + alice-at-rockhopper.services.ssh-agent.enable == true 73 + ); 74 + }; 75 + 76 + }
+27
templates/ci/modules/builds.nix
··· 1 + # Adds some checks for CI 2 + { 3 + perSystem = 4 + { 5 + pkgs, 6 + checkFile, 7 + rockhopper, 8 + honeycrisp, 9 + cam, 10 + bob, 11 + ... 12 + }: 13 + let 14 + checks.x86_64-linux = { 15 + vm = checkFile "vm-builds" "${rockhopper.config.system.build.vm}/bin/run-rockhopper-vm"; 16 + hosts-rockhopper = checkFile "nixos-builds" rockhopper.config.system.build.toplevel; 17 + homes-cam = checkFile "home-builds" cam.activation-script; 18 + }; 19 + checks.aarch64-darwin = { 20 + hosts-honeycrisp = checkFile "darwin-builds" honeycrisp.config.system.build.toplevel; 21 + homes-bob = checkFile "darwin-home-builds" bob.activation-script; 22 + }; 23 + in 24 + { 25 + checks = checks.${pkgs.stdenv.hostPlatform.system} or { }; 26 + }; 27 + }
+67
templates/ci/modules/cross-flake-parametric.nix
··· 1 + { 2 + inputs, 3 + lib, 4 + provider, 5 + ... 6 + }: 7 + let 8 + providerModule.nixos.options.providerVars = lib.mkOption { 9 + type = lib.types.attrsOf lib.types.str; 10 + default = { }; 11 + }; 12 + in 13 + { 14 + flake-file.inputs.provider = { 15 + url = "path:./provider"; 16 + inputs.den.follows = "den"; 17 + inputs.flake-aspects.follows = "flake-aspects"; 18 + inputs.flake-parts.follows = "flake-parts"; 19 + inputs.import-tree.follows = "import-tree"; 20 + inputs.nixpkgs.follows = "nixpkgs"; 21 + }; 22 + 23 + imports = [ 24 + (inputs.den.namespace "provider" [ 25 + true 26 + inputs.provider 27 + ]) 28 + ]; 29 + 30 + provider.tools._.dev._.editors = { 31 + nixos.providerVars.LOCAL_EDITOR = "emacs"; 32 + }; 33 + 34 + den.aspects.rockhopper.includes = [ 35 + providerModule 36 + provider.tools._.dev._.editors 37 + provider.tools._.dev._.shells 38 + ]; 39 + 40 + perSystem = 41 + { checkCond, rockhopper, ... }: 42 + let 43 + vars = rockhopper.config.providerVars; 44 + env = rockhopper.config.environment.variables; 45 + in 46 + { 47 + checks.cross-flake-provider-editor = checkCond "provider editor var set" ( 48 + env.PROVIDER_EDITOR == "vim" 49 + ); 50 + 51 + checks.cross-flake-provider-shell = checkCond "provider shell var set" ( 52 + env.PROVIDER_SHELL == "fish" 53 + ); 54 + 55 + checks.cross-flake-local-editor = checkCond "local editor var set" (vars.LOCAL_EDITOR == "emacs"); 56 + 57 + checks.cross-flake-namespace-merged = checkCond "namespace merged from provider input" ( 58 + provider.tools._.dev._.editors == inputs.self.denful.provider.tools._.dev._.editors 59 + && provider.tools._.dev._.shells == inputs.self.denful.provider.tools._.dev._.shells 60 + ); 61 + 62 + checks.cross-flake-input-denful = checkCond "input provider denful accessible" ( 63 + inputs.provider.denful.provider.tools._.dev._.editors.description 64 + == "Editor configurations from provider flake" 65 + ); 66 + }; 67 + }
+30
templates/ci/modules/custom-home-managed-package.nix
··· 1 + { 2 + # Including an static aspect should not cause duplicate definitions 3 + den.aspects.alice.includes = [ 4 + { 5 + homeManager = 6 + { pkgs, ... }: 7 + { 8 + programs.emacs.enable = true; 9 + programs.emacs.package = pkgs.emacs30-nox; 10 + }; 11 + } 12 + ]; 13 + 14 + perSystem = 15 + { 16 + checkCond, 17 + alice-at-rockhopper, 18 + lib, 19 + ... 20 + }: 21 + { 22 + checks.alice-custom-emacs = checkCond "set uniquely via a static includes" ( 23 + let 24 + expr = lib.getName alice-at-rockhopper.programs.emacs.package; 25 + expected = "emacs-nox"; 26 + in 27 + expr == expected 28 + ); 29 + }; 30 + }
+35
templates/ci/modules/custom-nixos-module.nix
··· 1 + { lib, ... }: 2 + let 3 + # A custom `nixos` class module that defines an option `names`. 4 + # Used to test that we are not duplicating values from owned configs. 5 + nixosNames = names: { options.${names} = lib.mkOption { type = lib.types.listOf lib.types.str; }; }; 6 + in 7 + { 8 + den.default.nixos.imports = [ (nixosNames "people") ]; 9 + den.default.includes = [ 10 + ( 11 + { user, ... }: 12 + { 13 + nixos.people = [ user.name ]; 14 + } 15 + ) 16 + ]; 17 + 18 + den.aspects.rockhopper.includes = [ 19 + # Example: importing a third-party nixos module. 20 + { nixos.imports = [ (nixosNames "names") ]; } 21 + ]; 22 + 23 + den.aspects.rockhopper.nixos.names = [ "tux" ]; 24 + 25 + perSystem = 26 + { checkCond, rockhopper, ... }: 27 + { 28 + checks.rockhopper-default-people = checkCond "set from den.default for each user" ( 29 + rockhopper.config.people == [ "alice" ] 30 + ); 31 + checks.rockhopper-names-single-entry = checkCond "custom nixos array option set once" ( 32 + rockhopper.config.names == [ "tux" ] 33 + ); 34 + }; 35 + }
+78
templates/ci/modules/deep-nested-namespace.nix
··· 1 + { 2 + inputs, 3 + lib, 4 + deep, 5 + ... 6 + }: 7 + let 8 + deepModule.nixos.options.deepVals = lib.mkOption { 9 + type = lib.types.listOf lib.types.str; 10 + }; 11 + depthA = { 12 + denful.deep.a._.b._.c._.d._.e = { 13 + description = "5 levels deep from inputA"; 14 + nixos.deepVals = [ "inputA-5-levels" ]; 15 + provides.f.nixos.deepVals = [ "inputA-6-levels" ]; 16 + }; 17 + }; 18 + depthB = { 19 + denful.deep.a._.b._.c._.d._.e = { 20 + nixos.deepVals = [ "inputB-5-levels" ]; 21 + provides.f.nixos.deepVals = [ "inputB-6-levels" ]; 22 + }; 23 + }; 24 + in 25 + { 26 + imports = [ 27 + (inputs.den.namespace "deep" [ 28 + true 29 + depthA 30 + depthB 31 + ]) 32 + ]; 33 + 34 + deep.a._.b._.c._.d._.e = { 35 + nixos.deepVals = [ "local-5-levels" ]; 36 + provides.f.nixos.deepVals = [ "local-6-levels" ]; 37 + }; 38 + 39 + den.aspects.rockhopper.includes = [ 40 + deepModule 41 + deep.a._.b._.c._.d._.e 42 + deep.a._.b._.c._.d._.e._.f 43 + ]; 44 + 45 + perSystem = 46 + { checkCond, rockhopper, ... }: 47 + let 48 + vals = lib.sort (a: b: a < b) rockhopper.config.deepVals; 49 + in 50 + { 51 + checks.deep-nest-5-levels = checkCond "5 levels deep merged correctly" ( 52 + builtins.elem "inputA-5-levels" vals 53 + && builtins.elem "inputB-5-levels" vals 54 + && builtins.elem "local-5-levels" vals 55 + ); 56 + 57 + checks.deep-nest-6-levels = checkCond "6 levels deep merged correctly" ( 58 + builtins.elem "inputA-6-levels" vals 59 + && builtins.elem "inputB-6-levels" vals 60 + && builtins.elem "local-6-levels" vals 61 + ); 62 + 63 + checks.deep-nest-all-merged = checkCond "all values merged" ( 64 + vals == [ 65 + "inputA-5-levels" 66 + "inputA-6-levels" 67 + "inputB-5-levels" 68 + "inputB-6-levels" 69 + "local-5-levels" 70 + "local-6-levels" 71 + ] 72 + ); 73 + 74 + checks.deep-nest-flake-output = checkCond "deep namespace as flake output" ( 75 + inputs.self.denful.deep.a._.b._.c._.d._.e._.f == deep.a._.b._.c._.d._.e._.f 76 + ); 77 + }; 78 + }
+14
templates/ci/modules/defaults.nix
··· 1 + # User TODO: Remove this file. 2 + { 3 + # default aspect can be used for global static settings. 4 + den.default = { 5 + # static values. 6 + darwin.system.stateVersion = 6; 7 + nixos.system.stateVersion = "25.05"; 8 + homeManager.home.stateVersion = "25.05"; 9 + 10 + # these defaults are set for checking with CI. 11 + nixos.programs.vim.enable = true; 12 + darwin.programs.zsh.enable = true; 13 + }; 14 + }
+27
templates/ci/modules/define-user.nix
··· 1 + { den, ... }: 2 + { 3 + den.default.includes = [ 4 + # Example: parametric over many contexts: { home }, { host, user }, { fromUser, toHost } 5 + den.provides.define-user 6 + ]; 7 + 8 + perSystem = 9 + { 10 + checkCond, 11 + rockhopper, 12 + adelie, 13 + ... 14 + }: 15 + { 16 + 17 + checks.alice-exists-on-rockhopper = checkCond "den.default.user.includes defines user on host" ( 18 + rockhopper.config.users.users.alice.isNormalUser 19 + ); 20 + checks.alice-not-exists-on-adelie = checkCond "den.default.user.includes defines user on host" ( 21 + !adelie.config.users.users ? alice 22 + ); 23 + checks.will-exists-on-adelie = checkCond "den.default.user.includes defines user on host" ( 24 + adelie.config.users.users.will.isNormalUser 25 + ); 26 + }; 27 + }
+9
templates/ci/modules/dendritic.nix
··· 1 + { inputs, lib, ... }: 2 + { 3 + flake-file.inputs.flake-file.url = lib.mkDefault "github:vic/flake-file"; 4 + flake-file.inputs.den.url = lib.mkDefault "github:vic/den"; 5 + imports = [ 6 + (inputs.flake-file.flakeModules.dendritic or { }) 7 + (inputs.den.flakeModules.dendritic or { }) 8 + ]; 9 + }
+8
templates/ci/modules/enable-wsl-host.nix
··· 1 + { inputs, ... }: 2 + { 3 + # Example: adelie host using github:nix-community/NixOS-WSL 4 + den.aspects.adelie.nixos = { 5 + imports = [ inputs.nixos-wsl.nixosModules.default ]; 6 + wsl.enable = true; 7 + }; 8 + }
+37
templates/ci/modules/helpers.nix
··· 1 + { self, ... }: 2 + { 3 + perSystem = 4 + { pkgs, ... }: 5 + let 6 + checkFile = 7 + name: file: 8 + pkgs.runCommandLocal name { } '' 9 + ls -la ${file} | tee $out 10 + ''; 11 + 12 + checkCond = 13 + name: cond: 14 + let 15 + code = if cond then "touch $out" else ''echo "Cond-Failed: ${name}"''; 16 + in 17 + pkgs.runCommandLocal name { } code; 18 + 19 + rockhopper = self.nixosConfigurations.rockhopper; 20 + honeycrisp = self.darwinConfigurations.honeycrisp; 21 + adelie = self.wslConfigurations.adelie; 22 + cam = self.homeConfigurations.cam; 23 + bob = self.homeConfigurations.bob; 24 + luke = self.homeConfigurations.luke; 25 + 26 + alice-at-rockhopper = rockhopper.config.home-manager.users.alice; 27 + alice-at-honeycrisp = honeycrisp.config.home-manager.users.alice; 28 + in 29 + { 30 + _module.args = { 31 + inherit checkCond checkFile; 32 + inherit rockhopper honeycrisp adelie; 33 + inherit cam bob luke; 34 + inherit alice-at-rockhopper alice-at-honeycrisp; 35 + }; 36 + }; 37 + }
+29
templates/ci/modules/hm-enabled-host.nix
··· 1 + { den, inputs, ... }: 2 + { 3 + # The `{ HM-OS-HOST }` context is activated ONLY for hosts that have 4 + # a HM supported OS and at least one user with homeManager class. 5 + den.aspects.hm-global-pkgs = 6 + { HM-OS-HOST }: 7 + den.lib.take.unused [ HM-OS-HOST.host ] # access host from context if needed 8 + { 9 + nixos.home-manager.useGlobalPkgs = true; 10 + }; 11 + 12 + den.default.includes = [ den.aspects.hm-global-pkgs ]; 13 + 14 + den.hosts.x86_64-linux.no-homes = { }; 15 + 16 + perSystem = 17 + { checkCond, rockhopper, ... }: 18 + { 19 + checks.rockhopper-hm-global-pkgs = checkCond "rockhopper-hm-global-pkgs" ( 20 + rockhopper.config.home-manager.useGlobalPkgs 21 + ); 22 + 23 + checks.no-homes-hm-global-pkgs = checkCond "no-homes-hm-global-pkgs" ( 24 + # no home-manager enabled nor useGlobalPkgs 25 + !inputs.self.nixosConfigurations.no-homes.config ? home-manager.useGlobalPkgs 26 + ); 27 + }; 28 + 29 + }
+12
templates/ci/modules/home-managed.nix
··· 1 + { den, ... }: 2 + { 3 + # see batteries/home-manager.nix 4 + den.default.includes = [ den._.home-manager ]; 5 + 6 + # enable home-manager dependency. 7 + flake-file.inputs.home-manager = { 8 + url = "github:nix-community/home-manager"; 9 + inputs.nixpkgs.follows = "nixpkgs"; 10 + }; 11 + 12 + }
+31
templates/ci/modules/homes.nix
··· 1 + # Example standalone home-manager configurations. 2 + # These are independent of any host configuration. 3 + # See documentation at <den>/nix/types.nix 4 + { inputs, ... }: 5 + { 6 + den.homes.x86_64-linux.cam = { }; 7 + 8 + den.homes.aarch64-darwin.bob = { 9 + userName = "robert"; 10 + aspect = "developer"; 11 + }; 12 + 13 + # Example: custom home-manager instantiate for passing extraSpecialArgs. 14 + den.homes.x86_64-linux.luke = 15 + let 16 + osConfig = inputs.self.nixosConfigurations.rockhopper.config; 17 + in 18 + { 19 + # Example: luke standalone-homemanager needs access to rockhopper osConfig. 20 + instantiate = 21 + { pkgs, modules }: 22 + inputs.home-manager.lib.homeManagerConfiguration { 23 + inherit pkgs modules; 24 + extraSpecialArgs.osConfig = osConfig; 25 + }; 26 + 27 + # Example: custom attribute instead of specialArgs 28 + programToDependOn = "vim"; 29 + }; 30 + 31 + }
+13
templates/ci/modules/host-configures-users.nix
··· 1 + { 2 + 3 + # Example: host provides static config to all its users hm. 4 + den.aspects.rockhopper.homeManager.programs.direnv.enable = true; 5 + 6 + perSystem = 7 + { checkCond, alice-at-rockhopper, ... }: 8 + { 9 + checks.host-contributes-to-user = checkCond "rockhopper contributes to all its users" ( 10 + alice-at-rockhopper.programs.direnv.enable 11 + ); 12 + }; 13 + }
+48
templates/ci/modules/host-user-conditional-hm.nix
··· 1 + { lib, ... }: 2 + let 3 + # Example: configuration that depends on both host and user. provides only to HM. 4 + program-conditional = 5 + program: 6 + { 7 + user, 8 + host, 9 + ... 10 + }: 11 + if user.userName == "alice" && !lib.hasSuffix "darwin" host.system then 12 + { 13 + homeManager.programs.${program}.enable = true; 14 + } 15 + else 16 + { }; 17 + in 18 + { 19 + 20 + # Example: host parametric includes. conditional user configuration. 21 + den.aspects.rockhopper.includes = [ (program-conditional "git") ]; 22 + 23 + # Example: user parametric includes 24 + den.aspects.alice.includes = [ (program-conditional "mpv") ]; 25 + 26 + perSystem = 27 + { 28 + checkCond, 29 + alice-at-rockhopper, 30 + alice-at-honeycrisp, 31 + ... 32 + }: 33 + { 34 + 35 + checks.alice-hm-git-enabled-on = checkCond "home-managed git for alice at rockhopper" ( 36 + alice-at-rockhopper.programs.git.enable 37 + ); 38 + checks.alice-hm-git-enabled-off = checkCond "home-managed git for alice at honeycrisp" ( 39 + !alice-at-honeycrisp.programs.git.enable 40 + ); 41 + 42 + checks.alice-hm-mpv-enabled-rockhopper = checkCond "home-managed mpv for alice at rockhopper" ( 43 + alice-at-rockhopper.programs.mpv.enable 44 + ); 45 + 46 + }; 47 + 48 + }
+50
templates/ci/modules/hosts.nix
··· 1 + # This is a fully working example configuration. 2 + # Feel free to remove it, adapt or split into several modules. 3 + # See documentation at <den>/nix/types.nix 4 + { inputs, ... }: 5 + { 6 + den.hosts.aarch64-darwin.honeycrisp.users.alice = { }; 7 + 8 + den.hosts.aarch64-linux.emperor.users.alice = { }; 9 + 10 + den.hosts.x86_64-linux = { 11 + rockhopper = { 12 + description = "rockhopper is a kind of penguin"; 13 + users.alice = { }; 14 + }; 15 + 16 + adelie = { 17 + description = "wsl on windows"; 18 + users.will = { }; 19 + intoAttr = "wslConfigurations"; 20 + # custom nixpkgs channel. 21 + instantiate = inputs.nixpkgs-stable.lib.nixosSystem; 22 + # custom attribute (see home-manager.nix) 23 + hm-module = inputs.home-manager-stable.nixosModules.home-manager; 24 + # custom attribute (see primary-user.nix) 25 + wsl = { }; 26 + }; 27 + }; 28 + 29 + # move these inputs to any module you want. 30 + # they are here for all our examples to work on CI. 31 + flake-file.inputs = { 32 + 33 + # these stable inputs are for wsl 34 + nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05"; 35 + home-manager-stable.url = "github:nix-community/home-manager/release-25.05"; 36 + home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable"; 37 + 38 + nixos-wsl = { 39 + url = "github:nix-community/nixos-wsl"; 40 + inputs.nixpkgs.follows = "nixpkgs-stable"; 41 + inputs.flake-compat.follows = ""; 42 + }; 43 + 44 + darwin = { 45 + url = "github:nix-darwin/nix-darwin"; 46 + inputs.nixpkgs.follows = "nixpkgs"; 47 + }; 48 + }; 49 + 50 + }
+81
templates/ci/modules/namespace.nix
··· 1 + { 2 + inputs, 3 + den, 4 + lib, 5 + eg, 6 + # deadnix: skip 7 + __findFile ? __findFile, 8 + ... 9 + }: 10 + let 11 + # module for testing inclusion of namespaces 12 + simsModule.nixos.options.sims = lib.mkOption { 13 + type = lib.types.listOf lib.types.str; 14 + }; 15 + in 16 + { 17 + # enable <angle/bracket> syntax for finding aspects. 18 + _module.args.__findFile = den.lib.__findFile; 19 + 20 + imports = [ 21 + # create a local namespace and output at flake.denful.eg 22 + (inputs.den.namespace "eg" true) 23 + 24 + # you can also mount a namespace from many input sources. 25 + # the second argument becomes an array of inputs. 26 + ( 27 + let 28 + # NOTE: here we simulate inputA and inputB are flakes. 29 + inputA.denful.sim.ul._.a._.tion.nixos.sims = [ "inputA simulation" ]; 30 + inputB.denful.sim.ul._.a._.tion.nixos.sims = [ "inputB simulation" ]; 31 + exposeToFlake = true; 32 + in 33 + inputs.den.namespace "sim" [ 34 + inputA 35 + inputB 36 + exposeToFlake 37 + ] 38 + ) 39 + ]; 40 + 41 + # define nested aspects in local namespace 42 + eg.foo.provides.bar.provides.baz = { 43 + nixos.sims = [ "local namespace" ]; 44 + }; 45 + 46 + # augment aspects on a mounted namespace 47 + sim.ul._.a._.tion.nixos.sims = [ "local simulation" ]; 48 + 49 + den.aspects.rockhopper.includes = [ 50 + simsModule 51 + <eg/foo/bar/baz> 52 + <sim/ul/a/tion> 53 + ]; 54 + 55 + perSystem = 56 + { checkCond, rockhopper, ... }: 57 + { 58 + checks.namespace-eg-flake-output = checkCond "namespace enabled as flake output" ( 59 + eg == den.ful.eg && eg == <eg> && eg == inputs.self.denful.eg 60 + ); 61 + 62 + checks.namespace-eg-provides-accessible = checkCond "exact same value" ( 63 + eg.foo._.bar._.baz == <eg/foo/bar/baz> 64 + && eg.foo._.bar._.baz == inputs.self.denful.eg.foo._.bar._.baz 65 + ); 66 + 67 + checks.namespace-sim-merged = checkCond "merges from all sources" ( 68 + let 69 + expected = [ 70 + "inputA simulation" 71 + "inputB simulation" 72 + "local namespace" 73 + "local simulation" 74 + ]; 75 + actual = lib.sort (a: b: a < b) rockhopper.config.sims; 76 + in 77 + expected == actual 78 + ); 79 + 80 + }; 81 + }
+41
templates/ci/modules/one-os-package-per-user.nix
··· 1 + let 2 + 3 + # Example: adds hello into each user. provides only to OS. 4 + hello-package-for-user = 5 + { 6 + user, 7 + host, 8 + ... 9 + }: 10 + { 11 + ${host.class} = 12 + { pkgs, ... }: 13 + { 14 + users.users.${user.userName}.packages = [ pkgs.hello ]; 15 + }; 16 + }; 17 + 18 + in 19 + { 20 + 21 + den.default.includes = [ hello-package-for-user ]; 22 + 23 + perSystem = 24 + { 25 + checkCond, 26 + rockhopper, 27 + lib, 28 + ... 29 + }: 30 + { 31 + checks.alice-hello-enabled-by-default = checkCond "added hello at user packages" ( 32 + let 33 + progs = rockhopper.config.users.users.alice.packages; 34 + expr = map lib.getName progs; 35 + expected = [ "hello" ]; 36 + in 37 + expr == expected 38 + ); 39 + }; 40 + 41 + }
+145
templates/ci/modules/parametric-with-owned.nix
··· 1 + { 2 + den, 3 + lib, 4 + ... 5 + }: 6 + let 7 + # a test module to check context was forwarded 8 + fwdModule.options.fwd = { 9 + a = strOpt; 10 + b = strOpt; 11 + c = strOpt; 12 + d = strOpt; 13 + e = strOpt; 14 + f = strOpt; 15 + # unlike strings, pkgs cannot be duplicated/merged, we use this to 16 + # ensure no-dups are created from parametric owned modules. 17 + pkg = pkgOpt; 18 + pkg2 = pkgOpt; 19 + pkg3 = pkgOpt; 20 + }; 21 + strOpt = lib.mkOption { type = lib.types.str; }; 22 + pkgOpt = lib.mkOption { type = lib.types.package; }; 23 + 24 + inherit (den.lib) parametric; 25 + in 26 + { 27 + den.aspects.rockhopper.includes = [ 28 + { nixos.imports = [ fwdModule ]; } 29 + { homeManager.imports = [ fwdModule ]; } 30 + den.aspects.fwd._.first 31 + ]; 32 + den.aspects.rockhopper.nixos.fwd.c = "host owned C"; 33 + den.aspects.rockhopper.homeManager.fwd.a = "host home-managed A"; 34 + 35 + # this aspect will take any context and also forward it 36 + # into any includes function that can take same context. 37 + den.aspects.fwd._.first = parametric { 38 + nixos = 39 + { pkgs, ... }: 40 + { 41 + fwd.a = "First owned A"; 42 + fwd.pkg = pkgs.hello; 43 + }; 44 + homeManager = 45 + { pkgs, ... }: 46 + { 47 + fwd.pkg = pkgs.vim; 48 + }; 49 + includes = [ 50 + den.aspects.fwd._.second 51 + { nixos.fwd.d = "First static includes D"; } 52 + den.aspects.fwd._.never 53 + den.aspects.fwd._.fourth 54 + ]; 55 + }; 56 + 57 + # Note that second has named arguments, while first does not. 58 + # the first aspect forwards whatever context it receives. 59 + den.aspects.fwd._.second = 60 + { host, ... }: 61 + parametric.fixedTo { third = "Impact"; } { 62 + includes = [ den.aspects.fwd._.third ]; 63 + nixos = 64 + { pkgs, ... }: 65 + { 66 + fwd.b = "Second owned B for ${host.name}"; 67 + fwd.pkg2 = pkgs.bat; 68 + }; 69 + homeManager = 70 + { pkgs, ... }: 71 + { 72 + fwd.pkg2 = pkgs.helix; 73 + }; 74 + }; 75 + 76 + den.aspects.fwd._.third = 77 + { third, ... }: 78 + { 79 + nixos.fwd.e = "Third ${third}"; 80 + }; 81 + 82 + den.aspects.fwd._.fourth = parametric.expands { planet = "Earth"; } { 83 + includes = [ den.aspects.fwd._.fifth ]; 84 + nixos = 85 + { pkgs, ... }: 86 + { 87 + fwd.pkg3 = pkgs.emacs-nox; 88 + }; 89 + homeManager = 90 + { pkgs, ... }: 91 + { 92 + fwd.pkg3 = pkgs.emacs-nox; 93 + }; 94 + }; 95 + 96 + den.aspects.fwd._.fifth = 97 + { host, planet, ... }: 98 + { 99 + nixos.fwd.f = "Fifth ${planet} ${host.name}"; 100 + }; 101 + 102 + den.aspects.fwd._.never = 103 + { never-matches }: 104 + { 105 + nixos.fwd.a = "Imposibru! should never be included ${never-matches}"; 106 + }; 107 + 108 + perSystem = 109 + { 110 + checkCond, 111 + rockhopper, 112 + alice-at-rockhopper, 113 + ... 114 + }: 115 + { 116 + checks.parametric-fwd-a = checkCond "fwd-a" (rockhopper.config.fwd.a == "First owned A"); 117 + checks.parametric-fwd-b = checkCond "fwd-b" ( 118 + rockhopper.config.fwd.b == "Second owned B for rockhopper" 119 + ); 120 + checks.parametric-fwd-c = checkCond "fwd-c" (rockhopper.config.fwd.c == "host owned C"); 121 + checks.parametric-fwd-d = checkCond "fwd-d" (rockhopper.config.fwd.d == "First static includes D"); 122 + checks.parametric-fwd-e = checkCond "fwd-e" (rockhopper.config.fwd.e == "Third Impact"); 123 + checks.parametric-fwd-f = checkCond "fwd-f" (rockhopper.config.fwd.f == "Fifth Earth rockhopper"); 124 + 125 + checks.parametric-fwd-pkg = checkCond "fwd-pkg" (lib.getName rockhopper.config.fwd.pkg == "hello"); 126 + checks.parametric-fwd-pkg2 = checkCond "fwd-pkg2" (lib.getName rockhopper.config.fwd.pkg2 == "bat"); 127 + checks.parametric-fwd-pkg3 = checkCond "fwd-pkg3" ( 128 + lib.getName rockhopper.config.fwd.pkg3 == "emacs-nox" 129 + ); 130 + 131 + checks.parametric-fwd-hm-a = checkCond "fwd-hm-a" ( 132 + alice-at-rockhopper.fwd.a == "host home-managed A" 133 + ); 134 + checks.parametric-fwd-hm-pkg = checkCond "fwd-hm-pkg" ( 135 + lib.getName alice-at-rockhopper.fwd.pkg == "vim" 136 + ); 137 + checks.parametric-fwd-hm-pkg2 = checkCond "fwd-hm-pkg2" ( 138 + lib.getName alice-at-rockhopper.fwd.pkg2 == "helix" 139 + ); 140 + checks.parametric-fwd-hm-pkg3 = checkCond "fwd-hm-pkg3" ( 141 + lib.getName alice-at-rockhopper.fwd.pkg3 == "emacs-nox" 142 + ); 143 + }; 144 + 145 + }
+29
templates/ci/modules/primary-user.nix
··· 1 + { den, ... }: 2 + { 3 + den.aspects.alice.includes = [ 4 + # alice is always admin in all its hosts 5 + den._.primary-user 6 + ]; 7 + 8 + den.aspects.will.includes = [ 9 + # will is primary user in WSL NixOS. 10 + den._.primary-user 11 + ]; 12 + 13 + perSystem = 14 + { 15 + checkCond, 16 + honeycrisp, 17 + adelie, 18 + ... 19 + }: 20 + { 21 + checks.alice-primary-on-macos = checkCond "den._.primary-user sets macos primary" ( 22 + honeycrisp.config.system.primaryUser == "alice" 23 + ); 24 + 25 + checks.will-is-wsl-default = checkCond "wsl.defaultUser defined" ( 26 + adelie.config.wsl.defaultUser == "will" 27 + ); 28 + }; 29 + }
+29
templates/ci/modules/set-hostname.nix
··· 1 + { 2 + den.default.includes = 3 + let 4 + # Example: parametric host aspect to automatically set hostName on any host. 5 + set-host-name = 6 + { host, ... }: 7 + { 8 + ${host.class}.networking.hostName = host.name; 9 + }; 10 + in 11 + [ set-host-name ]; 12 + 13 + perSystem = 14 + { 15 + checkCond, 16 + rockhopper, 17 + honeycrisp, 18 + ... 19 + }: 20 + { 21 + checks.rockhopper-hostname = checkCond "den.default.host.includes sets hostName" ( 22 + rockhopper.config.networking.hostName == "rockhopper" 23 + ); 24 + 25 + checks.honeycrisp-hostname = checkCond "den.default.host.includes sets hostName" ( 26 + honeycrisp.config.networking.hostName == "honeycrisp" 27 + ); 28 + }; 29 + }
+53
templates/ci/modules/shared-parametric-aspects.nix
··· 1 + { 2 + inputs, 3 + lib, 4 + shared, 5 + ... 6 + }: 7 + let 8 + dataModule.nixos.options.data = lib.mkOption { 9 + type = lib.types.listOf lib.types.str; 10 + }; 11 + mkInputFlake = name: { 12 + denful.shared.gaming._.retro._.sega = { 13 + nixos.data = [ "${name}-sega-static" ]; 14 + }; 15 + }; 16 + inputFoo = mkInputFlake "foo"; 17 + inputBar = mkInputFlake "bar"; 18 + in 19 + { 20 + imports = [ 21 + (inputs.den.namespace "shared" [ 22 + true 23 + inputFoo 24 + inputBar 25 + ]) 26 + ]; 27 + 28 + shared.gaming._.retro._.sega.nixos.data = [ "local-sega-static" ]; 29 + 30 + den.aspects.rockhopper.includes = [ 31 + dataModule 32 + shared.gaming._.retro._.sega 33 + ]; 34 + 35 + perSystem = 36 + { checkCond, rockhopper, ... }: 37 + let 38 + vals = lib.sort (a: b: a < b) rockhopper.config.data; 39 + in 40 + { 41 + checks.shared-parametric-all-merged = checkCond "all parametric merged" ( 42 + vals == [ 43 + "bar-sega-static" 44 + "foo-sega-static" 45 + "local-sega-static" 46 + ] 47 + ); 48 + 49 + checks.shared-flake-output-matches = checkCond "flake output matches" ( 50 + shared.gaming._.retro._.sega == inputs.self.denful.shared.gaming._.retro._.sega 51 + ); 52 + }; 53 + }
+70
templates/ci/modules/special-args.nix
··· 1 + { den, withSystem, ... }: 2 + let 3 + testModule = 4 + { 5 + inputs', 6 + lib, 7 + self', 8 + ... 9 + }: 10 + { 11 + options.specialArgsTest = { 12 + test-package = lib.mkOption { type = lib.types.package; }; 13 + neovim-package = lib.mkOption { type = lib.types.package; }; 14 + }; 15 + 16 + config.specialArgsTest = { 17 + test-package = self'.packages.hello; 18 + neovim-package = inputs'.neovim-nightly-overlay.packages.neovim; 19 + }; 20 + }; 21 + in 22 + { 23 + flake-file.inputs.neovim-nightly-overlay = { 24 + url = "github:nix-community/neovim-nightly-overlay"; 25 + inputs.nixpkgs.follows = "nixpkgs"; 26 + inputs.flake-parts.follows = "flake-parts"; 27 + }; 28 + 29 + den.default.includes = [ 30 + den._.self' 31 + den._.inputs' 32 + ]; 33 + 34 + den.aspects.rockhopper.nixos.imports = [ testModule ]; 35 + den.aspects.cam.homeManager.imports = [ testModule ]; 36 + 37 + flake.checks.x86_64-linux = withSystem "x86_64-linux" ( 38 + { 39 + checkCond, 40 + rockhopper, 41 + cam, 42 + self', 43 + inputs', 44 + ... 45 + }: 46 + { 47 + special-args-self-nixos = checkCond "self' provides same package to nixos" ( 48 + rockhopper.config.specialArgsTest.test-package == self'.packages.hello 49 + ); 50 + 51 + special-args-inputs-nixos = checkCond "inputs' provides same package to nixos" ( 52 + rockhopper.config.specialArgsTest.neovim-package == inputs'.neovim-nightly-overlay.packages.neovim 53 + ); 54 + 55 + special-args-self-hm = checkCond "self' provides same package to home-manager" ( 56 + cam.config.specialArgsTest.test-package == self'.packages.hello 57 + ); 58 + 59 + special-args-inputs-hm = checkCond "inputs' provides same package to home-manager" ( 60 + cam.config.specialArgsTest.neovim-package == inputs'.neovim-nightly-overlay.packages.neovim 61 + ); 62 + } 63 + ); 64 + 65 + perSystem = 66 + { pkgs, ... }: 67 + { 68 + packages.hello = pkgs.hello; 69 + }; 70 + }
+31
templates/ci/modules/standalone-hm-special-args-osconfig.nix
··· 1 + let 2 + 3 + # Example: luke standalone home-manager has access to rockhopper osConfig specialArg. 4 + os-conditional-hm = 5 + { home, ... }: 6 + { 7 + # access osConfig, wired via extraSpecialArgs in homes.nix. 8 + homeManager = 9 + { osConfig, ... }: 10 + { 11 + programs.bat.enable = osConfig.programs.${home.programToDependOn}.enable; 12 + }; 13 + }; 14 + in 15 + { 16 + 17 + # Example: standalone-hm config depends on osConfig (non-recursive) 18 + # NOTE: this will only work for standalone hm, and not for hosted hm 19 + # since a hosted hm configuration cannot depend on the os configuration. 20 + den.aspects.luke.includes = [ 21 + os-conditional-hm 22 + ]; 23 + 24 + perSystem = 25 + { checkCond, luke, ... }: 26 + { 27 + checks.luke-hm-depends-on-osConfig = checkCond "standalone hm can depend on osConfig" ( 28 + luke.config.programs.bat.enable 29 + ); 30 + }; 31 + }
+50
templates/ci/modules/top-level-parametric.nix
··· 1 + # it is possible for top-level aspects directly under 2 + # den.aspects to take a context argument. 3 + { den, lib, ... }: 4 + let 5 + # A module to test that toplevel had context. 6 + topLevel = name: { 7 + config.tops = name; 8 + options.tops = lib.mkOption { type = lib.types.str; }; 9 + }; 10 + in 11 + { 12 + 13 + den.aspects.toplevel-user = 14 + { user, ... }: 15 + { 16 + nixos.imports = [ (topLevel user.name) ]; 17 + }; 18 + 19 + den.aspects.toplevel-host = 20 + { host, ... }: 21 + { 22 + homeManager.imports = [ (topLevel host.name) ]; 23 + }; 24 + 25 + den.aspects.rockhopper.includes = [ 26 + den.aspects.toplevel-host 27 + ]; 28 + 29 + den.aspects.alice.includes = [ 30 + den.aspects.toplevel-user 31 + ]; 32 + 33 + perSystem = 34 + { 35 + checkCond, 36 + alice-at-rockhopper, 37 + rockhopper, 38 + ... 39 + }: 40 + { 41 + checks.alice-toplevel-user = checkCond "alice toplevel param aspect" ( 42 + rockhopper.config.tops == "alice" 43 + ); 44 + 45 + checks.alice-toplevel-host = checkCond "alice toplevel param aspect" ( 46 + alice-at-rockhopper.tops == "rockhopper" 47 + ); 48 + }; 49 + 50 + }
+25
templates/ci/modules/unfree.nix
··· 1 + { den, ... }: 2 + 3 + let 4 + codeAspect = { 5 + includes = [ (den._.unfree [ "vscode" ]) ]; 6 + homeManager.programs.vscode.enable = true; 7 + }; 8 + discordAspect = { 9 + includes = [ 10 + (den._.unfree [ "discord" ]) 11 + ]; 12 + homeManager = 13 + { pkgs, ... }: 14 + { 15 + home.packages = [ pkgs.discord ]; 16 + }; 17 + }; 18 + in 19 + { 20 + # cam uses unfree vscode and discord loaded from different aspects. 21 + den.aspects.cam.includes = [ 22 + codeAspect 23 + discordAspect 24 + ]; 25 + }
+12
templates/ci/modules/user-configures-hosts.nix
··· 1 + { 2 + # Example: user provides static config to all its nixos hosts. 3 + den.aspects.alice.nixos.users.users.alice.description = "Alice Q. User"; 4 + 5 + perSystem = 6 + { checkCond, rockhopper, ... }: 7 + { 8 + checks.user-contributes-to-host = checkCond "alice.nixos sets on rockhopper host" ( 9 + rockhopper.config.users.users.alice.description == "Alice Q. User" 10 + ); 11 + }; 12 + }
+12
templates/ci/modules/user-home-defaults.nix
··· 1 + { 2 + # globally enable fish on all homes ever. 3 + den.default.homeManager.programs.fish.enable = true; 4 + 5 + perSystem = 6 + { checkCond, alice-at-rockhopper, ... }: 7 + { 8 + checks.alice-hm-fish-enabled-by-default = checkCond "home-managed fish for alice" ( 9 + alice-at-rockhopper.programs.fish.enable 10 + ); 11 + }; 12 + }
+38
templates/ci/modules/user-host-conditional-os.nix
··· 1 + { lib, ... }: 2 + let 3 + 4 + # Example: configuration that depends on both host and user. provides anytime { user, host } is in context. 5 + user-to-host-conditional = 6 + { user, host, ... }: 7 + if user.userName == "alice" && !lib.hasSuffix "darwin" host.system then 8 + { 9 + nixos.programs.tmux.enable = true; 10 + } 11 + else 12 + { }; 13 + in 14 + { 15 + 16 + # Example: user provides parametric host configuration. 17 + den.aspects.alice.includes = [ 18 + user-to-host-conditional 19 + ]; 20 + 21 + perSystem = 22 + { 23 + checkCond, 24 + rockhopper, 25 + honeycrisp, 26 + ... 27 + }: 28 + { 29 + checks.alice-os-tmux-enabled-on = checkCond "os tmux for hosts having alice" ( 30 + rockhopper.config.programs.tmux.enable 31 + ); 32 + checks.alice-os-tmux-enabled-off = checkCond "os tmux for hosts having alice" ( 33 + !honeycrisp.config.programs.tmux.enable 34 + ); 35 + 36 + }; 37 + 38 + }
+17
templates/ci/modules/user-shell.nix
··· 1 + { den, lib, ... }: 2 + { 3 + 4 + den.aspects.will.includes = [ 5 + # will has always loved red snappers 6 + (den._.user-shell "fish") 7 + ]; 8 + 9 + perSystem = 10 + { checkCond, adelie, ... }: 11 + { 12 + checks.will-always-love-you = checkCond "red-snapper fish is default shell" ( 13 + "fish" == lib.getName adelie.config.users.users.will.shell 14 + ); 15 + }; 16 + 17 + }
+13
templates/ci/modules/user-specific-hm-config.nix
··· 1 + { 2 + # Example: enable helix for alice on all its home-managed hosts. 3 + den.aspects.alice.homeManager.programs.helix.enable = true; 4 + 5 + perSystem = 6 + { checkCond, alice-at-rockhopper, ... }: 7 + { 8 + checks.alice-hm-helix-enabled-by-user = checkCond "home-managed helix for alice" ( 9 + alice-at-rockhopper.programs.helix.enable 10 + ); 11 + }; 12 + 13 + }
+16
templates/ci/modules/vm-bootable.nix
··· 1 + let 2 + # Example: A static aspect for vm installers. 3 + vm-bootable = { 4 + nixos = 5 + { modulesPath, ... }: 6 + { 7 + imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") ]; 8 + }; 9 + }; 10 + in 11 + { 12 + den.default.includes = [ 13 + # Example: static aspect 14 + vm-bootable 15 + ]; 16 + }
+6
templates/ci/non-dendritic/hosts/honeycrisp/_darwin/something.nix
··· 1 + # this is a non-dendritic darwin class module file. 2 + # automatically discovered by `den.import-tree` as enabled in auto-imports.nix 3 + { ... }: 4 + { 5 + # see nix-darwin options. 6 + }
+14
templates/ci/non-dendritic/hosts/rockhopper/_nixos/hardware-auto-generated.nix
··· 1 + # this is a non-dendritic nix class module file. 2 + # automatically discovered by `den.import-tree` as enabled in auto-imports.nix 3 + # 4 + # USER TODO: Remove this file. 5 + # suppose this file was auto-generated by nixos-generate-config or some other hardware tooling. 6 + { lib, ... }: 7 + { 8 + # used in CI to test this file was actually imported. 9 + options.auto-imported = lib.mkOption { 10 + readOnly = true; 11 + type = lib.types.bool; 12 + default = true; 13 + }; 14 + }
+12
templates/ci/provider/flake.nix
··· 1 + { 2 + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 3 + 4 + inputs = { 5 + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 + flake-parts.url = "github:hercules-ci/flake-parts"; 7 + flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 8 + flake-aspects.url = "github:vic/flake-aspects"; 9 + import-tree.url = "github:vic/import-tree"; 10 + den.url = "github:vic/den"; 11 + }; 12 + }
+28
templates/ci/provider/modules/den.nix
··· 1 + { inputs, ... }: 2 + { 3 + systems = [ 4 + "x86_64-linux" 5 + "aarch64-darwin" 6 + ]; 7 + 8 + imports = [ 9 + inputs.den.flakeModule 10 + (inputs.den.namespace "provider" true) 11 + ]; 12 + 13 + provider.tools._.dev._.editors = { 14 + description = "Editor configurations from provider flake"; 15 + nixos.environment.variables.PROVIDER_EDITOR = "vim"; 16 + homeManager = 17 + { pkgs, ... }: 18 + { 19 + home.packages = [ pkgs.vim ]; 20 + }; 21 + }; 22 + 23 + provider.tools._.dev._.shells = { 24 + description = "Shell configurations from provider flake"; 25 + nixos.environment.variables.PROVIDER_SHELL = "fish"; 26 + nixos.environment.systemPackages = [ ]; 27 + }; 28 + }
+1 -17
templates/default/README.md
··· 16 16 nix flake check 17 17 ``` 18 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. 19 + - Edit [modules/hosts.nix](modules/hosts.nix)
-21
templates/default/flake.lock
··· 1 1 { 2 2 "nodes": { 3 - "darwin": { 4 - "inputs": { 5 - "nixpkgs": [ 6 - "nixpkgs" 7 - ] 8 - }, 9 - "locked": { 10 - "lastModified": 1762627886, 11 - "narHash": "sha256-/QLk1bzmbcqJt9sU43+y/3tHtXhAy0l8Ck0MoO2+evQ=", 12 - "owner": "nix-darwin", 13 - "repo": "nix-darwin", 14 - "rev": "5125a3cd414dc98bbe2c528227aa6b62ee61f733", 15 - "type": "github" 16 - }, 17 - "original": { 18 - "owner": "nix-darwin", 19 - "repo": "nix-darwin", 20 - "type": "github" 21 - } 22 - }, 23 3 "den": { 24 4 "locked": { 25 5 "lastModified": 1763707606, ··· 138 118 }, 139 119 "root": { 140 120 "inputs": { 141 - "darwin": "darwin", 142 121 "den": "den", 143 122 "flake-aspects": "flake-aspects", 144 123 "flake-file": "flake-file",
-4
templates/default/flake.nix
··· 5 5 outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 6 7 7 inputs = { 8 - darwin = { 9 - inputs.nixpkgs.follows = "nixpkgs"; 10 - url = "github:nix-darwin/nix-darwin"; 11 - }; 12 8 den.url = "github:vic/den"; 13 9 flake-aspects.url = "github:vic/flake-aspects"; 14 10 flake-file.url = "github:vic/flake-file";
-71
templates/default/modules/aspects/alice.nix
··· 1 - { den, eg, ... }: 2 - { 3 - den.aspects.alice = { 4 - 5 - # Alice can include other aspects. 6 - # For small, private one-shot aspects, use let-bindings like here. 7 - # for more complex or re-usable ones, define on their own modules, 8 - # as part of any aspect-subtree. 9 - includes = 10 - let 11 - # hack for nixf linter to keep findFile :/ 12 - unused = den.lib.take.unused __findFile; 13 - __findFile = unused den.lib.__findFile; 14 - 15 - customEmacs.homeManager = 16 - { pkgs, ... }: 17 - { 18 - programs.emacs.enable = true; 19 - programs.emacs.package = pkgs.emacs30-nox; 20 - }; 21 - in 22 - [ 23 - # from local bindings. 24 - customEmacs 25 - # from the aspect tree, cooper example is defined bellow 26 - den.aspects.cooper 27 - den.aspects.setHost 28 - # from the `eg` namespace. 29 - eg.autologin 30 - # den included batteries that provide common configs. 31 - <den/primary-user> # alice is admin always. 32 - (<den/user-shell> "fish") # default user shell 33 - ]; 34 - 35 - # Alice configures NixOS hosts it lives on. 36 - nixos = 37 - { pkgs, ... }: 38 - { 39 - users.users.alice.packages = [ pkgs.vim ]; 40 - }; 41 - 42 - # Alice home-manager. 43 - homeManager = 44 - { pkgs, ... }: 45 - { 46 - home.packages = [ pkgs.htop ]; 47 - }; 48 - 49 - # <user>.provides.<host>, via eg/routes.nix 50 - provides.igloo = 51 - { host, ... }: 52 - { 53 - nixos.programs.nh.enable = host.name == "igloo"; 54 - }; 55 - }; 56 - 57 - # This is a context-aware aspect, that emits configurations 58 - # **anytime** at least the `user` data is in context. 59 - # read more at https://vic.github.io/den/context-aware.html 60 - den.aspects.cooper = 61 - { user, ... }: 62 - { 63 - nixos.users.users.${user.userName}.description = "Alice Cooper"; 64 - }; 65 - 66 - den.aspects.setHost = 67 - { host, ... }: 68 - { 69 - networking.hostName = host.hostName; 70 - }; 71 - }
-47
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 - # ${user}.provides.${host} and ${host}.provides.${user} 20 - <eg/routes> 21 - 22 - # Enable home-manager on all hosts. 23 - <den/home-manager> 24 - 25 - # Automatically create the user on host. 26 - <den/define-user> 27 - 28 - # Disable booting when running on CI on all NixOS hosts. 29 - (if config ? _module.args.CI then <eg/ci-no-boot> else { }) 30 - 31 - # NOTE: be cautious when adding fully parametric functions to defaults. 32 - # defaults are included on EVERY host/user/home, and IF you are not careful 33 - # you could be duplicating config values. For example: 34 - # 35 - # # This will append 42 into foo option for the {host} and for EVERY {host,user} 36 - # ({ host, ... }: { nixos.foo = [ 42 ]; }) # DO-NOT-DO-THIS. 37 - # 38 - # # Instead try to be explicit if a function is intended for ONLY { host }. 39 - (den.lib.take.exactly ( 40 - { OS, host }: 41 - den.lib.take.unused OS { 42 - nixos.networking.hostName = host.hostName; 43 - } 44 - )) 45 - 46 - ]; 47 - }
-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 - }
-36
templates/default/modules/aspects/eg/routes.nix
··· 1 - # This example implements an aspect "routing" pattern. 2 - # 3 - # Unlike `den.default` which is `parametric.atLeast` 4 - # we use `parametric.fixedTo` here, which help us 5 - # propagate an already computed context to all includes. 6 - # 7 - # This aspect, when installed in a `parametric.atLeast` 8 - # will just forward the same context. 9 - # The `mutual` helper returns an static configuration which 10 - # is ignored by parametric aspects, thus allowing 11 - # non-existing aspects to be just ignored. 12 - # 13 - # Be sure to read: https://vic.github.io/den/dependencies.html 14 - # See usage at: defaults.nix, alice.nix, igloo.nix 15 - # 16 - { den, ... }: 17 - { 18 - # Usage: `den.default.includes [ eg.routes ]` 19 - eg.routes = 20 - let 21 - inherit (den.lib) parametric; 22 - 23 - # eg, `<user>._.<host>` and `<host>._.<user>` 24 - mutual = from: to: den.aspects.${from.aspect}._.${to.aspect} or { }; 25 - 26 - routes = 27 - { host, user, ... }@ctx: 28 - parametric.fixedTo ctx { 29 - includes = [ 30 - (mutual user host) 31 - (mutual host user) 32 - ]; 33 - }; 34 - in 35 - routes; 36 - }
-16
templates/default/modules/aspects/eg/vm-bootable.nix
··· 1 - let 2 - installer = variant: { 3 - nixos = 4 - { modulesPath, ... }: 5 - { 6 - imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-${variant}.nix") ]; 7 - }; 8 - }; 9 - in 10 - { 11 - # make USB/VM installers. 12 - eg.vm-bootable.provides = { 13 - tui = installer "minimal"; 14 - gui = installer "graphical-base"; 15 - }; 16 - }
-15
templates/default/modules/aspects/eg/vm.nix
··· 1 - { eg, ... }: 2 - { 3 - eg.vm.provides = { 4 - gui.includes = [ 5 - eg.vm 6 - eg.vm-bootable._.gui 7 - eg.xfce-desktop 8 - ]; 9 - 10 - tui.includes = [ 11 - eg.vm 12 - eg.vm-bootable._.tui 13 - ]; 14 - }; 15 - }
-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 - { 2 - den.aspects.igloo = { 3 - # igloo host provides some home-manager defaults to its users. 4 - homeManager.programs.direnv.enable = true; 5 - 6 - # NixOS configuration for igloo. 7 - nixos = 8 - { pkgs, ... }: 9 - { 10 - environment.systemPackages = [ pkgs.hello ]; 11 - }; 12 - 13 - # <host>.provides.<user>, via eg/routes.nix 14 - provides.alice = 15 - { user, ... }: 16 - { 17 - homeManager.programs.helix.enable = user.name == "alice"; 18 - }; 19 - }; 20 - }
-5
templates/default/modules/den.nix
··· 1 - { 2 - den.hosts.x86_64-linux.igloo.users.alice = { }; 3 - den.hosts.aarch64-darwin.apple.users.alice = { }; 4 - den.homes.x86_64-linux.alice = { }; 5 - }
+11 -3
templates/default/modules/dendritic.nix
··· 1 - { inputs, lib, ... }: 1 + { inputs, ... }: 2 2 { 3 - flake-file.inputs.flake-file.url = lib.mkDefault "github:vic/flake-file"; 4 - flake-file.inputs.den.url = lib.mkDefault "github:vic/den"; 5 3 imports = [ 6 4 (inputs.flake-file.flakeModules.dendritic or { }) 7 5 (inputs.den.flakeModules.dendritic or { }) 8 6 ]; 7 + 8 + # other inputs may be defined at a module using them. 9 + flake-file.inputs = { 10 + den.url = "github:vic/den"; 11 + flake-file.url = "github:vic/flake-file"; 12 + home-manager = { 13 + url = "github:nix-community/home-manager"; 14 + inputs.nixpkgs.follows = "nixpkgs"; 15 + }; 16 + }; 9 17 }
+19
templates/default/modules/hosts.nix
··· 1 + # defines all hosts + users + homes. 2 + # then config their aspects in as many files you want 3 + { 4 + # tux user at igloo host. 5 + den.hosts.x86_64-linux.igloo.users.tux = { }; 6 + 7 + # define an standalone home-manager for tux 8 + # den.homes.x86_64-linux.tux = { }; 9 + 10 + # be sure to add nix-darwin input for this: 11 + # den.hosts.aarch64-darwin.apple.users.alice = { }; 12 + 13 + # other hosts can also have user tux. 14 + # den.hosts.x86_64-linux.south = { 15 + # wsl = { }; # add nixos-wsl input for this. 16 + # users.tux = { }; 17 + # users.orca = { }; 18 + # }; 19 + }
+18
templates/default/modules/igloo.nix
··· 1 + { 2 + # host aspect 3 + den.aspects.igloo = { 4 + # host NixOS configuration 5 + nixos = 6 + { pkgs, ... }: 7 + { 8 + environment.systemPackages = [ pkgs.hello ]; 9 + }; 10 + 11 + # host provides default home environment for its users 12 + homeManager = 13 + { pkgs, ... }: 14 + { 15 + home.packages = [ pkgs.vim ]; 16 + }; 17 + }; 18 + }
-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 - { ... }: 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 - }
-15
templates/default/modules/namespace.nix
··· 1 - { inputs, den, ... }: 2 - { 3 - # create an `eg` (example!) namespace. (flake exposed) 4 - imports = [ (inputs.den.namespace "eg" true) ]; 5 - 6 - # you can have more than one namespace (false = not flake exposed) 7 - # imports = [ (inputs.den.namespace "my" false) ]; 8 - 9 - # you can also merge many namespaces from remote flakes. 10 - # keep in mind a namespace is defined only once, so give it an array: 11 - # imports = [ (inputs.den.namespace "ours" [inputs.ours inputs.theirs]) ]; 12 - 13 - # this line enables den angle brackets syntax in modules. 14 - _module.args.__findFile = den.lib.__findFile; 15 - }
-34
templates/default/modules/tests.nix
··· 1 - # Some CI checks to ensure this template always works. 2 - # Feel free to adapt or remove when this repo is yours. 3 - { inputs, ... }: 4 - { 5 - perSystem = 6 - { 7 - pkgs, 8 - self', 9 - lib, 10 - ... 11 - }: 12 - let 13 - checkCond = name: cond: pkgs.runCommandLocal name { } (if cond then "touch $out" else ""); 14 - apple = inputs.self.darwinConfigurations.apple.config; 15 - igloo = inputs.self.nixosConfigurations.igloo.config; 16 - alice-at-igloo = igloo.home-manager.users.alice; 17 - vmBuilds = !pkgs.stdenvNoCC.isLinux || builtins.pathExists (self'.packages.vm + "/bin/vm"); 18 - iglooBuilds = !pkgs.stdenvNoCC.isLinux || builtins.pathExists (igloo.system.build.toplevel); 19 - appleBuilds = !pkgs.stdenvNoCC.isDarwin || builtins.pathExists (apple.system.build.toplevel); 20 - in 21 - { 22 - checks."igloo builds" = checkCond "igloo-builds" iglooBuilds; 23 - checks."apple builds" = checkCond "apple-builds" appleBuilds; 24 - checks."vm builds" = checkCond "vm-builds" vmBuilds; 25 - 26 - checks."alice enabled igloo nh" = checkCond "alice.provides.igloo" igloo.programs.nh.enable; 27 - checks."igloo enabled alice helix" = 28 - checkCond "igloo.provides.alice" alice-at-igloo.programs.helix.enable; 29 - 30 - checks."alice-custom-emacs" = checkCond "hm.programs.emacs.package" ( 31 - "emacs-nox" == lib.getName alice-at-igloo.programs.emacs.package 32 - ); 33 - }; 34 - }
+20
templates/default/modules/tux.nix
··· 1 + { den, ... }: 2 + { 3 + # user aspect 4 + den.aspects.tux = { 5 + includes = [ 6 + den.provides.primary-user 7 + (den.provides.user-shell "fish") 8 + ]; 9 + 10 + homeManager = 11 + { pkgs, ... }: 12 + { 13 + home.packages = [ pkgs.htop ]; 14 + }; 15 + 16 + # user can provide NixOS configurations 17 + # to any host it is included on 18 + # nixos = { pkgs, ... }: { }; 19 + }; 20 + }
-22
templates/default/modules/vm.nix
··· 1 - # enables `nix run .#vm`. it is very useful to have a VM 2 - # you can edit your config and launch the VM to test stuff 3 - # instead of having to reboot each time. 4 - { inputs, eg, ... }: 5 - { 6 - 7 - den.aspects.igloo.includes = [ 8 - eg.vm._.gui 9 - # eg.vm._.tui 10 - ]; 11 - 12 - perSystem = 13 - { pkgs, ... }: 14 - { 15 - packages.vm = pkgs.writeShellApplication { 16 - name = "vm"; 17 - text = '' 18 - ${inputs.self.nixosConfigurations.igloo.config.system.build.vm}/bin/run-igloo-vm "$@" 19 - ''; 20 - }; 21 - }; 22 - }
+27
templates/example/.github/workflows/test.yml
··· 1 + on: 2 + pull_request: 3 + push: 4 + concurrency: 5 + group: ${{ github.workflow }}-${{ github.ref }} 6 + cancel-in-progress: true 7 + jobs: 8 + flake-check: 9 + strategy: 10 + matrix: 11 + os: [ubuntu-latest, macos-latest] 12 + name: Nix flake check ${{matrix.os}} 13 + runs-on: ${{matrix.os}} 14 + steps: 15 + - uses: wimpysworld/nothing-but-nix@main 16 + if: matrix.os == 'ubuntu-latest' 17 + - uses: DeterminateSystems/nix-installer-action@main 18 + - uses: DeterminateSystems/magic-nix-cache-action@main 19 + - uses: actions/checkout@v5 20 + - run: nix flake metadata 21 + - run: | 22 + cat <<-EOF > modules/ci-runtime.nix 23 + { 24 + _module.args.CI = true; 25 + } 26 + EOF 27 + - run: nix flake check
+38
templates/example/README.md
··· 1 + # Examples 2 + 3 + This template provides some basic examples of how to use Den features. 4 + However, you will learn more by reading templates/ci which tests all of Den. 5 + 6 + Steps you can follow after cloning this template: 7 + 8 + - Be sure to read the [den documentation](https://vic.github.io/den) 9 + 10 + - Update den input. 11 + 12 + ```console 13 + nix flake update den 14 + ``` 15 + 16 + - Run checks to test everything works. 17 + 18 + ```console 19 + nix flake check 20 + ``` 21 + 22 + - Read [modules/den.nix](modules/den.nix) where hosts and homes definitions are for this example. 23 + 24 + - Read [modules/namespace.nix](modules/namespace.nix) where a new `eg` (an example) aspects namespace is created. 25 + 26 + - Read [modules/aspects/igloo.nix](modules/aspects/igloo.nix) where the `igloo` host is configured. 27 + 28 + - Read [modules/aspects/alice.nix](modules/aspects/alice.nix) where the `alice` user is configured. 29 + 30 + - Run the VM. 31 + 32 + ```console 33 + nix run .#vm 34 + ``` 35 + 36 + - Edit and run VM loop. 37 + 38 + Feel free to add more aspects, organize things to your liking.
+173
templates/example/flake.lock
··· 1 + { 2 + "nodes": { 3 + "darwin": { 4 + "inputs": { 5 + "nixpkgs": [ 6 + "nixpkgs" 7 + ] 8 + }, 9 + "locked": { 10 + "lastModified": 1762627886, 11 + "narHash": "sha256-/QLk1bzmbcqJt9sU43+y/3tHtXhAy0l8Ck0MoO2+evQ=", 12 + "owner": "nix-darwin", 13 + "repo": "nix-darwin", 14 + "rev": "5125a3cd414dc98bbe2c528227aa6b62ee61f733", 15 + "type": "github" 16 + }, 17 + "original": { 18 + "owner": "nix-darwin", 19 + "repo": "nix-darwin", 20 + "type": "github" 21 + } 22 + }, 23 + "den": { 24 + "locked": { 25 + "lastModified": 1763707606, 26 + "narHash": "sha256-l9v3NNdKj3GJvV5LhzsWDs4Sl2bg0tuKNFFkMeFvUWo=", 27 + "owner": "vic", 28 + "repo": "den", 29 + "rev": "8164e0d89c59839d67757bc9a1fb61770dc6e8b7", 30 + "type": "github" 31 + }, 32 + "original": { 33 + "owner": "vic", 34 + "repo": "den", 35 + "type": "github" 36 + } 37 + }, 38 + "flake-aspects": { 39 + "locked": { 40 + "lastModified": 1769717274, 41 + "narHash": "sha256-U15OaMr9AcJiB1wW2uCFzFO+DnQ3jJSvln+ZR/+Q0vE=", 42 + "owner": "vic", 43 + "repo": "flake-aspects", 44 + "rev": "a35ed5efc9a629694d659d606230ba18a76cefaa", 45 + "type": "github" 46 + }, 47 + "original": { 48 + "owner": "vic", 49 + "repo": "flake-aspects", 50 + "type": "github" 51 + } 52 + }, 53 + "flake-file": { 54 + "locked": { 55 + "lastModified": 1763706734, 56 + "narHash": "sha256-kR1Rrh9evfiJaTb6ufWCSk6GMtrnPKFydqQUV0Bb4Eg=", 57 + "owner": "vic", 58 + "repo": "flake-file", 59 + "rev": "9af20d5e62c94b658b4d0671829393c1b8bb0b3e", 60 + "type": "github" 61 + }, 62 + "original": { 63 + "owner": "vic", 64 + "repo": "flake-file", 65 + "type": "github" 66 + } 67 + }, 68 + "flake-parts": { 69 + "inputs": { 70 + "nixpkgs-lib": [ 71 + "nixpkgs-lib" 72 + ] 73 + }, 74 + "locked": { 75 + "lastModified": 1762810396, 76 + "narHash": "sha256-dxFVgQPG+R72dkhXTtqUm7KpxElw3u6E+YlQ2WaDgt8=", 77 + "owner": "hercules-ci", 78 + "repo": "flake-parts", 79 + "rev": "0bdadb1b265fb4143a75bd1ec7d8c915898a9923", 80 + "type": "github" 81 + }, 82 + "original": { 83 + "owner": "hercules-ci", 84 + "repo": "flake-parts", 85 + "type": "github" 86 + } 87 + }, 88 + "home-manager": { 89 + "inputs": { 90 + "nixpkgs": [ 91 + "nixpkgs" 92 + ] 93 + }, 94 + "locked": { 95 + "lastModified": 1762787259, 96 + "narHash": "sha256-t2U/GLLXHa2+kJkwnFNRVc2fEJ/lUfyZXBE5iKzJdcs=", 97 + "owner": "nix-community", 98 + "repo": "home-manager", 99 + "rev": "37a3d97f2873e0f68711117c34d04b7c7ead8f4e", 100 + "type": "github" 101 + }, 102 + "original": { 103 + "owner": "nix-community", 104 + "repo": "home-manager", 105 + "type": "github" 106 + } 107 + }, 108 + "import-tree": { 109 + "locked": { 110 + "lastModified": 1762327901, 111 + "narHash": "sha256-AJ96FNj50DU0bTyIzAPkPOjCZTHqjURVjok8qoXvmqM=", 112 + "owner": "vic", 113 + "repo": "import-tree", 114 + "rev": "90fa129798be99cde036b78658e89475710966a1", 115 + "type": "github" 116 + }, 117 + "original": { 118 + "owner": "vic", 119 + "repo": "import-tree", 120 + "type": "github" 121 + } 122 + }, 123 + "nixpkgs": { 124 + "locked": { 125 + "lastModified": 1762482733, 126 + "narHash": "sha256-g/da4FzvckvbiZT075Sb1/YDNDr+tGQgh4N8i5ceYMg=", 127 + "owner": "nixos", 128 + "repo": "nixpkgs", 129 + "rev": "e1ebeec86b771e9d387dd02d82ffdc77ac753abc", 130 + "type": "github" 131 + }, 132 + "original": { 133 + "owner": "nixos", 134 + "ref": "nixpkgs-unstable", 135 + "repo": "nixpkgs", 136 + "type": "github" 137 + } 138 + }, 139 + "root": { 140 + "inputs": { 141 + "darwin": "darwin", 142 + "den": "den", 143 + "flake-aspects": "flake-aspects", 144 + "flake-file": "flake-file", 145 + "flake-parts": "flake-parts", 146 + "home-manager": "home-manager", 147 + "import-tree": "import-tree", 148 + "nixpkgs": "nixpkgs", 149 + "nixpkgs-lib": [ 150 + "nixpkgs" 151 + ], 152 + "systems": "systems" 153 + } 154 + }, 155 + "systems": { 156 + "locked": { 157 + "lastModified": 1681028828, 158 + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 159 + "owner": "nix-systems", 160 + "repo": "default", 161 + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 162 + "type": "github" 163 + }, 164 + "original": { 165 + "owner": "nix-systems", 166 + "repo": "default", 167 + "type": "github" 168 + } 169 + } 170 + }, 171 + "root": "root", 172 + "version": 7 173 + }
+29
templates/example/flake.nix
··· 1 + # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 + # Use `nix run .#write-flake` to regenerate it. 3 + { 4 + 5 + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 + 7 + inputs = { 8 + darwin = { 9 + inputs.nixpkgs.follows = "nixpkgs"; 10 + url = "github:nix-darwin/nix-darwin"; 11 + }; 12 + den.url = "github:vic/den"; 13 + flake-aspects.url = "github:vic/flake-aspects"; 14 + flake-file.url = "github:vic/flake-file"; 15 + flake-parts = { 16 + inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 17 + url = "github:hercules-ci/flake-parts"; 18 + }; 19 + home-manager = { 20 + inputs.nixpkgs.follows = "nixpkgs"; 21 + url = "github:nix-community/home-manager"; 22 + }; 23 + import-tree.url = "github:vic/import-tree"; 24 + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 25 + nixpkgs-lib.follows = "nixpkgs"; 26 + systems.url = "github:nix-systems/default"; 27 + }; 28 + 29 + }
+71
templates/example/modules/aspects/alice.nix
··· 1 + { den, eg, ... }: 2 + { 3 + den.aspects.alice = { 4 + 5 + # Alice can include other aspects. 6 + # For small, private one-shot aspects, use let-bindings like here. 7 + # for more complex or re-usable ones, define on their own modules, 8 + # as part of any aspect-subtree. 9 + includes = 10 + let 11 + # hack for nixf linter to keep findFile :/ 12 + unused = den.lib.take.unused __findFile; 13 + __findFile = unused den.lib.__findFile; 14 + 15 + customEmacs.homeManager = 16 + { pkgs, ... }: 17 + { 18 + programs.emacs.enable = true; 19 + programs.emacs.package = pkgs.emacs30-nox; 20 + }; 21 + in 22 + [ 23 + # from local bindings. 24 + customEmacs 25 + # from the aspect tree, cooper example is defined bellow 26 + den.aspects.cooper 27 + den.aspects.setHost 28 + # from the `eg` namespace. 29 + eg.autologin 30 + # den included batteries that provide common configs. 31 + <den/primary-user> # alice is admin always. 32 + (<den/user-shell> "fish") # default user shell 33 + ]; 34 + 35 + # Alice configures NixOS hosts it lives on. 36 + nixos = 37 + { pkgs, ... }: 38 + { 39 + users.users.alice.packages = [ pkgs.vim ]; 40 + }; 41 + 42 + # Alice home-manager. 43 + homeManager = 44 + { pkgs, ... }: 45 + { 46 + home.packages = [ pkgs.htop ]; 47 + }; 48 + 49 + # <user>.provides.<host>, via eg/routes.nix 50 + provides.igloo = 51 + { host, ... }: 52 + { 53 + nixos.programs.nh.enable = host.name == "igloo"; 54 + }; 55 + }; 56 + 57 + # This is a context-aware aspect, that emits configurations 58 + # **anytime** at least the `user` data is in context. 59 + # read more at https://vic.github.io/den/context-aware.html 60 + den.aspects.cooper = 61 + { user, ... }: 62 + { 63 + nixos.users.users.${user.userName}.description = "Alice Cooper"; 64 + }; 65 + 66 + den.aspects.setHost = 67 + { host, ... }: 68 + { 69 + networking.hostName = host.hostName; 70 + }; 71 + }
+47
templates/example/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 + # ${user}.provides.${host} and ${host}.provides.${user} 20 + <eg/routes> 21 + 22 + # Enable home-manager on all hosts. 23 + <den/home-manager> 24 + 25 + # Automatically create the user on host. 26 + <den/define-user> 27 + 28 + # Disable booting when running on CI on all NixOS hosts. 29 + (if config ? _module.args.CI then <eg/ci-no-boot> else { }) 30 + 31 + # NOTE: be cautious when adding fully parametric functions to defaults. 32 + # defaults are included on EVERY host/user/home, and IF you are not careful 33 + # you could be duplicating config values. For example: 34 + # 35 + # # This will append 42 into foo option for the {host} and for EVERY {host,user} 36 + # ({ host, ... }: { nixos.foo = [ 42 ]; }) # DO-NOT-DO-THIS. 37 + # 38 + # # Instead try to be explicit if a function is intended for ONLY { host }. 39 + (den.lib.take.exactly ( 40 + { OS, host }: 41 + den.lib.take.unused OS { 42 + nixos.networking.hostName = host.hostName; 43 + } 44 + )) 45 + 46 + ]; 47 + }
+15
templates/example/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/example/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 + }
+36
templates/example/modules/aspects/eg/routes.nix
··· 1 + # This example implements an aspect "routing" pattern. 2 + # 3 + # Unlike `den.default` which is `parametric.atLeast` 4 + # we use `parametric.fixedTo` here, which help us 5 + # propagate an already computed context to all includes. 6 + # 7 + # This aspect, when installed in a `parametric.atLeast` 8 + # will just forward the same context. 9 + # The `mutual` helper returns an static configuration which 10 + # is ignored by parametric aspects, thus allowing 11 + # non-existing aspects to be just ignored. 12 + # 13 + # Be sure to read: https://vic.github.io/den/dependencies.html 14 + # See usage at: defaults.nix, alice.nix, igloo.nix 15 + # 16 + { den, ... }: 17 + { 18 + # Usage: `den.default.includes [ eg.routes ]` 19 + eg.routes = 20 + let 21 + inherit (den.lib) parametric; 22 + 23 + # eg, `<user>._.<host>` and `<host>._.<user>` 24 + mutual = from: to: den.aspects.${from.aspect}._.${to.aspect} or { }; 25 + 26 + routes = 27 + { host, user, ... }@ctx: 28 + parametric.fixedTo ctx { 29 + includes = [ 30 + (mutual user host) 31 + (mutual host user) 32 + ]; 33 + }; 34 + in 35 + routes; 36 + }
+16
templates/example/modules/aspects/eg/vm-bootable.nix
··· 1 + let 2 + installer = variant: { 3 + nixos = 4 + { modulesPath, ... }: 5 + { 6 + imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-${variant}.nix") ]; 7 + }; 8 + }; 9 + in 10 + { 11 + # make USB/VM installers. 12 + eg.vm-bootable.provides = { 13 + tui = installer "minimal"; 14 + gui = installer "graphical-base"; 15 + }; 16 + }
+15
templates/example/modules/aspects/eg/vm.nix
··· 1 + { eg, ... }: 2 + { 3 + eg.vm.provides = { 4 + gui.includes = [ 5 + eg.vm 6 + eg.vm-bootable._.gui 7 + eg.xfce-desktop 8 + ]; 9 + 10 + tui.includes = [ 11 + eg.vm 12 + eg.vm-bootable._.tui 13 + ]; 14 + }; 15 + }
+19
templates/example/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/example/modules/aspects/igloo.nix
··· 1 + { 2 + den.aspects.igloo = { 3 + # igloo host provides some home-manager defaults to its users. 4 + homeManager.programs.direnv.enable = true; 5 + 6 + # NixOS configuration for igloo. 7 + nixos = 8 + { pkgs, ... }: 9 + { 10 + environment.systemPackages = [ pkgs.hello ]; 11 + }; 12 + 13 + # <host>.provides.<user>, via eg/routes.nix 14 + provides.alice = 15 + { user, ... }: 16 + { 17 + homeManager.programs.helix.enable = user.name == "alice"; 18 + }; 19 + }; 20 + }
+5
templates/example/modules/den.nix
··· 1 + { 2 + den.hosts.x86_64-linux.igloo.users.alice = { }; 3 + den.hosts.aarch64-darwin.apple.users.alice = { }; 4 + den.homes.x86_64-linux.alice = { }; 5 + }
+9
templates/example/modules/dendritic.nix
··· 1 + { inputs, lib, ... }: 2 + { 3 + flake-file.inputs.flake-file.url = lib.mkDefault "github:vic/flake-file"; 4 + flake-file.inputs.den.url = lib.mkDefault "github:vic/den"; 5 + imports = [ 6 + (inputs.flake-file.flakeModules.dendritic or { }) 7 + (inputs.den.flakeModules.dendritic or { }) 8 + ]; 9 + }
+37
templates/example/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 + { ... }: 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 + }
+15
templates/example/modules/namespace.nix
··· 1 + { inputs, den, ... }: 2 + { 3 + # create an `eg` (example!) namespace. (flake exposed) 4 + imports = [ (inputs.den.namespace "eg" true) ]; 5 + 6 + # you can have more than one namespace (false = not flake exposed) 7 + # imports = [ (inputs.den.namespace "my" false) ]; 8 + 9 + # you can also merge many namespaces from remote flakes. 10 + # keep in mind a namespace is defined only once, so give it an array: 11 + # imports = [ (inputs.den.namespace "ours" [inputs.ours inputs.theirs]) ]; 12 + 13 + # this line enables den angle brackets syntax in modules. 14 + _module.args.__findFile = den.lib.__findFile; 15 + }
+34
templates/example/modules/tests.nix
··· 1 + # Some CI checks to ensure this template always works. 2 + # Feel free to adapt or remove when this repo is yours. 3 + { inputs, ... }: 4 + { 5 + perSystem = 6 + { 7 + pkgs, 8 + self', 9 + lib, 10 + ... 11 + }: 12 + let 13 + checkCond = name: cond: pkgs.runCommandLocal name { } (if cond then "touch $out" else ""); 14 + apple = inputs.self.darwinConfigurations.apple.config; 15 + igloo = inputs.self.nixosConfigurations.igloo.config; 16 + alice-at-igloo = igloo.home-manager.users.alice; 17 + vmBuilds = !pkgs.stdenvNoCC.isLinux || builtins.pathExists (self'.packages.vm + "/bin/vm"); 18 + iglooBuilds = !pkgs.stdenvNoCC.isLinux || builtins.pathExists (igloo.system.build.toplevel); 19 + appleBuilds = !pkgs.stdenvNoCC.isDarwin || builtins.pathExists (apple.system.build.toplevel); 20 + in 21 + { 22 + checks."igloo builds" = checkCond "igloo-builds" iglooBuilds; 23 + checks."apple builds" = checkCond "apple-builds" appleBuilds; 24 + checks."vm builds" = checkCond "vm-builds" vmBuilds; 25 + 26 + checks."alice enabled igloo nh" = checkCond "alice.provides.igloo" igloo.programs.nh.enable; 27 + checks."igloo enabled alice helix" = 28 + checkCond "igloo.provides.alice" alice-at-igloo.programs.helix.enable; 29 + 30 + checks."alice-custom-emacs" = checkCond "hm.programs.emacs.package" ( 31 + "emacs-nox" == lib.getName alice-at-igloo.programs.emacs.package 32 + ); 33 + }; 34 + }
+22
templates/example/modules/vm.nix
··· 1 + # enables `nix run .#vm`. it is very useful to have a VM 2 + # you can edit your config and launch the VM to test stuff 3 + # instead of having to reboot each time. 4 + { inputs, eg, ... }: 5 + { 6 + 7 + den.aspects.igloo.includes = [ 8 + eg.vm._.gui 9 + # eg.vm._.tui 10 + ]; 11 + 12 + perSystem = 13 + { pkgs, ... }: 14 + { 15 + packages.vm = pkgs.writeShellApplication { 16 + name = "vm"; 17 + text = '' 18 + ${inputs.self.nixosConfigurations.igloo.config.system.build.vm}/bin/run-igloo-vm "$@" 19 + ''; 20 + }; 21 + }; 22 + }
-304
templates/examples/flake.lock
··· 1 - { 2 - "nodes": { 3 - "darwin": { 4 - "inputs": { 5 - "nixpkgs": [ 6 - "nixpkgs" 7 - ] 8 - }, 9 - "locked": { 10 - "lastModified": 1762039661, 11 - "narHash": "sha256-oM5BwAGE78IBLZn+AqxwH/saqwq3e926rNq5HmOulkc=", 12 - "owner": "nix-darwin", 13 - "repo": "nix-darwin", 14 - "rev": "c3c8c9f2a5ed43175ac4dc030308756620e6e4e4", 15 - "type": "github" 16 - }, 17 - "original": { 18 - "owner": "nix-darwin", 19 - "repo": "nix-darwin", 20 - "type": "github" 21 - } 22 - }, 23 - "den": { 24 - "locked": { 25 - "lastModified": 1767645236, 26 - "narHash": "sha256-VMrWett3fWRb0hQh9K1JUC3zV2OlV4zOajFZHGr1GPw=", 27 - "owner": "vic", 28 - "repo": "den", 29 - "rev": "e7837daa0ea0f03fba62a2653ce16314a7d9d1c8", 30 - "type": "github" 31 - }, 32 - "original": { 33 - "owner": "vic", 34 - "repo": "den", 35 - "type": "github" 36 - } 37 - }, 38 - "flake-aspects": { 39 - "locked": { 40 - "lastModified": 1769717274, 41 - "narHash": "sha256-U15OaMr9AcJiB1wW2uCFzFO+DnQ3jJSvln+ZR/+Q0vE=", 42 - "owner": "vic", 43 - "repo": "flake-aspects", 44 - "rev": "a35ed5efc9a629694d659d606230ba18a76cefaa", 45 - "type": "github" 46 - }, 47 - "original": { 48 - "owner": "vic", 49 - "repo": "flake-aspects", 50 - "type": "github" 51 - } 52 - }, 53 - "flake-file": { 54 - "locked": { 55 - "lastModified": 1763706734, 56 - "narHash": "sha256-kR1Rrh9evfiJaTb6ufWCSk6GMtrnPKFydqQUV0Bb4Eg=", 57 - "owner": "vic", 58 - "repo": "flake-file", 59 - "rev": "9af20d5e62c94b658b4d0671829393c1b8bb0b3e", 60 - "type": "github" 61 - }, 62 - "original": { 63 - "owner": "vic", 64 - "repo": "flake-file", 65 - "type": "github" 66 - } 67 - }, 68 - "flake-parts": { 69 - "inputs": { 70 - "nixpkgs-lib": [ 71 - "nixpkgs-lib" 72 - ] 73 - }, 74 - "locked": { 75 - "lastModified": 1762040540, 76 - "narHash": "sha256-z5PlZ47j50VNF3R+IMS9LmzI5fYRGY/Z5O5tol1c9I4=", 77 - "owner": "hercules-ci", 78 - "repo": "flake-parts", 79 - "rev": "0010412d62a25d959151790968765a70c436598b", 80 - "type": "github" 81 - }, 82 - "original": { 83 - "owner": "hercules-ci", 84 - "repo": "flake-parts", 85 - "type": "github" 86 - } 87 - }, 88 - "home-manager": { 89 - "inputs": { 90 - "nixpkgs": [ 91 - "nixpkgs" 92 - ] 93 - }, 94 - "locked": { 95 - "lastModified": 1762087455, 96 - "narHash": "sha256-hpbPma1eUKwLAmiVRoMgIHbHiIKFkcACobJLbDt6ABw=", 97 - "owner": "nix-community", 98 - "repo": "home-manager", 99 - "rev": "43e205606aeb253bfcee15fd8a4a01d8ce8384ca", 100 - "type": "github" 101 - }, 102 - "original": { 103 - "owner": "nix-community", 104 - "repo": "home-manager", 105 - "type": "github" 106 - } 107 - }, 108 - "home-manager-stable": { 109 - "inputs": { 110 - "nixpkgs": [ 111 - "nixpkgs-stable" 112 - ] 113 - }, 114 - "locked": { 115 - "lastModified": 1758463745, 116 - "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", 117 - "owner": "nix-community", 118 - "repo": "home-manager", 119 - "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", 120 - "type": "github" 121 - }, 122 - "original": { 123 - "owner": "nix-community", 124 - "ref": "release-25.05", 125 - "repo": "home-manager", 126 - "type": "github" 127 - } 128 - }, 129 - "import-tree": { 130 - "locked": { 131 - "lastModified": 1761120675, 132 - "narHash": "sha256-TEbh9zISiQcU82VwVoEbmXHnSGlUxTwvjJA9g9ErSDA=", 133 - "owner": "vic", 134 - "repo": "import-tree", 135 - "rev": "a037ed2a58fc0ebed9e93b9ef79b0646e648f719", 136 - "type": "github" 137 - }, 138 - "original": { 139 - "owner": "vic", 140 - "repo": "import-tree", 141 - "type": "github" 142 - } 143 - }, 144 - "neovim-nightly-overlay": { 145 - "inputs": { 146 - "flake-parts": [ 147 - "flake-parts" 148 - ], 149 - "neovim-src": "neovim-src", 150 - "nixpkgs": [ 151 - "nixpkgs" 152 - ] 153 - }, 154 - "locked": { 155 - "lastModified": 1766016290, 156 - "narHash": "sha256-YMf/PUyY4z7RlIe/Dzn1NnxZGS0Vp2eHxcMNWJM9q+A=", 157 - "owner": "nix-community", 158 - "repo": "neovim-nightly-overlay", 159 - "rev": "f7fbc4e3d4ccea45eaa5b187884592eb42dfdbbd", 160 - "type": "github" 161 - }, 162 - "original": { 163 - "owner": "nix-community", 164 - "repo": "neovim-nightly-overlay", 165 - "type": "github" 166 - } 167 - }, 168 - "neovim-src": { 169 - "flake": false, 170 - "locked": { 171 - "lastModified": 1766014002, 172 - "narHash": "sha256-KE/ufBGH8XFXTw3Vt1DrK1rQmAEp1Q+oyLQibX5UKO0=", 173 - "owner": "neovim", 174 - "repo": "neovim", 175 - "rev": "c172fd9f464d5766eab9071e8f4770504c920c05", 176 - "type": "github" 177 - }, 178 - "original": { 179 - "owner": "neovim", 180 - "repo": "neovim", 181 - "type": "github" 182 - } 183 - }, 184 - "nixos-wsl": { 185 - "inputs": { 186 - "flake-compat": [], 187 - "nixpkgs": [ 188 - "nixpkgs-stable" 189 - ] 190 - }, 191 - "locked": { 192 - "lastModified": 1761969132, 193 - "narHash": "sha256-0me4+e+1VxNuvySSw0voqMCWU/eUmTuth7f4+Q2jbUY=", 194 - "owner": "nix-community", 195 - "repo": "nixos-wsl", 196 - "rev": "761582d6ab431549fe1396d2cd681e3fe9376020", 197 - "type": "github" 198 - }, 199 - "original": { 200 - "owner": "nix-community", 201 - "repo": "nixos-wsl", 202 - "type": "github" 203 - } 204 - }, 205 - "nixpkgs": { 206 - "locked": { 207 - "lastModified": 1761880412, 208 - "narHash": "sha256-QoJjGd4NstnyOG4mm4KXF+weBzA2AH/7gn1Pmpfcb0A=", 209 - "owner": "nixos", 210 - "repo": "nixpkgs", 211 - "rev": "a7fc11be66bdfb5cdde611ee5ce381c183da8386", 212 - "type": "github" 213 - }, 214 - "original": { 215 - "owner": "nixos", 216 - "ref": "nixpkgs-unstable", 217 - "repo": "nixpkgs", 218 - "type": "github" 219 - } 220 - }, 221 - "nixpkgs-stable": { 222 - "locked": { 223 - "lastModified": 1762081535, 224 - "narHash": "sha256-+j+CUiaUoa87EhnSOqG5pwXdJWahP8vo6BE0ekssdzs=", 225 - "owner": "nixos", 226 - "repo": "nixpkgs", 227 - "rev": "2afc9d6e79b59ea9bcaf620d335623b0f7c2ce96", 228 - "type": "github" 229 - }, 230 - "original": { 231 - "owner": "nixos", 232 - "ref": "release-25.05", 233 - "repo": "nixpkgs", 234 - "type": "github" 235 - } 236 - }, 237 - "provider": { 238 - "inputs": { 239 - "den": [ 240 - "den" 241 - ], 242 - "flake-aspects": [ 243 - "flake-aspects" 244 - ], 245 - "flake-parts": [ 246 - "flake-parts" 247 - ], 248 - "import-tree": [ 249 - "import-tree" 250 - ], 251 - "nixpkgs": [ 252 - "nixpkgs" 253 - ] 254 - }, 255 - "locked": { 256 - "path": "./provider", 257 - "type": "path" 258 - }, 259 - "original": { 260 - "path": "./provider", 261 - "type": "path" 262 - }, 263 - "parent": [] 264 - }, 265 - "root": { 266 - "inputs": { 267 - "darwin": "darwin", 268 - "den": "den", 269 - "flake-aspects": "flake-aspects", 270 - "flake-file": "flake-file", 271 - "flake-parts": "flake-parts", 272 - "home-manager": "home-manager", 273 - "home-manager-stable": "home-manager-stable", 274 - "import-tree": "import-tree", 275 - "neovim-nightly-overlay": "neovim-nightly-overlay", 276 - "nixos-wsl": "nixos-wsl", 277 - "nixpkgs": "nixpkgs", 278 - "nixpkgs-lib": [ 279 - "nixpkgs" 280 - ], 281 - "nixpkgs-stable": "nixpkgs-stable", 282 - "provider": "provider", 283 - "systems": "systems" 284 - } 285 - }, 286 - "systems": { 287 - "locked": { 288 - "lastModified": 1681028828, 289 - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 290 - "owner": "nix-systems", 291 - "repo": "default", 292 - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 293 - "type": "github" 294 - }, 295 - "original": { 296 - "owner": "nix-systems", 297 - "repo": "default", 298 - "type": "github" 299 - } 300 - } 301 - }, 302 - "root": "root", 303 - "version": 7 304 - }
-58
templates/examples/flake.nix
··· 1 - # DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file. 2 - # Use `nix run .#write-flake` to regenerate it. 3 - { 4 - 5 - outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 6 - 7 - inputs = { 8 - darwin = { 9 - inputs.nixpkgs.follows = "nixpkgs"; 10 - url = "github:nix-darwin/nix-darwin"; 11 - }; 12 - den.url = "github:vic/den"; 13 - flake-aspects.url = "github:vic/flake-aspects"; 14 - flake-file.url = "github:vic/flake-file"; 15 - flake-parts = { 16 - inputs.nixpkgs-lib.follows = "nixpkgs-lib"; 17 - url = "github:hercules-ci/flake-parts"; 18 - }; 19 - home-manager = { 20 - inputs.nixpkgs.follows = "nixpkgs"; 21 - url = "github:nix-community/home-manager"; 22 - }; 23 - home-manager-stable = { 24 - inputs.nixpkgs.follows = "nixpkgs-stable"; 25 - url = "github:nix-community/home-manager/release-25.05"; 26 - }; 27 - import-tree.url = "github:vic/import-tree"; 28 - neovim-nightly-overlay = { 29 - inputs = { 30 - flake-parts.follows = "flake-parts"; 31 - nixpkgs.follows = "nixpkgs"; 32 - }; 33 - url = "github:nix-community/neovim-nightly-overlay"; 34 - }; 35 - nixos-wsl = { 36 - inputs = { 37 - flake-compat.follows = ""; 38 - nixpkgs.follows = "nixpkgs-stable"; 39 - }; 40 - url = "github:nix-community/nixos-wsl"; 41 - }; 42 - nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 43 - nixpkgs-lib.follows = "nixpkgs"; 44 - nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05"; 45 - provider = { 46 - inputs = { 47 - den.follows = "den"; 48 - flake-aspects.follows = "flake-aspects"; 49 - flake-parts.follows = "flake-parts"; 50 - import-tree.follows = "import-tree"; 51 - nixpkgs.follows = "nixpkgs"; 52 - }; 53 - url = "path:./provider"; 54 - }; 55 - systems.url = "github:nix-systems/default"; 56 - }; 57 - 58 - }
-5
templates/examples/modules/_example/README.md
··· 1 - User TODO: REMOVE this directory (or disable its import from den.nix) 2 - 3 - It is used to implement tests for all den features so we can validate at CI. 4 - 5 - Use it as reference to see how den features are used, however, be aware that this might not be the best practices for file/aspect organization.
-6
templates/examples/modules/_example/ci/_non_dendritic/hosts/honeycrisp/_darwin/something.nix
··· 1 - # this is a non-dendritic darwin class module file. 2 - # automatically discovered by `den.import-tree` as enabled in auto-imports.nix 3 - { ... }: 4 - { 5 - # see nix-darwin options. 6 - }
-14
templates/examples/modules/_example/ci/_non_dendritic/hosts/rockhopper/_nixos/hardware-auto-generated.nix
··· 1 - # this is a non-dendritic nix class module file. 2 - # automatically discovered by `den.import-tree` as enabled in auto-imports.nix 3 - # 4 - # USER TODO: Remove this file. 5 - # suppose this file was auto-generated by nixos-generate-config or some other hardware tooling. 6 - { lib, ... }: 7 - { 8 - # used in CI to test this file was actually imported. 9 - options.auto-imported = lib.mkOption { 10 - readOnly = true; 11 - type = lib.types.bool; 12 - default = true; 13 - }; 14 - }
-81
templates/examples/modules/_example/ci/angle-bracket-deep.nix
··· 1 - { 2 - inputs, 3 - lib, 4 - ns, 5 - # deadnix: skip 6 - __findFile ? __findFile, 7 - ... 8 - }: 9 - let 10 - treeModule.nixos.options.tree = lib.mkOption { 11 - type = lib.types.listOf lib.types.str; 12 - }; 13 - inputX = { 14 - denful.ns.root = { 15 - nixos.tree = [ "X-root" ]; 16 - provides.branch.nixos.tree = [ "X-branch" ]; 17 - provides.branch.provides.leaf.nixos.tree = [ "X-leaf" ]; 18 - }; 19 - }; 20 - inputY = { 21 - denful.ns.root = { 22 - nixos.tree = [ "Y-root" ]; 23 - provides.branch.nixos.tree = [ "Y-branch" ]; 24 - provides.branch.provides.leaf.nixos.tree = [ "Y-leaf" ]; 25 - }; 26 - }; 27 - in 28 - { 29 - 30 - imports = [ 31 - (inputs.den.namespace "ns" [ 32 - true 33 - inputX 34 - inputY 35 - ]) 36 - ]; 37 - 38 - ns.root = { 39 - nixos.tree = [ "local-root" ]; 40 - provides.branch.nixos.tree = [ "local-branch" ]; 41 - provides.branch.provides.leaf.nixos.tree = [ "local-leaf" ]; 42 - }; 43 - 44 - den.aspects.rockhopper.includes = [ 45 - treeModule 46 - <ns/root> 47 - <ns/root/branch> 48 - <ns/root/branch/leaf> 49 - ]; 50 - 51 - perSystem = 52 - { checkCond, rockhopper, ... }: 53 - let 54 - vals = lib.sort (a: b: a < b) rockhopper.config.tree; 55 - in 56 - { 57 - checks.ns-angle-bracket-root = checkCond "angle-bracket access root" (<ns/root> == ns.root); 58 - 59 - checks.ns-angle-bracket-branch = checkCond "angle-bracket access branch" ( 60 - <ns/root/branch> == ns.root._.branch 61 - ); 62 - 63 - checks.ns-angle-bracket-leaf = checkCond "angle-bracket access leaf" ( 64 - <ns/root/branch/leaf> == ns.root._.branch._.leaf 65 - ); 66 - 67 - checks.ns-tree-all-levels-merged = checkCond "all tree levels merged" ( 68 - vals == [ 69 - "X-branch" 70 - "X-leaf" 71 - "X-root" 72 - "Y-branch" 73 - "Y-leaf" 74 - "Y-root" 75 - "local-branch" 76 - "local-leaf" 77 - "local-root" 78 - ] 79 - ); 80 - }; 81 - }
-76
templates/examples/modules/_example/ci/base-conf-modules.nix
··· 1 - # tests for extending `den.base.*` modules with capabilities (options). 2 - # these allow you to expend all hosts/users/homes with custom option 3 - # that can later be used by aspects for providing features. 4 - # 5 - { lib, ... }: 6 - { 7 - 8 - # This module is base for all host configs. 9 - den.base.host = 10 - { host, ... }: 11 - { 12 - options.capabilities.ssh-server = lib.mkEnableOption "Does host ${host.name} provide ssh?"; 13 - }; 14 - 15 - # This module is base for all user configs. 16 - den.base.user = 17 - { user, ... }: 18 - { 19 - options.isAdmin = lib.mkOption { 20 - type = lib.types.bool; 21 - default = user.name == "alice"; # only alice is always admin 22 - }; 23 - }; 24 - 25 - # This module is base for all home configs. 26 - # den.base.home = { home, ... }: { }; 27 - 28 - # This one is included on each host/user/home 29 - # it cannot access host/user/home values since this conf is generic. 30 - den.base.conf = { 31 - options.foo = lib.mkOption { 32 - type = lib.types.str; 33 - default = "bar"; 34 - }; 35 - }; 36 - 37 - # Now hosts and users can set any option defined in base modules. 38 - den.hosts.x86_64-linux.rockhopper = { 39 - capabilities.ssh-server = true; 40 - foo = "boo"; 41 - users.alice = { 42 - # isAdmin = true; # alice is admin by default, nothing explicit here. 43 - foo = "moo"; 44 - }; 45 - }; 46 - 47 - den.aspects.rockhopper.includes = 48 - let 49 - # An aspect can make use of these options to provide configuration. 50 - sshCapable = 51 - { host, ... }: 52 - { 53 - nixos.services.sshd.enable = host.capabilities.ssh-server; 54 - homeManager.services.ssh-agent.enable = host.capabilities.ssh-server; 55 - }; 56 - in 57 - [ sshCapable ]; 58 - 59 - # CI checks 60 - perSystem = 61 - { 62 - checkCond, 63 - rockhopper, 64 - alice-at-rockhopper, 65 - ... 66 - }: 67 - { 68 - checks.host-conf-rockhopper-sshd = checkCond "sshd enabled" ( 69 - rockhopper.config.services.sshd.enable == true 70 - ); 71 - checks.host-conf-alice-sshd = checkCond "ssh-agent enabled" ( 72 - alice-at-rockhopper.services.ssh-agent.enable == true 73 - ); 74 - }; 75 - 76 - }
-27
templates/examples/modules/_example/ci/builds.nix
··· 1 - # Adds some checks for CI 2 - { 3 - perSystem = 4 - { 5 - pkgs, 6 - checkFile, 7 - rockhopper, 8 - honeycrisp, 9 - cam, 10 - bob, 11 - ... 12 - }: 13 - let 14 - checks.x86_64-linux = { 15 - vm = checkFile "vm-builds" "${rockhopper.config.system.build.vm}/bin/run-rockhopper-vm"; 16 - hosts-rockhopper = checkFile "nixos-builds" rockhopper.config.system.build.toplevel; 17 - homes-cam = checkFile "home-builds" cam.activation-script; 18 - }; 19 - checks.aarch64-darwin = { 20 - hosts-honeycrisp = checkFile "darwin-builds" honeycrisp.config.system.build.toplevel; 21 - homes-bob = checkFile "darwin-home-builds" bob.activation-script; 22 - }; 23 - in 24 - { 25 - checks = checks.${pkgs.stdenv.hostPlatform.system} or { }; 26 - }; 27 - }
-67
templates/examples/modules/_example/ci/cross-flake-parametric.nix
··· 1 - { 2 - inputs, 3 - lib, 4 - provider, 5 - ... 6 - }: 7 - let 8 - providerModule.nixos.options.providerVars = lib.mkOption { 9 - type = lib.types.attrsOf lib.types.str; 10 - default = { }; 11 - }; 12 - in 13 - { 14 - flake-file.inputs.provider = { 15 - url = "path:./provider"; 16 - inputs.den.follows = "den"; 17 - inputs.flake-aspects.follows = "flake-aspects"; 18 - inputs.flake-parts.follows = "flake-parts"; 19 - inputs.import-tree.follows = "import-tree"; 20 - inputs.nixpkgs.follows = "nixpkgs"; 21 - }; 22 - 23 - imports = [ 24 - (inputs.den.namespace "provider" [ 25 - true 26 - inputs.provider 27 - ]) 28 - ]; 29 - 30 - provider.tools._.dev._.editors = { 31 - nixos.providerVars.LOCAL_EDITOR = "emacs"; 32 - }; 33 - 34 - den.aspects.rockhopper.includes = [ 35 - providerModule 36 - provider.tools._.dev._.editors 37 - provider.tools._.dev._.shells 38 - ]; 39 - 40 - perSystem = 41 - { checkCond, rockhopper, ... }: 42 - let 43 - vars = rockhopper.config.providerVars; 44 - env = rockhopper.config.environment.variables; 45 - in 46 - { 47 - checks.cross-flake-provider-editor = checkCond "provider editor var set" ( 48 - env.PROVIDER_EDITOR == "vim" 49 - ); 50 - 51 - checks.cross-flake-provider-shell = checkCond "provider shell var set" ( 52 - env.PROVIDER_SHELL == "fish" 53 - ); 54 - 55 - checks.cross-flake-local-editor = checkCond "local editor var set" (vars.LOCAL_EDITOR == "emacs"); 56 - 57 - checks.cross-flake-namespace-merged = checkCond "namespace merged from provider input" ( 58 - provider.tools._.dev._.editors == inputs.self.denful.provider.tools._.dev._.editors 59 - && provider.tools._.dev._.shells == inputs.self.denful.provider.tools._.dev._.shells 60 - ); 61 - 62 - checks.cross-flake-input-denful = checkCond "input provider denful accessible" ( 63 - inputs.provider.denful.provider.tools._.dev._.editors.description 64 - == "Editor configurations from provider flake" 65 - ); 66 - }; 67 - }
-30
templates/examples/modules/_example/ci/custom-home-managed-package.nix
··· 1 - { 2 - # Including an static aspect should not cause duplicate definitions 3 - den.aspects.alice.includes = [ 4 - { 5 - homeManager = 6 - { pkgs, ... }: 7 - { 8 - programs.emacs.enable = true; 9 - programs.emacs.package = pkgs.emacs30-nox; 10 - }; 11 - } 12 - ]; 13 - 14 - perSystem = 15 - { 16 - checkCond, 17 - alice-at-rockhopper, 18 - lib, 19 - ... 20 - }: 21 - { 22 - checks.alice-custom-emacs = checkCond "set uniquely via a static includes" ( 23 - let 24 - expr = lib.getName alice-at-rockhopper.programs.emacs.package; 25 - expected = "emacs-nox"; 26 - in 27 - expr == expected 28 - ); 29 - }; 30 - }
-35
templates/examples/modules/_example/ci/custom-nixos-module.nix
··· 1 - { lib, ... }: 2 - let 3 - # A custom `nixos` class module that defines an option `names`. 4 - # Used to test that we are not duplicating values from owned configs. 5 - nixosNames = names: { options.${names} = lib.mkOption { type = lib.types.listOf lib.types.str; }; }; 6 - in 7 - { 8 - den.default.nixos.imports = [ (nixosNames "people") ]; 9 - den.default.includes = [ 10 - ( 11 - { user, ... }: 12 - { 13 - nixos.people = [ user.name ]; 14 - } 15 - ) 16 - ]; 17 - 18 - den.aspects.rockhopper.includes = [ 19 - # Example: importing a third-party nixos module. 20 - { nixos.imports = [ (nixosNames "names") ]; } 21 - ]; 22 - 23 - den.aspects.rockhopper.nixos.names = [ "tux" ]; 24 - 25 - perSystem = 26 - { checkCond, rockhopper, ... }: 27 - { 28 - checks.rockhopper-default-people = checkCond "set from den.default for each user" ( 29 - rockhopper.config.people == [ "alice" ] 30 - ); 31 - checks.rockhopper-names-single-entry = checkCond "custom nixos array option set once" ( 32 - rockhopper.config.names == [ "tux" ] 33 - ); 34 - }; 35 - }
-78
templates/examples/modules/_example/ci/deep-nested-namespace.nix
··· 1 - { 2 - inputs, 3 - lib, 4 - deep, 5 - ... 6 - }: 7 - let 8 - deepModule.nixos.options.deepVals = lib.mkOption { 9 - type = lib.types.listOf lib.types.str; 10 - }; 11 - depthA = { 12 - denful.deep.a._.b._.c._.d._.e = { 13 - description = "5 levels deep from inputA"; 14 - nixos.deepVals = [ "inputA-5-levels" ]; 15 - provides.f.nixos.deepVals = [ "inputA-6-levels" ]; 16 - }; 17 - }; 18 - depthB = { 19 - denful.deep.a._.b._.c._.d._.e = { 20 - nixos.deepVals = [ "inputB-5-levels" ]; 21 - provides.f.nixos.deepVals = [ "inputB-6-levels" ]; 22 - }; 23 - }; 24 - in 25 - { 26 - imports = [ 27 - (inputs.den.namespace "deep" [ 28 - true 29 - depthA 30 - depthB 31 - ]) 32 - ]; 33 - 34 - deep.a._.b._.c._.d._.e = { 35 - nixos.deepVals = [ "local-5-levels" ]; 36 - provides.f.nixos.deepVals = [ "local-6-levels" ]; 37 - }; 38 - 39 - den.aspects.rockhopper.includes = [ 40 - deepModule 41 - deep.a._.b._.c._.d._.e 42 - deep.a._.b._.c._.d._.e._.f 43 - ]; 44 - 45 - perSystem = 46 - { checkCond, rockhopper, ... }: 47 - let 48 - vals = lib.sort (a: b: a < b) rockhopper.config.deepVals; 49 - in 50 - { 51 - checks.deep-nest-5-levels = checkCond "5 levels deep merged correctly" ( 52 - builtins.elem "inputA-5-levels" vals 53 - && builtins.elem "inputB-5-levels" vals 54 - && builtins.elem "local-5-levels" vals 55 - ); 56 - 57 - checks.deep-nest-6-levels = checkCond "6 levels deep merged correctly" ( 58 - builtins.elem "inputA-6-levels" vals 59 - && builtins.elem "inputB-6-levels" vals 60 - && builtins.elem "local-6-levels" vals 61 - ); 62 - 63 - checks.deep-nest-all-merged = checkCond "all values merged" ( 64 - vals == [ 65 - "inputA-5-levels" 66 - "inputA-6-levels" 67 - "inputB-5-levels" 68 - "inputB-6-levels" 69 - "local-5-levels" 70 - "local-6-levels" 71 - ] 72 - ); 73 - 74 - checks.deep-nest-flake-output = checkCond "deep namespace as flake output" ( 75 - inputs.self.denful.deep.a._.b._.c._.d._.e._.f == deep.a._.b._.c._.d._.e._.f 76 - ); 77 - }; 78 - }
-27
templates/examples/modules/_example/ci/define-user.nix
··· 1 - { den, ... }: 2 - { 3 - den.default.includes = [ 4 - # Example: parametric over many contexts: { home }, { host, user }, { fromUser, toHost } 5 - den.provides.define-user 6 - ]; 7 - 8 - perSystem = 9 - { 10 - checkCond, 11 - rockhopper, 12 - adelie, 13 - ... 14 - }: 15 - { 16 - 17 - checks.alice-exists-on-rockhopper = checkCond "den.default.user.includes defines user on host" ( 18 - rockhopper.config.users.users.alice.isNormalUser 19 - ); 20 - checks.alice-not-exists-on-adelie = checkCond "den.default.user.includes defines user on host" ( 21 - !adelie.config.users.users ? alice 22 - ); 23 - checks.will-exists-on-adelie = checkCond "den.default.user.includes defines user on host" ( 24 - adelie.config.users.users.will.isNormalUser 25 - ); 26 - }; 27 - }
-8
templates/examples/modules/_example/ci/enable-wsl-host.nix
··· 1 - { inputs, ... }: 2 - { 3 - # Example: adelie host using github:nix-community/NixOS-WSL 4 - den.aspects.adelie.nixos = { 5 - imports = [ inputs.nixos-wsl.nixosModules.default ]; 6 - wsl.enable = true; 7 - }; 8 - }
-37
templates/examples/modules/_example/ci/helpers.nix
··· 1 - { self, ... }: 2 - { 3 - perSystem = 4 - { pkgs, ... }: 5 - let 6 - checkFile = 7 - name: file: 8 - pkgs.runCommandLocal name { } '' 9 - ls -la ${file} | tee $out 10 - ''; 11 - 12 - checkCond = 13 - name: cond: 14 - let 15 - code = if cond then "touch $out" else ''echo "Cond-Failed: ${name}"''; 16 - in 17 - pkgs.runCommandLocal name { } code; 18 - 19 - rockhopper = self.nixosConfigurations.rockhopper; 20 - honeycrisp = self.darwinConfigurations.honeycrisp; 21 - adelie = self.wslConfigurations.adelie; 22 - cam = self.homeConfigurations.cam; 23 - bob = self.homeConfigurations.bob; 24 - luke = self.homeConfigurations.luke; 25 - 26 - alice-at-rockhopper = rockhopper.config.home-manager.users.alice; 27 - alice-at-honeycrisp = honeycrisp.config.home-manager.users.alice; 28 - in 29 - { 30 - _module.args = { 31 - inherit checkCond checkFile; 32 - inherit rockhopper honeycrisp adelie; 33 - inherit cam bob luke; 34 - inherit alice-at-rockhopper alice-at-honeycrisp; 35 - }; 36 - }; 37 - }
-29
templates/examples/modules/_example/ci/hm-enabled-host.nix
··· 1 - { den, inputs, ... }: 2 - { 3 - # The `{ HM-OS-HOST }` context is activated ONLY for hosts that have 4 - # a HM supported OS and at least one user with homeManager class. 5 - den.aspects.hm-global-pkgs = 6 - { HM-OS-HOST }: 7 - den.lib.take.unused [ HM-OS-HOST.host ] # access host from context if needed 8 - { 9 - nixos.home-manager.useGlobalPkgs = true; 10 - }; 11 - 12 - den.default.includes = [ den.aspects.hm-global-pkgs ]; 13 - 14 - den.hosts.x86_64-linux.no-homes = { }; 15 - 16 - perSystem = 17 - { checkCond, rockhopper, ... }: 18 - { 19 - checks.rockhopper-hm-global-pkgs = checkCond "rockhopper-hm-global-pkgs" ( 20 - rockhopper.config.home-manager.useGlobalPkgs 21 - ); 22 - 23 - checks.no-homes-hm-global-pkgs = checkCond "no-homes-hm-global-pkgs" ( 24 - # no home-manager enabled nor useGlobalPkgs 25 - !inputs.self.nixosConfigurations.no-homes.config ? home-manager.useGlobalPkgs 26 - ); 27 - }; 28 - 29 - }
-13
templates/examples/modules/_example/ci/host-configures-users.nix
··· 1 - { 2 - 3 - # Example: host provides static config to all its users hm. 4 - den.aspects.rockhopper.homeManager.programs.direnv.enable = true; 5 - 6 - perSystem = 7 - { checkCond, alice-at-rockhopper, ... }: 8 - { 9 - checks.host-contributes-to-user = checkCond "rockhopper contributes to all its users" ( 10 - alice-at-rockhopper.programs.direnv.enable 11 - ); 12 - }; 13 - }
-42
templates/examples/modules/_example/ci/host-user-conditional-hm.nix
··· 1 - { lib, ... }: 2 - let 3 - # Example: configuration that depends on both host and user. provides only to HM. 4 - host-to-user-conditional = 5 - { 6 - user, 7 - host, 8 - ... 9 - }: 10 - if user.userName == "alice" && !lib.hasSuffix "darwin" host.system then 11 - { 12 - homeManager.programs.git.enable = true; 13 - } 14 - else 15 - { }; 16 - in 17 - { 18 - 19 - den.aspects.rockhopper.includes = [ 20 - # Example: host provides parametric user configuration. 21 - host-to-user-conditional 22 - ]; 23 - 24 - perSystem = 25 - { 26 - checkCond, 27 - alice-at-rockhopper, 28 - alice-at-honeycrisp, 29 - ... 30 - }: 31 - { 32 - 33 - checks.alice-hm-git-enabled-on = checkCond "home-managed git for alice at rockhopper" ( 34 - alice-at-rockhopper.programs.git.enable 35 - ); 36 - checks.alice-hm-git-enabled-off = checkCond "home-managed git for alice at honeycrisp" ( 37 - !alice-at-honeycrisp.programs.git.enable 38 - ); 39 - 40 - }; 41 - 42 - }
-28
templates/examples/modules/_example/ci/import-tree.nix
··· 1 - # configures class-automatic module auto imports for hosts/users/homes. 2 - # See documentation at modules/aspects/provides/import-tree.nix 3 - { 4 - # deadnix: skip 5 - __findFile ? __findFile, 6 - ... 7 - }: 8 - { 9 - 10 - # alice imports non-dendritic <class> modules from _non_dendritic/alice/_<class>/*.nix 11 - den.aspects.alice.includes = [ (<den/import-tree> ./_non_dendritic/alice) ]; 12 - 13 - # See the documentation at batteries/import-tree.nix 14 - den.default.includes = [ 15 - (<den/import-tree/host> ./_non_dendritic/hosts) 16 - (<den/import-tree/user> ./_non_dendritic/users) 17 - (<den/import-tree/home> ./_non_dendritic/homes) 18 - ]; 19 - 20 - # tests 21 - perSystem = 22 - { checkCond, rockhopper, ... }: 23 - { 24 - checks.import-tree = checkCond "auto-imported from rockhopper/_nixos" ( 25 - rockhopper.config.auto-imported 26 - ); 27 - }; 28 - }
-81
templates/examples/modules/_example/ci/namespace.nix
··· 1 - { 2 - inputs, 3 - den, 4 - lib, 5 - eg, 6 - # deadnix: skip 7 - __findFile ? __findFile, 8 - ... 9 - }: 10 - let 11 - # module for testing inclusion of namespaces 12 - simsModule.nixos.options.sims = lib.mkOption { 13 - type = lib.types.listOf lib.types.str; 14 - }; 15 - in 16 - { 17 - # enable <angle/bracket> syntax for finding aspects. 18 - _module.args.__findFile = den.lib.__findFile; 19 - 20 - imports = [ 21 - # create a local namespace and output at flake.denful.eg 22 - (inputs.den.namespace "eg" true) 23 - 24 - # you can also mount a namespace from many input sources. 25 - # the second argument becomes an array of inputs. 26 - ( 27 - let 28 - # NOTE: here we simulate inputA and inputB are flakes. 29 - inputA.denful.sim.ul._.a._.tion.nixos.sims = [ "inputA simulation" ]; 30 - inputB.denful.sim.ul._.a._.tion.nixos.sims = [ "inputB simulation" ]; 31 - exposeToFlake = true; 32 - in 33 - inputs.den.namespace "sim" [ 34 - inputA 35 - inputB 36 - exposeToFlake 37 - ] 38 - ) 39 - ]; 40 - 41 - # define nested aspects in local namespace 42 - eg.foo.provides.bar.provides.baz = { 43 - nixos.sims = [ "local namespace" ]; 44 - }; 45 - 46 - # augment aspects on a mounted namespace 47 - sim.ul._.a._.tion.nixos.sims = [ "local simulation" ]; 48 - 49 - den.aspects.rockhopper.includes = [ 50 - simsModule 51 - <eg/foo/bar/baz> 52 - <sim/ul/a/tion> 53 - ]; 54 - 55 - perSystem = 56 - { checkCond, rockhopper, ... }: 57 - { 58 - checks.namespace-eg-flake-output = checkCond "namespace enabled as flake output" ( 59 - eg == den.ful.eg && eg == <eg> && eg == inputs.self.denful.eg 60 - ); 61 - 62 - checks.namespace-eg-provides-accessible = checkCond "exact same value" ( 63 - eg.foo._.bar._.baz == <eg/foo/bar/baz> 64 - && eg.foo._.bar._.baz == inputs.self.denful.eg.foo._.bar._.baz 65 - ); 66 - 67 - checks.namespace-sim-merged = checkCond "merges from all sources" ( 68 - let 69 - expected = [ 70 - "inputA simulation" 71 - "inputB simulation" 72 - "local namespace" 73 - "local simulation" 74 - ]; 75 - actual = lib.sort (a: b: a < b) rockhopper.config.sims; 76 - in 77 - expected == actual 78 - ); 79 - 80 - }; 81 - }
-41
templates/examples/modules/_example/ci/one-os-package-per-user.nix
··· 1 - let 2 - 3 - # Example: adds hello into each user. provides only to OS. 4 - hello-package-for-user = 5 - { 6 - user, 7 - host, 8 - ... 9 - }: 10 - { 11 - ${host.class} = 12 - { pkgs, ... }: 13 - { 14 - users.users.${user.userName}.packages = [ pkgs.hello ]; 15 - }; 16 - }; 17 - 18 - in 19 - { 20 - 21 - den.default.includes = [ hello-package-for-user ]; 22 - 23 - perSystem = 24 - { 25 - checkCond, 26 - rockhopper, 27 - lib, 28 - ... 29 - }: 30 - { 31 - checks.alice-hello-enabled-by-default = checkCond "added hello at user packages" ( 32 - let 33 - progs = rockhopper.config.users.users.alice.packages; 34 - expr = map lib.getName progs; 35 - expected = [ "hello" ]; 36 - in 37 - expr == expected 38 - ); 39 - }; 40 - 41 - }
-145
templates/examples/modules/_example/ci/parametric-with-owned.nix
··· 1 - { 2 - den, 3 - lib, 4 - ... 5 - }: 6 - let 7 - # a test module to check context was forwarded 8 - fwdModule.options.fwd = { 9 - a = strOpt; 10 - b = strOpt; 11 - c = strOpt; 12 - d = strOpt; 13 - e = strOpt; 14 - f = strOpt; 15 - # unlike strings, pkgs cannot be duplicated/merged, we use this to 16 - # ensure no-dups are created from parametric owned modules. 17 - pkg = pkgOpt; 18 - pkg2 = pkgOpt; 19 - pkg3 = pkgOpt; 20 - }; 21 - strOpt = lib.mkOption { type = lib.types.str; }; 22 - pkgOpt = lib.mkOption { type = lib.types.package; }; 23 - 24 - inherit (den.lib) parametric; 25 - in 26 - { 27 - den.aspects.rockhopper.includes = [ 28 - { nixos.imports = [ fwdModule ]; } 29 - { homeManager.imports = [ fwdModule ]; } 30 - den.aspects.fwd._.first 31 - ]; 32 - den.aspects.rockhopper.nixos.fwd.c = "host owned C"; 33 - den.aspects.rockhopper.homeManager.fwd.a = "host home-managed A"; 34 - 35 - # this aspect will take any context and also forward it 36 - # into any includes function that can take same context. 37 - den.aspects.fwd._.first = parametric { 38 - nixos = 39 - { pkgs, ... }: 40 - { 41 - fwd.a = "First owned A"; 42 - fwd.pkg = pkgs.hello; 43 - }; 44 - homeManager = 45 - { pkgs, ... }: 46 - { 47 - fwd.pkg = pkgs.vim; 48 - }; 49 - includes = [ 50 - den.aspects.fwd._.second 51 - { nixos.fwd.d = "First static includes D"; } 52 - den.aspects.fwd._.never 53 - den.aspects.fwd._.fourth 54 - ]; 55 - }; 56 - 57 - # Note that second has named arguments, while first does not. 58 - # the first aspect forwards whatever context it receives. 59 - den.aspects.fwd._.second = 60 - { host, ... }: 61 - parametric.fixedTo { third = "Impact"; } { 62 - includes = [ den.aspects.fwd._.third ]; 63 - nixos = 64 - { pkgs, ... }: 65 - { 66 - fwd.b = "Second owned B for ${host.name}"; 67 - fwd.pkg2 = pkgs.bat; 68 - }; 69 - homeManager = 70 - { pkgs, ... }: 71 - { 72 - fwd.pkg2 = pkgs.helix; 73 - }; 74 - }; 75 - 76 - den.aspects.fwd._.third = 77 - { third, ... }: 78 - { 79 - nixos.fwd.e = "Third ${third}"; 80 - }; 81 - 82 - den.aspects.fwd._.fourth = parametric.expands { planet = "Earth"; } { 83 - includes = [ den.aspects.fwd._.fifth ]; 84 - nixos = 85 - { pkgs, ... }: 86 - { 87 - fwd.pkg3 = pkgs.emacs-nox; 88 - }; 89 - homeManager = 90 - { pkgs, ... }: 91 - { 92 - fwd.pkg3 = pkgs.emacs-nox; 93 - }; 94 - }; 95 - 96 - den.aspects.fwd._.fifth = 97 - { host, planet, ... }: 98 - { 99 - nixos.fwd.f = "Fifth ${planet} ${host.name}"; 100 - }; 101 - 102 - den.aspects.fwd._.never = 103 - { never-matches }: 104 - { 105 - nixos.fwd.a = "Imposibru! should never be included ${never-matches}"; 106 - }; 107 - 108 - perSystem = 109 - { 110 - checkCond, 111 - rockhopper, 112 - alice-at-rockhopper, 113 - ... 114 - }: 115 - { 116 - checks.parametric-fwd-a = checkCond "fwd-a" (rockhopper.config.fwd.a == "First owned A"); 117 - checks.parametric-fwd-b = checkCond "fwd-b" ( 118 - rockhopper.config.fwd.b == "Second owned B for rockhopper" 119 - ); 120 - checks.parametric-fwd-c = checkCond "fwd-c" (rockhopper.config.fwd.c == "host owned C"); 121 - checks.parametric-fwd-d = checkCond "fwd-d" (rockhopper.config.fwd.d == "First static includes D"); 122 - checks.parametric-fwd-e = checkCond "fwd-e" (rockhopper.config.fwd.e == "Third Impact"); 123 - checks.parametric-fwd-f = checkCond "fwd-f" (rockhopper.config.fwd.f == "Fifth Earth rockhopper"); 124 - 125 - checks.parametric-fwd-pkg = checkCond "fwd-pkg" (lib.getName rockhopper.config.fwd.pkg == "hello"); 126 - checks.parametric-fwd-pkg2 = checkCond "fwd-pkg2" (lib.getName rockhopper.config.fwd.pkg2 == "bat"); 127 - checks.parametric-fwd-pkg3 = checkCond "fwd-pkg3" ( 128 - lib.getName rockhopper.config.fwd.pkg3 == "emacs-nox" 129 - ); 130 - 131 - checks.parametric-fwd-hm-a = checkCond "fwd-hm-a" ( 132 - alice-at-rockhopper.fwd.a == "host home-managed A" 133 - ); 134 - checks.parametric-fwd-hm-pkg = checkCond "fwd-hm-pkg" ( 135 - lib.getName alice-at-rockhopper.fwd.pkg == "vim" 136 - ); 137 - checks.parametric-fwd-hm-pkg2 = checkCond "fwd-hm-pkg2" ( 138 - lib.getName alice-at-rockhopper.fwd.pkg2 == "helix" 139 - ); 140 - checks.parametric-fwd-hm-pkg3 = checkCond "fwd-hm-pkg3" ( 141 - lib.getName alice-at-rockhopper.fwd.pkg3 == "emacs-nox" 142 - ); 143 - }; 144 - 145 - }
-29
templates/examples/modules/_example/ci/primary-user.nix
··· 1 - { den, ... }: 2 - { 3 - den.aspects.alice.includes = [ 4 - # alice is always admin in all its hosts 5 - den._.primary-user 6 - ]; 7 - 8 - den.aspects.will.includes = [ 9 - # will is primary user in WSL NixOS. 10 - den._.primary-user 11 - ]; 12 - 13 - perSystem = 14 - { 15 - checkCond, 16 - honeycrisp, 17 - adelie, 18 - ... 19 - }: 20 - { 21 - checks.alice-primary-on-macos = checkCond "den._.primary-user sets macos primary" ( 22 - honeycrisp.config.system.primaryUser == "alice" 23 - ); 24 - 25 - checks.will-is-wsl-default = checkCond "wsl.defaultUser defined" ( 26 - adelie.config.wsl.defaultUser == "will" 27 - ); 28 - }; 29 - }
-29
templates/examples/modules/_example/ci/set-hostname.nix
··· 1 - { 2 - den.default.includes = 3 - let 4 - # Example: parametric host aspect to automatically set hostName on any host. 5 - set-host-name = 6 - { host, ... }: 7 - { 8 - ${host.class}.networking.hostName = host.name; 9 - }; 10 - in 11 - [ set-host-name ]; 12 - 13 - perSystem = 14 - { 15 - checkCond, 16 - rockhopper, 17 - honeycrisp, 18 - ... 19 - }: 20 - { 21 - checks.rockhopper-hostname = checkCond "den.default.host.includes sets hostName" ( 22 - rockhopper.config.networking.hostName == "rockhopper" 23 - ); 24 - 25 - checks.honeycrisp-hostname = checkCond "den.default.host.includes sets hostName" ( 26 - honeycrisp.config.networking.hostName == "honeycrisp" 27 - ); 28 - }; 29 - }
-53
templates/examples/modules/_example/ci/shared-parametric-aspects.nix
··· 1 - { 2 - inputs, 3 - lib, 4 - shared, 5 - ... 6 - }: 7 - let 8 - dataModule.nixos.options.data = lib.mkOption { 9 - type = lib.types.listOf lib.types.str; 10 - }; 11 - mkInputFlake = name: { 12 - denful.shared.gaming._.retro._.sega = { 13 - nixos.data = [ "${name}-sega-static" ]; 14 - }; 15 - }; 16 - inputFoo = mkInputFlake "foo"; 17 - inputBar = mkInputFlake "bar"; 18 - in 19 - { 20 - imports = [ 21 - (inputs.den.namespace "shared" [ 22 - true 23 - inputFoo 24 - inputBar 25 - ]) 26 - ]; 27 - 28 - shared.gaming._.retro._.sega.nixos.data = [ "local-sega-static" ]; 29 - 30 - den.aspects.rockhopper.includes = [ 31 - dataModule 32 - shared.gaming._.retro._.sega 33 - ]; 34 - 35 - perSystem = 36 - { checkCond, rockhopper, ... }: 37 - let 38 - vals = lib.sort (a: b: a < b) rockhopper.config.data; 39 - in 40 - { 41 - checks.shared-parametric-all-merged = checkCond "all parametric merged" ( 42 - vals == [ 43 - "bar-sega-static" 44 - "foo-sega-static" 45 - "local-sega-static" 46 - ] 47 - ); 48 - 49 - checks.shared-flake-output-matches = checkCond "flake output matches" ( 50 - shared.gaming._.retro._.sega == inputs.self.denful.shared.gaming._.retro._.sega 51 - ); 52 - }; 53 - }
-70
templates/examples/modules/_example/ci/special-args.nix
··· 1 - { den, withSystem, ... }: 2 - let 3 - testModule = 4 - { 5 - inputs', 6 - lib, 7 - self', 8 - ... 9 - }: 10 - { 11 - options.specialArgsTest = { 12 - test-package = lib.mkOption { type = lib.types.package; }; 13 - neovim-package = lib.mkOption { type = lib.types.package; }; 14 - }; 15 - 16 - config.specialArgsTest = { 17 - test-package = self'.packages.hello; 18 - neovim-package = inputs'.neovim-nightly-overlay.packages.neovim; 19 - }; 20 - }; 21 - in 22 - { 23 - flake-file.inputs.neovim-nightly-overlay = { 24 - url = "github:nix-community/neovim-nightly-overlay"; 25 - inputs.nixpkgs.follows = "nixpkgs"; 26 - inputs.flake-parts.follows = "flake-parts"; 27 - }; 28 - 29 - den.default.includes = [ 30 - den._.self' 31 - den._.inputs' 32 - ]; 33 - 34 - den.aspects.rockhopper.nixos.imports = [ testModule ]; 35 - den.aspects.cam.homeManager.imports = [ testModule ]; 36 - 37 - flake.checks.x86_64-linux = withSystem "x86_64-linux" ( 38 - { 39 - checkCond, 40 - rockhopper, 41 - cam, 42 - self', 43 - inputs', 44 - ... 45 - }: 46 - { 47 - special-args-self-nixos = checkCond "self' provides same package to nixos" ( 48 - rockhopper.config.specialArgsTest.test-package == self'.packages.hello 49 - ); 50 - 51 - special-args-inputs-nixos = checkCond "inputs' provides same package to nixos" ( 52 - rockhopper.config.specialArgsTest.neovim-package == inputs'.neovim-nightly-overlay.packages.neovim 53 - ); 54 - 55 - special-args-self-hm = checkCond "self' provides same package to home-manager" ( 56 - cam.config.specialArgsTest.test-package == self'.packages.hello 57 - ); 58 - 59 - special-args-inputs-hm = checkCond "inputs' provides same package to home-manager" ( 60 - cam.config.specialArgsTest.neovim-package == inputs'.neovim-nightly-overlay.packages.neovim 61 - ); 62 - } 63 - ); 64 - 65 - perSystem = 66 - { pkgs, ... }: 67 - { 68 - packages.hello = pkgs.hello; 69 - }; 70 - }
-31
templates/examples/modules/_example/ci/standalone-hm-special-args-osconfig.nix
··· 1 - let 2 - 3 - # Example: luke standalone home-manager has access to rockhopper osConfig specialArg. 4 - os-conditional-hm = 5 - { home, ... }: 6 - { 7 - # access osConfig, wired via extraSpecialArgs in homes.nix. 8 - homeManager = 9 - { osConfig, ... }: 10 - { 11 - programs.bat.enable = osConfig.programs.${home.programToDependOn}.enable; 12 - }; 13 - }; 14 - in 15 - { 16 - 17 - # Example: standalone-hm config depends on osConfig (non-recursive) 18 - # NOTE: this will only work for standalone hm, and not for hosted hm 19 - # since a hosted hm configuration cannot depend on the os configuration. 20 - den.aspects.luke.includes = [ 21 - os-conditional-hm 22 - ]; 23 - 24 - perSystem = 25 - { checkCond, luke, ... }: 26 - { 27 - checks.luke-hm-depends-on-osConfig = checkCond "standalone hm can depend on osConfig" ( 28 - luke.config.programs.bat.enable 29 - ); 30 - }; 31 - }
-50
templates/examples/modules/_example/ci/top-level-parametric.nix
··· 1 - # it is possible for top-level aspects directly under 2 - # den.aspects to take a context argument. 3 - { den, lib, ... }: 4 - let 5 - # A module to test that toplevel had context. 6 - topLevel = name: { 7 - config.tops = name; 8 - options.tops = lib.mkOption { type = lib.types.str; }; 9 - }; 10 - in 11 - { 12 - 13 - den.aspects.toplevel-user = 14 - { user, ... }: 15 - { 16 - nixos.imports = [ (topLevel user.name) ]; 17 - }; 18 - 19 - den.aspects.toplevel-host = 20 - { host, ... }: 21 - { 22 - homeManager.imports = [ (topLevel host.name) ]; 23 - }; 24 - 25 - den.aspects.rockhopper.includes = [ 26 - den.aspects.toplevel-host 27 - ]; 28 - 29 - den.aspects.alice.includes = [ 30 - den.aspects.toplevel-user 31 - ]; 32 - 33 - perSystem = 34 - { 35 - checkCond, 36 - alice-at-rockhopper, 37 - rockhopper, 38 - ... 39 - }: 40 - { 41 - checks.alice-toplevel-user = checkCond "alice toplevel param aspect" ( 42 - rockhopper.config.tops == "alice" 43 - ); 44 - 45 - checks.alice-toplevel-host = checkCond "alice toplevel param aspect" ( 46 - alice-at-rockhopper.tops == "rockhopper" 47 - ); 48 - }; 49 - 50 - }
-25
templates/examples/modules/_example/ci/unfree.nix
··· 1 - { den, ... }: 2 - 3 - let 4 - codeAspect = { 5 - includes = [ (den._.unfree [ "vscode" ]) ]; 6 - homeManager.programs.vscode.enable = true; 7 - }; 8 - discordAspect = { 9 - includes = [ 10 - (den._.unfree [ "discord" ]) 11 - ]; 12 - homeManager = 13 - { pkgs, ... }: 14 - { 15 - home.packages = [ pkgs.discord ]; 16 - }; 17 - }; 18 - in 19 - { 20 - # cam uses unfree vscode and discord loaded from different aspects. 21 - den.aspects.cam.includes = [ 22 - codeAspect 23 - discordAspect 24 - ]; 25 - }
-12
templates/examples/modules/_example/ci/user-configures-hosts.nix
··· 1 - { 2 - # Example: user provides static config to all its nixos hosts. 3 - den.aspects.alice.nixos.users.users.alice.description = "Alice Q. User"; 4 - 5 - perSystem = 6 - { checkCond, rockhopper, ... }: 7 - { 8 - checks.user-contributes-to-host = checkCond "alice.nixos sets on rockhopper host" ( 9 - rockhopper.config.users.users.alice.description == "Alice Q. User" 10 - ); 11 - }; 12 - }
-12
templates/examples/modules/_example/ci/user-home-defaults.nix
··· 1 - { 2 - # globally enable fish on all homes ever. 3 - den.default.homeManager.programs.fish.enable = true; 4 - 5 - perSystem = 6 - { checkCond, alice-at-rockhopper, ... }: 7 - { 8 - checks.alice-hm-fish-enabled-by-default = checkCond "home-managed fish for alice" ( 9 - alice-at-rockhopper.programs.fish.enable 10 - ); 11 - }; 12 - }
-38
templates/examples/modules/_example/ci/user-host-conditional-os.nix
··· 1 - { lib, ... }: 2 - let 3 - 4 - # Example: configuration that depends on both host and user. provides anytime { user, host } is in context. 5 - user-to-host-conditional = 6 - { user, host, ... }: 7 - if user.userName == "alice" && !lib.hasSuffix "darwin" host.system then 8 - { 9 - nixos.programs.tmux.enable = true; 10 - } 11 - else 12 - { }; 13 - in 14 - { 15 - 16 - # Example: user provides parametric host configuration. 17 - den.aspects.alice.includes = [ 18 - user-to-host-conditional 19 - ]; 20 - 21 - perSystem = 22 - { 23 - checkCond, 24 - rockhopper, 25 - honeycrisp, 26 - ... 27 - }: 28 - { 29 - checks.alice-os-tmux-enabled-on = checkCond "os tmux for hosts having alice" ( 30 - rockhopper.config.programs.tmux.enable 31 - ); 32 - checks.alice-os-tmux-enabled-off = checkCond "os tmux for hosts having alice" ( 33 - !honeycrisp.config.programs.tmux.enable 34 - ); 35 - 36 - }; 37 - 38 - }
-17
templates/examples/modules/_example/ci/user-shell.nix
··· 1 - { den, lib, ... }: 2 - { 3 - 4 - den.aspects.will.includes = [ 5 - # will has always loved red snappers 6 - (den._.user-shell "fish") 7 - ]; 8 - 9 - perSystem = 10 - { checkCond, adelie, ... }: 11 - { 12 - checks.will-always-love-you = checkCond "red-snapper fish is default shell" ( 13 - "fish" == lib.getName adelie.config.users.users.will.shell 14 - ); 15 - }; 16 - 17 - }
-13
templates/examples/modules/_example/ci/user-specific-hm-config.nix
··· 1 - { 2 - # Example: enable helix for alice on all its home-managed hosts. 3 - den.aspects.alice.homeManager.programs.helix.enable = true; 4 - 5 - perSystem = 6 - { checkCond, alice-at-rockhopper, ... }: 7 - { 8 - checks.alice-hm-helix-enabled-by-user = checkCond "home-managed helix for alice" ( 9 - alice-at-rockhopper.programs.helix.enable 10 - ); 11 - }; 12 - 13 - }
-16
templates/examples/modules/_example/ci/vm-bootable.nix
··· 1 - let 2 - # Example: A static aspect for vm installers. 3 - vm-bootable = { 4 - nixos = 5 - { modulesPath, ... }: 6 - { 7 - imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") ]; 8 - }; 9 - }; 10 - in 11 - { 12 - den.default.includes = [ 13 - # Example: static aspect 14 - vm-bootable 15 - ]; 16 - }
-14
templates/examples/modules/_example/defaults.nix
··· 1 - # User TODO: Remove this file. 2 - { 3 - # default aspect can be used for global static settings. 4 - den.default = { 5 - # static values. 6 - darwin.system.stateVersion = 6; 7 - nixos.system.stateVersion = "25.05"; 8 - homeManager.home.stateVersion = "25.05"; 9 - 10 - # these defaults are set for checking with CI. 11 - nixos.programs.vim.enable = true; 12 - darwin.programs.zsh.enable = true; 13 - }; 14 - }
-12
templates/examples/modules/_example/home-managed.nix
··· 1 - { den, ... }: 2 - { 3 - # see batteries/home-manager.nix 4 - den.default.includes = [ den._.home-manager ]; 5 - 6 - # enable home-manager dependency. 7 - flake-file.inputs.home-manager = { 8 - url = "github:nix-community/home-manager"; 9 - inputs.nixpkgs.follows = "nixpkgs"; 10 - }; 11 - 12 - }
-31
templates/examples/modules/_example/homes.nix
··· 1 - # Example standalone home-manager configurations. 2 - # These are independent of any host configuration. 3 - # See documentation at <den>/nix/types.nix 4 - { inputs, ... }: 5 - { 6 - den.homes.x86_64-linux.cam = { }; 7 - 8 - den.homes.aarch64-darwin.bob = { 9 - userName = "robert"; 10 - aspect = "developer"; 11 - }; 12 - 13 - # Example: custom home-manager instantiate for passing extraSpecialArgs. 14 - den.homes.x86_64-linux.luke = 15 - let 16 - osConfig = inputs.self.nixosConfigurations.rockhopper.config; 17 - in 18 - { 19 - # Example: luke standalone-homemanager needs access to rockhopper osConfig. 20 - instantiate = 21 - { pkgs, modules }: 22 - inputs.home-manager.lib.homeManagerConfiguration { 23 - inherit pkgs modules; 24 - extraSpecialArgs.osConfig = osConfig; 25 - }; 26 - 27 - # Example: custom attribute instead of specialArgs 28 - programToDependOn = "vim"; 29 - }; 30 - 31 - }
-50
templates/examples/modules/_example/hosts.nix
··· 1 - # This is a fully working example configuration. 2 - # Feel free to remove it, adapt or split into several modules. 3 - # See documentation at <den>/nix/types.nix 4 - { inputs, ... }: 5 - { 6 - den.hosts.aarch64-darwin.honeycrisp.users.alice = { }; 7 - 8 - den.hosts.aarch64-linux.emperor.users.alice = { }; 9 - 10 - den.hosts.x86_64-linux = { 11 - rockhopper = { 12 - description = "rockhopper is a kind of penguin"; 13 - users.alice = { }; 14 - }; 15 - 16 - adelie = { 17 - description = "wsl on windows"; 18 - users.will = { }; 19 - intoAttr = "wslConfigurations"; 20 - # custom nixpkgs channel. 21 - instantiate = inputs.nixpkgs-stable.lib.nixosSystem; 22 - # custom attribute (see home-manager.nix) 23 - hm-module = inputs.home-manager-stable.nixosModules.home-manager; 24 - # custom attribute (see primary-user.nix) 25 - wsl = { }; 26 - }; 27 - }; 28 - 29 - # move these inputs to any module you want. 30 - # they are here for all our examples to work on CI. 31 - flake-file.inputs = { 32 - 33 - # these stable inputs are for wsl 34 - nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05"; 35 - home-manager-stable.url = "github:nix-community/home-manager/release-25.05"; 36 - home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable"; 37 - 38 - nixos-wsl = { 39 - url = "github:nix-community/nixos-wsl"; 40 - inputs.nixpkgs.follows = "nixpkgs-stable"; 41 - inputs.flake-compat.follows = ""; 42 - }; 43 - 44 - darwin = { 45 - url = "github:nix-darwin/nix-darwin"; 46 - inputs.nixpkgs.follows = "nixpkgs"; 47 - }; 48 - }; 49 - 50 - }
-10
templates/examples/modules/den.nix
··· 1 - # USER TODO: remove this file. 2 - # copy any desired module to your ./modules and let it be auto-imported. 3 - { inputs, ... }: 4 - { 5 - imports = [ 6 - # The _example directory contains CI tests for all den features. 7 - # use it as reference of usage, but not of best practices. 8 - (inputs.import-tree ./_example) 9 - ]; 10 - }
-9
templates/examples/modules/dendritic.nix
··· 1 - { inputs, lib, ... }: 2 - { 3 - flake-file.inputs.flake-file.url = lib.mkDefault "github:vic/flake-file"; 4 - flake-file.inputs.den.url = lib.mkDefault "github:vic/den"; 5 - imports = [ 6 - (inputs.flake-file.flakeModules.dendritic or { }) 7 - (inputs.den.flakeModules.dendritic or { }) 8 - ]; 9 - }
-12
templates/examples/provider/flake.nix
··· 1 - { 2 - outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 3 - 4 - inputs = { 5 - nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 - flake-parts.url = "github:hercules-ci/flake-parts"; 7 - flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 8 - flake-aspects.url = "github:vic/flake-aspects"; 9 - import-tree.url = "github:vic/import-tree"; 10 - den.url = "github:vic/den"; 11 - }; 12 - }
-28
templates/examples/provider/modules/den.nix
··· 1 - { inputs, ... }: 2 - { 3 - systems = [ 4 - "x86_64-linux" 5 - "aarch64-darwin" 6 - ]; 7 - 8 - imports = [ 9 - inputs.den.flakeModule 10 - (inputs.den.namespace "provider" true) 11 - ]; 12 - 13 - provider.tools._.dev._.editors = { 14 - description = "Editor configurations from provider flake"; 15 - nixos.environment.variables.PROVIDER_EDITOR = "vim"; 16 - homeManager = 17 - { pkgs, ... }: 18 - { 19 - home.packages = [ pkgs.vim ]; 20 - }; 21 - }; 22 - 23 - provider.tools._.dev._.shells = { 24 - description = "Shell configurations from provider flake"; 25 - nixos.environment.variables.PROVIDER_SHELL = "fish"; 26 - nixos.environment.systemPackages = [ ]; 27 - }; 28 - }
-21
templates/minimal/flake.lock
··· 30 30 "type": "github" 31 31 } 32 32 }, 33 - "flake-parts": { 34 - "inputs": { 35 - "nixpkgs-lib": [ 36 - "nixpkgs" 37 - ] 38 - }, 39 - "locked": { 40 - "lastModified": 1762980239, 41 - "narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=", 42 - "owner": "hercules-ci", 43 - "repo": "flake-parts", 44 - "rev": "52a2caecc898d0b46b2b905f058ccc5081f842da", 45 - "type": "github" 46 - }, 47 - "original": { 48 - "owner": "hercules-ci", 49 - "repo": "flake-parts", 50 - "type": "github" 51 - } 52 - }, 53 33 "import-tree": { 54 34 "locked": { 55 35 "lastModified": 1763263999, ··· 85 65 "inputs": { 86 66 "den": "den", 87 67 "flake-aspects": "flake-aspects", 88 - "flake-parts": "flake-parts", 89 68 "import-tree": "import-tree", 90 69 "nixpkgs": "nixpkgs" 91 70 }
+6 -4
templates/minimal/flake.nix
··· 1 1 { 2 - outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules); 2 + outputs = 3 + inputs: 4 + (inputs.nixpkgs.lib.evalModules { 5 + modules = [ (inputs.import-tree ./modules) ]; 6 + specialArgs = { inherit inputs; }; 7 + }).config.flake; 3 8 4 9 inputs = { 5 10 nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 - flake-parts.url = "github:hercules-ci/flake-parts"; 7 - flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 8 - 9 11 import-tree.url = "github:vic/import-tree"; 10 12 flake-aspects.url = "github:vic/flake-aspects"; 11 13 den.url = "github:vic/den";
+14 -2
templates/minimal/modules/den.nix
··· 1 1 { inputs, den, ... }: 2 2 { 3 - systems = builtins.attrNames den.hosts; 3 + # we can import this flakeModule even if we dont have flake-parts as input! 4 4 imports = [ inputs.den.flakeModule ]; 5 5 6 6 den.hosts.x86_64-linux.igloo.users.tux = { }; 7 - den.aspects.igloo = { }; 7 + 8 + den.aspects.igloo = { 9 + nixos = 10 + { pkgs, ... }: 11 + { 12 + environment.systemPackages = [ pkgs.hello ]; 13 + passthru = { }; 14 + }; 15 + }; 16 + 17 + den.aspects.tux = { 18 + includes = [ den.provides.primary-user ]; 19 + }; 8 20 }
-11
templates/noflake/modules/compat.nix
··· 1 - { inputs, lib, ... }: 2 - { 3 - # we can import this flakeModule even if we dont have flake-parts as input! 4 - imports = [ inputs.den.flakeModule ]; 5 - 6 - # NOTE: Currently Den needs a top-level attribute where to place configurations, 7 - # by default it is the `flake` attribute, even if Den uses no flake-parts at all. 8 - options.flake = lib.mkOption { 9 - type = lib.types.submodule { freeformType = lib.types.anything; }; 10 - }; 11 - }
+3 -4
templates/noflake/modules/den.nix
··· 1 1 { inputs, ... }: 2 2 { 3 + # we can import this flakeModule even if we dont have flake-parts as input! 4 + imports = [ inputs.den.flakeModule ]; 5 + 3 6 # tux user on igloo host. 4 7 den.hosts.x86_64-linux.igloo.users.tux = { }; 5 8 ··· 8 11 nixos = 9 12 { pkgs, ... }: 10 13 { 11 - # remove these for a real bootable host 12 - boot.loader.grub.enable = false; 13 - fileSystems."/".device = "/dev/fake"; 14 14 passthru = { }; 15 - 16 15 environment.systemPackages = [ 17 16 pkgs.vim 18 17 ];