├── .gitignore ├── CONTRIBUTING.md ├── ChangeLog.md ├── LICENSE ├── README.md ├── all-modules.nix ├── bors.toml ├── dev ├── flake-module.nix ├── flake.lock ├── flake.nix └── tests │ ├── README.md │ ├── eval-tests.nix │ └── template.nix ├── examples ├── project-commands │ ├── Hello.avdl │ ├── README.md │ ├── flake.lock │ └── flake.nix └── shell-environments │ ├── README.md │ ├── flake.lock │ └── flake.nix ├── extras ├── easyOverlay.nix ├── flakeModules.nix ├── modules.nix └── partitions.nix ├── flake.lock ├── flake.nix ├── lib.nix ├── modules ├── apps.nix ├── checks.nix ├── debug.nix ├── devShells.nix ├── flake.nix ├── formatter.nix ├── legacyPackages.nix ├── moduleWithSystem.nix ├── nixosConfigurations.nix ├── nixosModules.nix ├── nixpkgs.nix ├── overlays.nix ├── packages.nix ├── perSystem.nix ├── transposition.nix └── withSystem.nix ├── shell.nix └── template ├── default └── flake.nix ├── multi-module ├── flake.nix └── hello │ └── flake-module.nix ├── package ├── flake.nix └── hello │ ├── hello.sh │ ├── package.nix │ └── test.nix └── unfree └── flake.nix /.gitignore: -------------------------------------------------------------------------------- 1 | # nix 2 | result 3 | result-* 4 | 5 | # pre-commit-hooks.nix 6 | .pre-commit-config.yaml 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # How do I contribute? 3 | 4 | Flake-parts is designed to be extremely modular, so often, you don't have to. 5 | 6 | Nonetheless, some changes can only be made here. 7 | 8 | Step 1. Look for an open or closed issue. This may be the quickest path to a solution to your problem. 9 | 10 | Step 2. If needed, open an issue. This way we can discuss the problem, and if necessary discuss changes, if any need to be made. 11 | 12 | Step 3. If needed, create a PR. Make sure to run `nix-shell` before comitting. It installs a pre-commit hook with `nixpkgs-fmt`. 13 | 14 | 15 | # Style 16 | 17 | This repository is written in a style similar to that of Nixpkgs, with some exceptions. 18 | The following sections describe such additions, exceptions, and it probably confirms some rules. 19 | 20 | ## Rule #1. Go with the flow 21 | 22 | Write code that fits in. Don't reformat existing code. Don't obsess over fitting in. Write good docs and tests instead. 23 | 24 | ## Camel case 25 | 26 | 27 | - File names may be in camelCase. This reduces the number of unique names in the project. 28 | 29 | Except for file names, the Nixpkgs casing rule is maintained here as well: 30 | 31 | - Package names are verbatim or in snake-case. Example: 32 | - `flake-parts-lib` 33 | 34 | - Functionality provided by flake-parts is in camelCase. Examples: 35 | - `getSystem` 36 | - `mkFlake` 37 | 38 | ## Operators and such 39 | 40 | - The "contains attribute" operator is spelled without spaces, just like the "select attribute" operator. I believe Nixpkgs is undecided on this. 41 | 42 | ```nix 43 | if x?a then x.a else "does not have a" 44 | # ^^^ 45 | ``` 46 | 47 | - `@` pattern goes before and uses no extra spaces. 48 | 49 | ```nix 50 | # immediately before parameter list when single line 51 | pair@{ name, value }: 52 | 53 | # newline after @ when multi-line 54 | pair@ 55 | { name 56 | , value 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | 2 | # 2023-05-30 3 | 4 | - Fix a strictness issue in `perInput`, affecting `inputs'`, `self'`. 5 | This has caused infinite recursions and potentially performance issues since 6 | the introduction of these module arguments. 7 | 8 | # 2023-05-08 9 | 10 | - Add [`importApply`](https://flake.parts/define-module-in-separate-file.html?highlight=importApply#importApply) for bringing variables from the flake scope into module files. 11 | 12 | - Add `mkDeferredModuleOption` as a generic name for the implementation of `mkPerSystemOption`. 13 | 14 | # 2023-03-26 15 | 16 | - Add preliminary support for `disabledModules` for modules exposed via the importable `flakeModules` module. 17 | This requires a Nixpkgs of 2023-03-09 or newer. 18 | 19 | # 2023-01-05 20 | 21 | - Add importable `easyOverlay` module for defining an overlay "easily" by reusing `perSystem`. 22 | This is not for consuming overlays. 23 | 24 | # 2022-12-25 25 | 26 | - Added a new `flake.flakeModules` option so a flake can expose a module 27 | to be used in a downstream flake's flake-parts usage. `.flakeModule` is 28 | now an alias for `.flakeModules.default`. 29 | 30 | Option only available if `flake-parts.flakeModules.flakeModules` is imported. 31 | 32 | # 2022-12-17 33 | 34 | - The old syntax `mkFlake { inherit self; }` is now strongly discouraged in 35 | favor of: 36 | 37 | ```nix 38 | outputs = inputs@{ flake-parts, ... }: 39 | flake-parts.lib.mkFlake { inherit inputs; } { /* module */ } 40 | ``` 41 | 42 | This fixes an infinite recursion that occurs with the old syntax when 43 | using the `inputs` module argument in `imports`. 44 | 45 | If you're under the impression that this already worked, that's probably 46 | because you were using `inputs` from the lexical scope (ie directly from 47 | the flake outputs function arguments), rather than in a separate module file. 48 | 49 | 50 | # 2022-12-07 51 | 52 | - The `darwinModules` option has been removed. This was added in the early days 53 | without full consideration. The removal will have no effect on most flakes 54 | considering that the [`flake` option](https://flake.parts/options/flake-parts.html#opt-flake) 55 | allows any attribute to be set. This attribute and related attributes should 56 | be added to the nix-darwin project instead. 57 | 58 | # 2022-10-11 59 | 60 | - The `nixpkgs` input has been renamed to `nixpkgs-lib` to signify that the 61 | only dependency is on the `lib` attribute, which can be provided by either 62 | the `nixpkgs?dir=lib` subflake or by the `nixpkgs` flake itself. 63 | 64 | - The templates now use the default, _fixed_ `nixpkgs?dir=lib` dependency instead 65 | of a _following_ `nixpkgs` dependency. 66 | 67 | # 2022-05-25 68 | 69 | - `perSystem` is not a `functionTo submodule` anymore, but a `deferredModule`, 70 | which is a lot like a regular submodule, but possible to invoke multiple 71 | times, for each `system`. 72 | 73 | All `perSystem` value definitions must remove the `system: ` argument. 74 | If you need `system` to be in scope, use the one in the module arguments. 75 | 76 | ```diff 77 | -perSystem = system: { config, lib, ... }: 78 | +perSystem = { config, lib, system, ... }: 79 | ``` 80 | 81 | All `perSystem` option declarations must now use `flake-parts-lib.mkPerSystemOption`. 82 | 83 | ```nix 84 | { 85 | options.perSystem = mkPerSystemOption ({ config, ... }: { 86 | options = { 87 | # ... 88 | }; 89 | # ... 90 | }); 91 | } 92 | ``` 93 | 94 | - `flake-modules-core` is now called `flake-parts`. 95 | 96 | - `flake.overlay` has been removed in favor of `flake.overlays.default`. 97 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Hercules CI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Flake Parts 3 | 4 | _Core of a distributed framework for writing Nix Flakes._ 5 | 6 | `flake-parts` provides the options that represent standard flake attributes 7 | and establishes a way of working with `system`. 8 | Opinionated features are provided by an ecosystem of modules that you can import. 9 | 10 | `flake-parts` _itself_ has the goal to be a minimal mirror of the Nix flake schema. 11 | Used by itself, it is very lightweight. 12 | 13 | --- 14 | 15 | **Documentation**: [flake.parts](https://flake.parts) 16 | 17 | --- 18 | 19 | # Why Modules? 20 | 21 | Flakes are configuration. The module system lets you refactor configuration 22 | into modules that can be shared. 23 | 24 | It reduces the proliferation of custom Nix glue code, similar to what the 25 | module system has done for NixOS configurations. 26 | 27 | Unlike NixOS, but following Flakes' spirit, `flake-parts` is not a 28 | monorepo with the implied goal of absorbing all of open source, but rather 29 | a single module that other repositories can build upon, while ensuring a 30 | baseline level of compatibility: the core attributes that constitute a flake. 31 | 32 | # Features 33 | 34 | - Split your `flake.nix` into focused units, each in their own file. 35 | 36 | - Take care of [system](https://flake.parts/system.html). 37 | 38 | - Allow users of your library flake to easily integrate your generated flake outputs 39 | into their flake. 40 | 41 | - Reuse project logic written by others 42 | 43 | 44 | 45 | 46 | # Getting Started 47 | 48 | If your project does not have a flake yet: 49 | 50 | ```console 51 | nix flake init -t github:hercules-ci/flake-parts 52 | ``` 53 | 54 | # Migrate 55 | 56 | Otherwise, add the input, 57 | 58 | ```nix 59 | flake-parts.url = "github:hercules-ci/flake-parts"; 60 | ``` 61 | 62 | then slide `mkFlake` between your outputs function head and body, 63 | 64 | ```nix 65 | outputs = inputs@{ flake-parts, ... }: 66 | flake-parts.lib.mkFlake { inherit inputs; } { 67 | flake = { 68 | # Put your original flake attributes here. 69 | }; 70 | systems = [ 71 | # systems for which you want to build the `perSystem` attributes 72 | "x86_64-linux" 73 | # ... 74 | ]; 75 | }; 76 | ``` 77 | 78 | Now you can add the remaining module attributes like in the [the template](./template/default/flake.nix). 79 | 80 | # Templates 81 | 82 | See [the template](./template/default/flake.nix). 83 | 84 | # Examples 85 | 86 | See the [examples/](./examples) directory. 87 | 88 | # Projects using flake-parts 89 | 90 | - [nixd](https://github.com/nix-community/nixd/blob/main/flake.nix) (c++) 91 | - [hyperswitch](https://github.com/juspay/hyperswitch/blob/main/flake.nix) (rust) 92 | - [argo-workflows](https://github.com/argoproj/argo-workflows/blob/master/dev/nix/flake.nix) (go) 93 | - [nlp-service](https://github.com/recap-utr/nlp-service/blob/main/flake.nix) (python) 94 | - [emanote](https://github.com/srid/emanote/blob/master/flake.nix) (haskell) 95 | 96 | # Options Reference 97 | 98 | See [flake.parts options](https://flake.parts/options/flake-parts.html) 99 | -------------------------------------------------------------------------------- /all-modules.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./modules/apps.nix 4 | ./modules/checks.nix 5 | ./modules/debug.nix 6 | ./modules/devShells.nix 7 | ./modules/flake.nix 8 | ./modules/formatter.nix 9 | ./modules/legacyPackages.nix 10 | ./modules/moduleWithSystem.nix 11 | ./modules/nixosConfigurations.nix 12 | ./modules/nixosModules.nix 13 | ./modules/nixpkgs.nix 14 | ./modules/overlays.nix 15 | ./modules/packages.nix 16 | ./modules/perSystem.nix 17 | ./modules/transposition.nix 18 | ./modules/withSystem.nix 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "ci/hercules/onPush/default", 3 | "ci/hercules/evaluation", 4 | ] 5 | delete_merged_branches = true 6 | -------------------------------------------------------------------------------- /dev/flake-module.nix: -------------------------------------------------------------------------------- 1 | { config, lib, inputs, self, withSystem, ... }: 2 | 3 | { 4 | imports = [ 5 | inputs.pre-commit-hooks-nix.flakeModule 6 | inputs.hercules-ci-effects.flakeModule # herculesCI attr 7 | ]; 8 | systems = [ "x86_64-linux" "aarch64-darwin" ]; 9 | 10 | hercules-ci.flake-update = { 11 | enable = true; 12 | autoMergeMethod = "merge"; 13 | when.dayOfMonth = 1; 14 | flakes = { 15 | "." = { }; 16 | "dev" = { }; 17 | }; 18 | }; 19 | 20 | perSystem = { config, pkgs, ... }: { 21 | 22 | devShells.default = pkgs.mkShell { 23 | nativeBuildInputs = [ 24 | pkgs.nixpkgs-fmt 25 | pkgs.pre-commit 26 | pkgs.hci 27 | ]; 28 | shellHook = '' 29 | ${config.pre-commit.installationScript} 30 | ''; 31 | }; 32 | 33 | pre-commit = { 34 | inherit pkgs; # should make this default to the one it can get via follows 35 | settings = { 36 | hooks.nixpkgs-fmt.enable = true; 37 | }; 38 | }; 39 | 40 | checks.eval-tests = 41 | let tests = import ./tests/eval-tests.nix { flake-parts = self; }; 42 | in tests.runTests pkgs.emptyFile // { internals = tests; }; 43 | 44 | }; 45 | flake = { 46 | # for repl exploration / debug 47 | config.config = config; 48 | options.mySystem = lib.mkOption { default = config.allSystems.${builtins.currentSystem}; }; 49 | config.effects = withSystem "x86_64-linux" ({ pkgs, hci-effects, ... }: { 50 | tests = { 51 | template = pkgs.callPackage ./tests/template.nix { inherit hci-effects; }; 52 | }; 53 | }); 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /dev/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-compat": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1696426674, 7 | "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", 8 | "owner": "edolstra", 9 | "repo": "flake-compat", 10 | "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "edolstra", 15 | "repo": "flake-compat", 16 | "type": "github" 17 | } 18 | }, 19 | "flake-parts": { 20 | "inputs": { 21 | "nixpkgs-lib": [ 22 | "hercules-ci-effects", 23 | "nixpkgs" 24 | ] 25 | }, 26 | "locked": { 27 | "lastModified": 1743550720, 28 | "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", 29 | "owner": "hercules-ci", 30 | "repo": "flake-parts", 31 | "rev": "c621e8422220273271f52058f618c94e405bb0f5", 32 | "type": "github" 33 | }, 34 | "original": { 35 | "id": "flake-parts", 36 | "type": "indirect" 37 | } 38 | }, 39 | "gitignore": { 40 | "inputs": { 41 | "nixpkgs": [ 42 | "pre-commit-hooks-nix", 43 | "nixpkgs" 44 | ] 45 | }, 46 | "locked": { 47 | "lastModified": 1709087332, 48 | "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", 49 | "owner": "hercules-ci", 50 | "repo": "gitignore.nix", 51 | "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", 52 | "type": "github" 53 | }, 54 | "original": { 55 | "owner": "hercules-ci", 56 | "repo": "gitignore.nix", 57 | "type": "github" 58 | } 59 | }, 60 | "hercules-ci-effects": { 61 | "inputs": { 62 | "flake-parts": "flake-parts", 63 | "nixpkgs": "nixpkgs" 64 | }, 65 | "locked": { 66 | "lastModified": 1748000383, 67 | "narHash": "sha256-EaAJhwfJGBncgIV/0NlJviid2DP93cTMc9h0q6P6xXk=", 68 | "owner": "hercules-ci", 69 | "repo": "hercules-ci-effects", 70 | "rev": "231726642197817d20310b9d39dd4afb9e899489", 71 | "type": "github" 72 | }, 73 | "original": { 74 | "owner": "hercules-ci", 75 | "repo": "hercules-ci-effects", 76 | "type": "github" 77 | } 78 | }, 79 | "nixpkgs": { 80 | "locked": { 81 | "lastModified": 1747179050, 82 | "narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=", 83 | "owner": "NixOS", 84 | "repo": "nixpkgs", 85 | "rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e", 86 | "type": "github" 87 | }, 88 | "original": { 89 | "owner": "NixOS", 90 | "ref": "nixos-unstable", 91 | "repo": "nixpkgs", 92 | "type": "github" 93 | } 94 | }, 95 | "nixpkgs_2": { 96 | "locked": { 97 | "lastModified": 1748815281, 98 | "narHash": "sha256-twQNQ/9ELOtbXRtSloQwFoNWujA2wev428pCiT0Okg8=", 99 | "owner": "NixOS", 100 | "repo": "nixpkgs", 101 | "rev": "f9969bf7f6a6ab7e0fadd889ddd9fa6ad8cc5288", 102 | "type": "github" 103 | }, 104 | "original": { 105 | "owner": "NixOS", 106 | "repo": "nixpkgs", 107 | "type": "github" 108 | } 109 | }, 110 | "pre-commit-hooks-nix": { 111 | "inputs": { 112 | "flake-compat": "flake-compat", 113 | "gitignore": "gitignore", 114 | "nixpkgs": [ 115 | "nixpkgs" 116 | ] 117 | }, 118 | "locked": { 119 | "lastModified": 1747372754, 120 | "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=", 121 | "owner": "cachix", 122 | "repo": "pre-commit-hooks.nix", 123 | "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46", 124 | "type": "github" 125 | }, 126 | "original": { 127 | "owner": "cachix", 128 | "repo": "pre-commit-hooks.nix", 129 | "type": "github" 130 | } 131 | }, 132 | "root": { 133 | "inputs": { 134 | "hercules-ci-effects": "hercules-ci-effects", 135 | "nixpkgs": "nixpkgs_2", 136 | "pre-commit-hooks-nix": "pre-commit-hooks-nix" 137 | } 138 | } 139 | }, 140 | "root": "root", 141 | "version": 7 142 | } 143 | -------------------------------------------------------------------------------- /dev/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Dependencies for development purposes"; 3 | 4 | inputs = { 5 | # Flakes don't give us a good way to depend on .., so we don't. 6 | # As a consequence, this flake only provides dependencies, and 7 | # we can't use the `nix` CLI as expected. 8 | 9 | nixpkgs.url = "github:NixOS/nixpkgs"; 10 | pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix"; 11 | pre-commit-hooks-nix.inputs.nixpkgs.follows = "nixpkgs"; 12 | hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects"; 13 | }; 14 | 15 | outputs = { ... }: 16 | { 17 | # The dev tooling is in ./flake-module.nix 18 | # See comment at `inputs` above. 19 | # It is loaded into partitions.dev by the root flake. 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /dev/tests/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Running the tests 3 | 4 | These tests can be run locally with the `hci effect run` command. This gives 5 | the tests access to a proper nix daemon and the network. 6 | 7 | Designed for convenient deployments, it needs some information from git. You 8 | may use `--no-token` to disable this functionality if you're getting errors, or 9 | if you're asked to log in. 10 | 11 | Example: 12 | 13 | ```console 14 | hci effect run --no-token default.effects.tests.template 15 | ``` 16 | -------------------------------------------------------------------------------- /dev/tests/eval-tests.nix: -------------------------------------------------------------------------------- 1 | # Run with 2 | # 3 | # nix build .#checks.x86_64-linux.eval-tests 4 | 5 | { flake-parts }: 6 | rec { 7 | nixpkgs = flake-parts.inputs.nixpkgs; 8 | f-p-lib = flake-parts.lib; 9 | inherit (f-p-lib) mkFlake; 10 | inherit (flake-parts.inputs.nixpkgs-lib) lib; 11 | 12 | pkg = system: name: 13 | derivation 14 | { 15 | name = name; 16 | builder = "no-builder"; 17 | system = system; 18 | } 19 | // { 20 | meta = { 21 | mainProgram = name; 22 | }; 23 | }; 24 | 25 | empty = mkFlake 26 | { inputs.self = { }; } 27 | { 28 | systems = [ ]; 29 | }; 30 | 31 | emptyExposeArgs = mkFlake 32 | { inputs.self = { outPath = "the self outpath"; }; } 33 | ({ config, moduleLocation, ... }: { 34 | flake = { 35 | inherit moduleLocation; 36 | }; 37 | }); 38 | 39 | emptyExposeArgsNoSelf = mkFlake 40 | { inputs.self = throw "self won't be available in case of some errors"; } 41 | ({ config, moduleLocation, ... }: { 42 | flake = { 43 | inherit moduleLocation; 44 | }; 45 | }); 46 | 47 | example1 = mkFlake 48 | { inputs.self = { }; } 49 | { 50 | systems = [ "a" "b" ]; 51 | perSystem = { config, system, ... }: { 52 | packages.hello = pkg system "hello"; 53 | apps.hello.program = config.packages.hello; 54 | }; 55 | }; 56 | 57 | packagesNonStrictInDevShells = mkFlake 58 | { inputs.self = packagesNonStrictInDevShells; /* approximation */ } 59 | { 60 | systems = [ "a" "b" ]; 61 | perSystem = { system, self', ... }: { 62 | packages.hello = pkg system "hello"; 63 | packages.default = self'.packages.hello; 64 | devShells = throw "can't be strict in perSystem.devShells!"; 65 | }; 66 | flake.devShells = throw "can't be strict in devShells!"; 67 | }; 68 | 69 | easyOverlay = mkFlake 70 | { inputs.self = { }; } 71 | { 72 | imports = [ flake-parts.flakeModules.easyOverlay ]; 73 | systems = [ "a" "aarch64-linux" ]; 74 | perSystem = { system, config, final, pkgs, ... }: { 75 | packages.default = config.packages.hello; 76 | packages.hello = pkg system "hello"; 77 | packages.hello_new = final.hello; 78 | overlayAttrs = { 79 | hello = config.packages.hello; 80 | hello_old = pkgs.hello; 81 | hello_new = config.packages.hello_new; 82 | }; 83 | }; 84 | }; 85 | 86 | modulesFlake = mkFlake 87 | { 88 | inputs.self = { }; 89 | moduleLocation = "modulesFlake"; 90 | } 91 | { 92 | imports = [ flake-parts.flakeModules.modules ]; 93 | systems = [ ]; 94 | flake = { 95 | modules.generic.example = { lib, ... }: { 96 | options.generic.example = lib.mkOption { default = "works in any module system application"; }; 97 | }; 98 | modules.foo.example = { lib, ... }: { 99 | options.foo.example = lib.mkOption { default = "works in foo application"; }; 100 | }; 101 | }; 102 | }; 103 | 104 | flakeModulesDeclare = mkFlake 105 | { inputs.self = { outPath = ./.; }; } 106 | ({ config, ... }: { 107 | imports = [ flake-parts.flakeModules.flakeModules ]; 108 | systems = [ ]; 109 | flake.flakeModules.default = { lib, ... }: { 110 | options.flake.test123 = lib.mkOption { default = "option123"; }; 111 | imports = [ config.flake.flakeModules.extra ]; 112 | }; 113 | flake.flakeModules.extra = { 114 | flake.test123 = "123test"; 115 | }; 116 | }); 117 | 118 | flakeModulesImport = mkFlake 119 | { inputs.self = { }; } 120 | { 121 | imports = [ flakeModulesDeclare.flakeModules.default ]; 122 | }; 123 | 124 | flakeModulesDisable = mkFlake 125 | { inputs.self = { }; } 126 | { 127 | imports = [ flakeModulesDeclare.flakeModules.default ]; 128 | disabledModules = [ flakeModulesDeclare.flakeModules.extra ]; 129 | }; 130 | 131 | nixpkgsWithoutEasyOverlay = import nixpkgs { 132 | system = "x86_64-linux"; 133 | overlays = [ ]; 134 | config = { }; 135 | }; 136 | 137 | nixpkgsWithEasyOverlay = import nixpkgs { 138 | # non-memoized 139 | system = "x86_64-linux"; 140 | overlays = [ easyOverlay.overlays.default ]; 141 | config = { }; 142 | }; 143 | 144 | nixpkgsWithEasyOverlayMemoized = import nixpkgs { 145 | # memoized 146 | system = "aarch64-linux"; 147 | overlays = [ easyOverlay.overlays.default ]; 148 | config = { }; 149 | }; 150 | 151 | specialArgFlake = mkFlake 152 | { 153 | inputs.self = { }; 154 | specialArgs.soSpecial = true; 155 | } 156 | ({ soSpecial, ... }: { 157 | imports = assert soSpecial; [ ]; 158 | flake.foo = true; 159 | }); 160 | 161 | partitionWithoutExtraInputsFlake = mkFlake 162 | { 163 | inputs.self = { }; 164 | } 165 | ({ config, ... }: { 166 | imports = [ flake-parts.flakeModules.partitions ]; 167 | systems = [ "x86_64-linux" ]; 168 | partitions.dev.module = { inputs, ... }: builtins.seq inputs { }; 169 | partitionedAttrs.devShells = "dev"; 170 | }); 171 | 172 | runTests = ok: 173 | 174 | assert empty == { 175 | apps = { }; 176 | checks = { }; 177 | devShells = { }; 178 | formatter = { }; 179 | legacyPackages = { }; 180 | nixosConfigurations = { }; 181 | nixosModules = { }; 182 | overlays = { }; 183 | packages = { }; 184 | }; 185 | 186 | assert example1 == { 187 | apps = { 188 | a = { 189 | hello = { 190 | program = "${pkg "a" "hello"}/bin/hello"; 191 | type = "app"; 192 | meta = { }; 193 | }; 194 | }; 195 | b = { 196 | hello = { 197 | program = "${pkg "b" "hello"}/bin/hello"; 198 | type = "app"; 199 | meta = { }; 200 | }; 201 | }; 202 | }; 203 | checks = { a = { }; b = { }; }; 204 | devShells = { a = { }; b = { }; }; 205 | formatter = { }; 206 | legacyPackages = { a = { }; b = { }; }; 207 | nixosConfigurations = { }; 208 | nixosModules = { }; 209 | overlays = { }; 210 | packages = { 211 | a = { hello = pkg "a" "hello"; }; 212 | b = { hello = pkg "b" "hello"; }; 213 | }; 214 | }; 215 | 216 | # - exported package becomes part of overlay. 217 | # - perSystem is invoked for the right system, when system is non-memoized 218 | assert nixpkgsWithEasyOverlay.hello == pkg "x86_64-linux" "hello"; 219 | 220 | # - perSystem is invoked for the right system, when system is memoized 221 | assert nixpkgsWithEasyOverlayMemoized.hello == pkg "aarch64-linux" "hello"; 222 | 223 | # - Non-exported package does not become part of overlay. 224 | assert nixpkgsWithEasyOverlay.default or null != pkg "x86_64-linux" "hello"; 225 | 226 | # - hello_old comes from super 227 | assert nixpkgsWithEasyOverlay.hello_old == nixpkgsWithoutEasyOverlay.hello; 228 | 229 | # - `hello_new` shows that the `final` wiring works 230 | assert nixpkgsWithEasyOverlay.hello_new == nixpkgsWithEasyOverlay.hello; 231 | 232 | assert flakeModulesImport.test123 == "123test"; 233 | 234 | assert flakeModulesDisable.test123 == "option123"; 235 | 236 | assert packagesNonStrictInDevShells.packages.a.default == pkg "a" "hello"; 237 | 238 | assert emptyExposeArgs.moduleLocation == "the self outpath/flake.nix"; 239 | 240 | assert (lib.evalModules { 241 | class = "barrr"; 242 | modules = [ 243 | modulesFlake.modules.generic.example 244 | ]; 245 | }).config.generic.example == "works in any module system application"; 246 | 247 | assert (lib.evalModules { 248 | class = "foo"; 249 | modules = [ 250 | modulesFlake.modules.foo.example 251 | ]; 252 | }).config.foo.example == "works in foo application"; 253 | 254 | assert specialArgFlake.foo; 255 | 256 | assert builtins.isAttrs partitionWithoutExtraInputsFlake.devShells.x86_64-linux; 257 | 258 | ok; 259 | 260 | result = runTests "ok"; 261 | } 262 | -------------------------------------------------------------------------------- /dev/tests/template.nix: -------------------------------------------------------------------------------- 1 | { hci-effects, nix, git, path }: 2 | 3 | hci-effects.mkEffect { 4 | inputs = [ nix git ]; 5 | effectScript = '' 6 | ann() { # announce 7 | printf '\n\e[34;1m%s\e[0m\n' "$*" 8 | } 9 | mkdir -p ~/.config/nix 10 | echo 'experimental-features = nix-command flakes' >>~/.config/nix/nix.conf 11 | mkdir clean 12 | cd clean 13 | 14 | ann nix flake init... 15 | nix -v flake init -t ${../..} 16 | 17 | ann pointing to local sources... 18 | 19 | override=(--override-input flake-parts ${../..}) 20 | 21 | ann nix flake lock... 22 | nix flake lock "''${override[@]}" 23 | 24 | ann nix flake show... 25 | nix -v flake show "''${override[@]}" 26 | 27 | ann nix build... 28 | nix build . "''${override[@]}" 29 | 30 | ann checking result... 31 | readlink ./result | grep hello 32 | 33 | echo 34 | printf '\n\e[32;1m%s\e[0m\n' 'All good!' 35 | ''; 36 | } 37 | -------------------------------------------------------------------------------- /examples/project-commands/Hello.avdl: -------------------------------------------------------------------------------- 1 | protocol Hello { 2 | record Hello { 3 | string message; 4 | int timestamp; 5 | } 6 | } -------------------------------------------------------------------------------- /examples/project-commands/README.md: -------------------------------------------------------------------------------- 1 | # project-commands 2 | 3 | > **Warning** 4 | > If you copy the flake.nix remember to `git add [-N|--intent-to-add] flake.nix`, otherwise it won't work 5 | 6 | This example shows how to create scripts for your project, by leveraging [mission-control](https://github.com/Platonic-Systems/mission-control) 7 | 8 | This is a **potential** alternative to: 9 | 10 | - Using a `Makefile` to manage your project's scripts 11 | - Using the popular [Scripts To Rule Them All](https://github.com/github/scripts-to-rule-them-all); a naming convention for a `scripts/` directory 12 | - Using a `bin/` directory 13 | 14 | ## Explanation 15 | 16 | In this example we use the [avro-tools](https://avro.apache.org/) to convert our scripts from `.avdl` to `.avsc`. 17 | 18 | You don't need to know anything about avro to understand mission-control and use this example (that's Nix baby 🚀). 19 | 20 | When setting up [mission-control](https://github.com/Platonic-Systems/mission-control), we add 21 | one script called `build`. Because of `wrapperName = "run";`, once we open the shell created by nix, 22 | the commands will be listed as `run build`. 23 | 24 | mission-control depends on flake-root, which also exposes the helpful `$FLAKE_ROOT` variable. 25 | 26 | After creating the scripts, we need to pass the newly created scripts to the desired shell, in this example we use the default shell. 27 | 28 | ## Usage 29 | 30 | Run: 31 | 32 | ```sh 33 | nix develop 34 | ``` 35 | 36 | And mission-control will print in the new shell the available commands (you should see only one). 37 | 38 | Try running 39 | 40 | ```sh 41 | run build 42 | ``` 43 | -------------------------------------------------------------------------------- /examples/project-commands/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-parts": { 4 | "inputs": { 5 | "nixpkgs-lib": "nixpkgs-lib" 6 | }, 7 | "locked": { 8 | "lastModified": 1685662779, 9 | "narHash": "sha256-cKDDciXGpMEjP1n6HlzKinN0H+oLmNpgeCTzYnsA2po=", 10 | "owner": "hercules-ci", 11 | "repo": "flake-parts", 12 | "rev": "71fb97f0d875fd4de4994dfb849f2c75e17eb6c3", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "id": "flake-parts", 17 | "type": "indirect" 18 | } 19 | }, 20 | "flake-root": { 21 | "locked": { 22 | "lastModified": 1680964220, 23 | "narHash": "sha256-dIdTYcf+KW9a4pKHsEbddvLVSfR1yiAJynzg2x0nfWg=", 24 | "owner": "srid", 25 | "repo": "flake-root", 26 | "rev": "f1c0b93d05bdbea6c011136ba1a135c80c5b326c", 27 | "type": "github" 28 | }, 29 | "original": { 30 | "owner": "srid", 31 | "repo": "flake-root", 32 | "type": "github" 33 | } 34 | }, 35 | "mission-control": { 36 | "locked": { 37 | "lastModified": 1683658484, 38 | "narHash": "sha256-JkGnWyYZxOnyOhztrxLSqaod6+O/3rRypq0dAqA/zn0=", 39 | "owner": "Platonic-Systems", 40 | "repo": "mission-control", 41 | "rev": "a0c93bd764a3c25e6999397e9f5f119c1b124e38", 42 | "type": "github" 43 | }, 44 | "original": { 45 | "owner": "Platonic-Systems", 46 | "repo": "mission-control", 47 | "type": "github" 48 | } 49 | }, 50 | "nixpkgs": { 51 | "locked": { 52 | "lastModified": 1687502512, 53 | "narHash": "sha256-dBL/01TayOSZYxtY4cMXuNCBk8UMLoqRZA+94xiFpJA=", 54 | "owner": "NixOS", 55 | "repo": "nixpkgs", 56 | "rev": "3ae20aa58a6c0d1ca95c9b11f59a2d12eebc511f", 57 | "type": "github" 58 | }, 59 | "original": { 60 | "owner": "NixOS", 61 | "ref": "nixos-unstable", 62 | "repo": "nixpkgs", 63 | "type": "github" 64 | } 65 | }, 66 | "nixpkgs-lib": { 67 | "locked": { 68 | "dir": "lib", 69 | "lastModified": 1685564631, 70 | "narHash": "sha256-8ywr3AkblY4++3lIVxmrWZFzac7+f32ZEhH/A8pNscI=", 71 | "owner": "NixOS", 72 | "repo": "nixpkgs", 73 | "rev": "4f53efe34b3a8877ac923b9350c874e3dcd5dc0a", 74 | "type": "github" 75 | }, 76 | "original": { 77 | "dir": "lib", 78 | "owner": "NixOS", 79 | "ref": "nixos-unstable", 80 | "repo": "nixpkgs", 81 | "type": "github" 82 | } 83 | }, 84 | "root": { 85 | "inputs": { 86 | "flake-parts": "flake-parts", 87 | "flake-root": "flake-root", 88 | "mission-control": "mission-control", 89 | "nixpkgs": "nixpkgs" 90 | } 91 | } 92 | }, 93 | "root": "root", 94 | "version": 7 95 | } 96 | -------------------------------------------------------------------------------- /examples/project-commands/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Description for the project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | 7 | mission-control.url = "github:Platonic-Systems/mission-control"; 8 | flake-root.url = "github:srid/flake-root"; 9 | }; 10 | 11 | outputs = inputs@{ flake-parts, ... }: 12 | flake-parts.lib.mkFlake { inherit inputs; } { 13 | imports = [ 14 | inputs.mission-control.flakeModule 15 | inputs.flake-root.flakeModule 16 | ]; 17 | systems = [ "x86_64-linux" "aarch64-darwin" "x86_64-darwin" ]; 18 | perSystem = { config, self', inputs', pkgs, system, ... }: { 19 | devShells.default = pkgs.mkShell { 20 | nativeBuildInputs = with pkgs; [ avro-tools ]; 21 | inputsFrom = [ config.mission-control.devShell config.flake-root.devShell ]; 22 | }; 23 | mission-control = { 24 | wrapperName = "run"; 25 | scripts = { 26 | build = { 27 | description = "convert files from .avdl to .avsc"; 28 | exec = '' 29 | avro-tools idl2schemata "$FLAKE_ROOT/Hello.avdl" . 30 | ''; 31 | category = "Development"; 32 | }; 33 | }; 34 | }; 35 | }; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /examples/shell-environments/README.md: -------------------------------------------------------------------------------- 1 | # shell-environment 2 | 3 | > **Warning** 4 | > If you copy the flake.nix remember to `git add [-N|--intent-to-add] flake.nix`, otherwise it won't work 5 | 6 | This example shows how to create a shell environment which 7 | includes a diverse set of tools: 8 | 9 | ```sh 10 | terraform 11 | wget 12 | bat 13 | nixpkgs-fmt 14 | ``` 15 | 16 | You can search for more packages in [nix packages](https://search.nixos.org/packages) 17 | 18 | ## Usage 19 | 20 | The [`devShells` option](https://flake.parts/options/flake-parts.html#opt-perSystem.devShells) is used by the following command: 21 | 22 | ```sh 23 | nix develop 24 | ``` 25 | 26 | You can have as many shells as you want, in this [flake.nix](./flake.nix), you also have 27 | `another_env` which includes `curl`. To open it: 28 | 29 | ```sh 30 | nix develop .#another_env 31 | ``` 32 | 33 | ## Troubleshooting 34 | 35 | ### I get bash instead of my shell 36 | 37 | `nix develop` was designed for Nixpkgs stdenv, which uses bash, so that you can troubleshoot a Nix build with it. If you use a different shell, you'll want to get just the variables instead. 38 | 39 | There are 3 possible solutions: 40 | 41 | First, using [direnv](https://direnv.net/) to manage your dev environments. See [direnv-guide](https://haskell.flake.page/direnv). This is the recommended approach. 42 | 43 | Second is a simple-unreliable hack, which is adding a `shellHook` to `devShells` 44 | 45 | ```nix 46 | devShells.default = pkgs.mkShell { 47 | shellHook = '' 48 | exec $SHELL 49 | ''; 50 | }; 51 | ``` 52 | 53 | You might get a lot different issues, use it at your own risk. 54 | 55 | Lastly, there's `nix print-dev-env` which returns the variables - in case you're feeling adventurous, because this is far from a complete solution. See `nix print-dev-env --help`. 56 | -------------------------------------------------------------------------------- /examples/shell-environments/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-parts": { 4 | "inputs": { 5 | "nixpkgs-lib": "nixpkgs-lib" 6 | }, 7 | "locked": { 8 | "lastModified": 1685662779, 9 | "narHash": "sha256-cKDDciXGpMEjP1n6HlzKinN0H+oLmNpgeCTzYnsA2po=", 10 | "owner": "hercules-ci", 11 | "repo": "flake-parts", 12 | "rev": "71fb97f0d875fd4de4994dfb849f2c75e17eb6c3", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "id": "flake-parts", 17 | "type": "indirect" 18 | } 19 | }, 20 | "nixpkgs": { 21 | "locked": { 22 | "lastModified": 1687412861, 23 | "narHash": "sha256-Z/g0wbL68C+mSGerYS2quv9FXQ1RRP082cAC0Bh4vcs=", 24 | "owner": "NixOS", 25 | "repo": "nixpkgs", 26 | "rev": "e603dc5f061ca1d8a19b3ede6a8cf9c9fcba6cdc", 27 | "type": "github" 28 | }, 29 | "original": { 30 | "owner": "NixOS", 31 | "ref": "nixos-unstable", 32 | "repo": "nixpkgs", 33 | "type": "github" 34 | } 35 | }, 36 | "nixpkgs-lib": { 37 | "locked": { 38 | "dir": "lib", 39 | "lastModified": 1685564631, 40 | "narHash": "sha256-8ywr3AkblY4++3lIVxmrWZFzac7+f32ZEhH/A8pNscI=", 41 | "owner": "NixOS", 42 | "repo": "nixpkgs", 43 | "rev": "4f53efe34b3a8877ac923b9350c874e3dcd5dc0a", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "dir": "lib", 48 | "owner": "NixOS", 49 | "ref": "nixos-unstable", 50 | "repo": "nixpkgs", 51 | "type": "github" 52 | } 53 | }, 54 | "root": { 55 | "inputs": { 56 | "flake-parts": "flake-parts", 57 | "nixpkgs": "nixpkgs" 58 | } 59 | } 60 | }, 61 | "root": "root", 62 | "version": 7 63 | } 64 | -------------------------------------------------------------------------------- /examples/shell-environments/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Description for the project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | }; 7 | 8 | outputs = inputs@{ flake-parts, ... }: 9 | flake-parts.lib.mkFlake { inherit inputs; } { 10 | systems = [ "x86_64-linux" "aarch64-darwin" "x86_64-darwin" ]; 11 | perSystem = { config, self', inputs', pkgs, system, ... }: { 12 | devShells.default = pkgs.mkShell { 13 | nativeBuildInputs = with pkgs; [ terraform wget bat nixpkgs-fmt ]; 14 | }; 15 | 16 | devShells.another_env = pkgs.mkShell { 17 | nativeBuildInputs = with pkgs; [ curl ]; 18 | }; 19 | }; 20 | 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /extras/easyOverlay.nix: -------------------------------------------------------------------------------- 1 | toplevel@{ lib, flake-parts-lib, getSystemIgnoreWarning, ... }: 2 | let 3 | inherit (flake-parts-lib) 4 | mkPerSystemOption; 5 | inherit (lib) 6 | mkOption 7 | types; 8 | in 9 | { 10 | options = { 11 | perSystem = mkPerSystemOption ({ config, extendModules, pkgs, ... }: { 12 | _file = ./easyOverlay.nix; 13 | options = { 14 | extendModules = mkOption { 15 | type = types.raw; 16 | default = extendModules; 17 | internal = true; 18 | }; 19 | overlayAttrs = mkOption { 20 | type = types.lazyAttrsOf types.raw; 21 | default = { }; 22 | description = '' 23 | Attributes to add to `overlays.default`. 24 | 25 | The `overlays.default` overlay will re-evaluate `perSystem` with 26 | the "prev" (or "super") overlay argument value as the `pkgs` module 27 | argument. The `easyOverlay` module also adds the `final` module 28 | argument, for the result of applying the overlay. 29 | 30 | When not in an overlay, `final` defaults to `pkgs` plus the generated 31 | overlay. This requires Nixpkgs to be re-evaluated, which is more 32 | expensive than setting `pkgs` to a Nixpkgs that already includes 33 | the necessary overlays that are required for the flake itself. 34 | 35 | See [Overlays](../overlays.html). 36 | ''; 37 | }; 38 | }; 39 | config = { 40 | _module.args.final = lib.mkDefault (pkgs.extend toplevel.config.flake.overlays.default); 41 | }; 42 | }); 43 | }; 44 | config = { 45 | flake.overlays.default = final: prev: 46 | let 47 | system = 48 | prev.stdenv.hostPlatform.system or ( 49 | prev.system or ( 50 | throw "Could not determine the `hostPlatform` of Nixpkgs. Was this overlay loaded as a Nixpkgs overlay, or was it loaded into something else?" 51 | ) 52 | ); 53 | perSys = (getSystemIgnoreWarning system).extendModules { 54 | modules = [ 55 | { 56 | _file = "flake-parts#flakeModules.easyOverlay/overlay-overrides"; 57 | _module.args.pkgs = lib.mkForce prev; 58 | _module.args.final = lib.mkForce final; 59 | } 60 | ]; 61 | }; 62 | in 63 | perSys.config.overlayAttrs; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /extras/flakeModules.nix: -------------------------------------------------------------------------------- 1 | { self, lib, flake-parts-lib, moduleLocation, ... }: 2 | let 3 | inherit (lib) 4 | mapAttrs 5 | mkOption 6 | types 7 | ; 8 | inherit (flake-parts-lib) 9 | mkAliasOptionModule 10 | ; 11 | 12 | flakeModulesOption = mkOption { 13 | type = types.lazyAttrsOf types.deferredModule; 14 | default = { }; 15 | apply = mapAttrs (k: v: { 16 | _file = "${toString moduleLocation}#flakeModules.${k}"; 17 | key = "${toString moduleLocation}#flakeModules.${k}"; 18 | imports = [ v ]; 19 | _class = "flake"; 20 | }); 21 | description = '' 22 | flake-parts modules for use by other flakes. 23 | 24 | If the flake defines only one module, it should be `flakeModules.default`. 25 | 26 | You can not read this option in defining the flake's own `imports`. Instead, you can 27 | put the module in question into its own file or let binding and reference 28 | it both in `imports` and export it with this option. 29 | 30 | See [Dogfood a Reusable Module](../dogfood-a-reusable-module.md) for details and an example. 31 | ''; 32 | }; 33 | in 34 | { 35 | options = { 36 | flake = mkOption { 37 | type = types.submoduleWith { 38 | modules = [ 39 | (mkAliasOptionModule [ "flakeModule" ] [ "flakeModules" "default" ]) 40 | { 41 | options.flakeModules = flakeModulesOption; 42 | } 43 | ]; 44 | }; 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /extras/modules.nix: -------------------------------------------------------------------------------- 1 | { lib, moduleLocation, ... }: 2 | let 3 | inherit (lib) 4 | mapAttrs 5 | mkOption 6 | types 7 | ; 8 | inherit (lib.strings) 9 | escapeNixIdentifier 10 | ; 11 | 12 | addInfo = class: moduleName: 13 | if class == "generic" 14 | then module: module 15 | else 16 | module: 17 | # TODO: set key? 18 | { 19 | _class = class; 20 | _file = "${toString moduleLocation}#modules.${escapeNixIdentifier class}.${escapeNixIdentifier moduleName}"; 21 | imports = [ module ]; 22 | }; 23 | in 24 | { 25 | options = { 26 | flake.modules = mkOption { 27 | type = types.lazyAttrsOf (types.lazyAttrsOf types.deferredModule); 28 | description = '' 29 | Groups of modules published by the flake. 30 | 31 | The outer attributes declare the [`class`](https://nixos.org/manual/nixpkgs/stable/#module-system-lib-evalModules-param-class) of the modules within it. 32 | The special attribute `generic` does not declare a class, allowing its modules to be used in any module class. 33 | ''; 34 | example = lib.literalExpression '' 35 | { 36 | # NixOS configurations are modules with class "nixos" 37 | nixos = { 38 | # You can define a module right here: 39 | noBoot = { config, ... }: { 40 | boot.loader.enable = false; 41 | }; 42 | # Or you may refer to it by file 43 | autoDeploy = ./nixos/auto-deploy.nix; 44 | # Or maybe you need both 45 | projectIcarus = { config, pkgs, ... }: { 46 | imports = [ ./nixos/project-icarus.nix ]; 47 | services.project-icarus.package = 48 | withSystem pkgs.stdenv.hostPlatform.system ({ config, ... }: 49 | config.packages.default 50 | ); 51 | }; 52 | }; 53 | # Flake-parts modules 54 | # If you're not just publishing a module, but also using it locally, 55 | # create a let binding to declare it before calling `mkFlake` so you can 56 | # use it in both places. 57 | flake = { 58 | foo = someModule; 59 | }; 60 | # Modules that can be loaded anywhere 61 | generic = { 62 | my-pkgs = { _module.args.my-pkgs = …; }; 63 | }; 64 | } 65 | ''; 66 | apply = mapAttrs (k: mapAttrs (addInfo k)); 67 | }; 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /extras/partitions.nix: -------------------------------------------------------------------------------- 1 | { lib, config, inputs, extendModules, partitionStack, self, ... }: 2 | let 3 | inherit (lib) 4 | literalMD 5 | mapAttrs 6 | mkOption 7 | optionalAttrs 8 | types 9 | ; 10 | 11 | partitionModule = { config, options, name, ... }: { 12 | options = { 13 | extraInputsFlake = mkOption { 14 | type = types.raw; 15 | description = '' 16 | Location of a flake whose inputs to add to the inputs module argument in the partition. 17 | Note that flake `follows` are resolved without any awareness of inputs that are not in the flake. 18 | As a consequence, a `follows` entry in the flake inputs can not refer to inputs that are not in that specific flake. 19 | 20 | Implementation note: if the type of `extraInputsFlake` is a path, it is loaded with an expression-based reimplementation of `builtins.getFlake`, as `getFlake` is incapable of loading paths in pure mode as of writing. 21 | ''; 22 | example = lib.literalExpression "./dev"; 23 | }; 24 | extraInputs = mkOption { 25 | type = types.lazyAttrsOf types.raw; 26 | description = '' 27 | Extra inputs to add to the inputs module argument in the partition. 28 | 29 | This can be used as a workaround for the fact that transitive inputs are locked in the "end user" flake. 30 | That's not desirable for inputs they don't need, such as development inputs. 31 | ''; 32 | default = { }; 33 | defaultText = literalMD '' 34 | if `extraInputsFlake` is set, then `builtins.getFlake extraInputsFlake`, else `{ }` 35 | ''; 36 | }; 37 | module = mkOption { 38 | type = (extendModules { 39 | specialArgs = 40 | let 41 | inputs2 = inputs // config.extraInputs // { 42 | self = self2; 43 | }; 44 | self2 = self // { 45 | inputs = inputs2; 46 | }; 47 | in 48 | { 49 | inputs = inputs2; 50 | self = self2; 51 | partitionStack = partitionStack ++ [ name ]; 52 | }; 53 | }).type; 54 | default = { }; 55 | description = '' 56 | A re-evaluation of the flake-parts top level modules. 57 | 58 | You may define config definitions, `imports`, etc here, and it can be read like any other submodule. 59 | ''; 60 | example = lib.literalExpression '' 61 | { 62 | imports = [ 63 | ./dev/flake-module.nix 64 | ]; 65 | } 66 | ''; 67 | visible = "shallow"; 68 | }; 69 | }; 70 | config = { 71 | extraInputs = lib.mkIf options.extraInputsFlake.isDefined ( 72 | let 73 | p = options.extraInputsFlake.value; 74 | flake = 75 | if builtins.typeOf p == "path" 76 | then get-flake p 77 | else builtins.getFlake p; 78 | in 79 | flake.inputs 80 | ); 81 | }; 82 | }; 83 | 84 | # Nix does not recognize that a flake like "${./dev}", which is a content 85 | # addressed store path is a pure input, so we have to fetch and wire it 86 | # manually with flake-compat. 87 | get-flake = src: (flake-compat { inherit src; system = throw "operating flake-compat in pure mode; system not allowed to be used"; }).outputs; 88 | # TODO: update 89 | flake-compat = import (builtins.fetchTarball { 90 | url = "https://github.com/edolstra/flake-compat/archive/9ed2ac151eada2306ca8c418ebd97807bb08f6ac.tar.gz"; 91 | sha256 = "sha256:063slk1np1g1dkh21a82x655kpja7p4pc74rb3lqankyrbbpy4hx"; 92 | }); 93 | 94 | in 95 | { 96 | options = { 97 | partitionedAttrs = mkOption { 98 | type = types.attrsOf types.str; 99 | default = { }; 100 | description = '' 101 | A set of flake output attributes that are taken from a partition instead of the default top level flake-parts evaluation. 102 | 103 | The attribute name refers to the flake output attribute name, and the value is the name of the partition to use. 104 | 105 | The flake attributes are overridden with `lib.mkForce` priority. 106 | 107 | See the `partitions` options to understand the purpose. 108 | ''; 109 | example = { 110 | "devShells" = "dev"; 111 | "checks" = "dev"; 112 | "herculesCI" = "dev"; 113 | }; 114 | }; 115 | partitions = mkOption { 116 | type = types.attrsOf (types.submodule partitionModule); 117 | default = { }; 118 | description = '' 119 | By partitioning the flake, you can avoid fetching inputs that are not 120 | needed for the evaluation of a particular attribute. 121 | 122 | Each partition is a distinct module system evaluation. This allows 123 | attributes of the final flake to be defined by multiple sets of modules, 124 | so that for example the `packages` attribute can be evaluated without 125 | loading development related inputs. 126 | 127 | While the module system does a good job at preserving laziness, the fact 128 | that a development related import can define `packages` means that 129 | in order to evaluate `packages`, you need to evaluate at least to the 130 | point where you can conclude that the development related import does 131 | not actually define a `packages` attribute. While the actual evaluation 132 | is cheap, it can only happen after fetching the input, which is not 133 | as cheap. 134 | ''; 135 | example = lib.literalExpression '' 136 | { 137 | dev = { 138 | extraInputsFlake = ./dev; 139 | module = ./dev/flake-module.nix; 140 | }; 141 | } 142 | ''; 143 | }; 144 | }; 145 | config = { 146 | # Default, overriden with specialArgs inside partitions. 147 | _module.args.partitionStack = [ ]; 148 | flake = optionalAttrs (partitionStack == [ ]) ( 149 | mapAttrs 150 | (attrName: partition: lib.mkForce (config.partitions.${partition}.module.flake.${attrName})) 151 | config.partitionedAttrs 152 | ); 153 | }; 154 | } 155 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs-lib": { 4 | "locked": { 5 | "lastModified": 1748740939, 6 | "narHash": "sha256-rQaysilft1aVMwF14xIdGS3sj1yHlI6oKQNBRTF40cc=", 7 | "owner": "nix-community", 8 | "repo": "nixpkgs.lib", 9 | "rev": "656a64127e9d791a334452c6b6606d17539476e2", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nix-community", 14 | "repo": "nixpkgs.lib", 15 | "type": "github" 16 | } 17 | }, 18 | "root": { 19 | "inputs": { 20 | "nixpkgs-lib": "nixpkgs-lib" 21 | } 22 | } 23 | }, 24 | "root": "root", 25 | "version": 7 26 | } 27 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Flake basics described using the module system"; 3 | 4 | inputs = { 5 | nixpkgs-lib.url = "github:nix-community/nixpkgs.lib"; 6 | }; 7 | 8 | outputs = inputs@{ nixpkgs-lib, ... }: 9 | let 10 | lib = import ./lib.nix { 11 | inherit (nixpkgs-lib) lib; 12 | # Extra info for version check message 13 | revInfo = 14 | if nixpkgs-lib?rev 15 | then " (nixpkgs-lib.rev: ${nixpkgs-lib.rev})" 16 | else ""; 17 | }; 18 | templates = { 19 | default = { 20 | path = ./template/default; 21 | description = '' 22 | A minimal flake using flake-parts. 23 | ''; 24 | }; 25 | multi-module = { 26 | path = ./template/multi-module; 27 | description = '' 28 | A minimal flake using flake-parts. 29 | ''; 30 | }; 31 | unfree = { 32 | path = ./template/unfree; 33 | description = '' 34 | A minimal flake using flake-parts importing nixpkgs with the unfree option. 35 | ''; 36 | }; 37 | package = { 38 | path = ./template/package; 39 | description = '' 40 | A flake with a simple package: 41 | - Nixpkgs 42 | - callPackage 43 | - src with fileset 44 | - a check with runCommand 45 | ''; 46 | }; 47 | }; 48 | flakeModules = { 49 | easyOverlay = ./extras/easyOverlay.nix; 50 | flakeModules = ./extras/flakeModules.nix; 51 | modules = ./extras/modules.nix; 52 | partitions = ./extras/partitions.nix; 53 | }; 54 | in 55 | lib.mkFlake { inherit inputs; } { 56 | systems = [ ]; 57 | imports = [ flakeModules.partitions ]; 58 | partitionedAttrs.checks = "dev"; 59 | partitionedAttrs.devShells = "dev"; 60 | partitionedAttrs.herculesCI = "dev"; 61 | partitions.dev.extraInputsFlake = ./dev; 62 | partitions.dev.module = { 63 | imports = [ ./dev/flake-module.nix ]; 64 | }; 65 | flake = { 66 | inherit lib templates flakeModules; 67 | }; 68 | }; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /lib.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | # Optionally a string with extra version info to be included in the error message 3 | # in case is lib is out of date. Empty or starts with space. 4 | , revInfo ? "" 5 | }: 6 | let 7 | inherit (lib) 8 | mkOption 9 | mkOptionType 10 | defaultFunctor 11 | isAttrs 12 | isFunction 13 | showOption 14 | throwIf 15 | types 16 | warnIf 17 | getAttrFromPath 18 | setAttrByPath 19 | attrByPath 20 | optionalAttrs 21 | ; 22 | inherit (lib.modules) 23 | mkAliasAndWrapDefsWithPriority; 24 | inherit (lib.types) 25 | path 26 | submoduleWith 27 | ; 28 | 29 | # Polyfill isFlake until Nix with https://github.com/NixOS/nix/pull/7207 is common 30 | isFlake = maybeFlake: 31 | if maybeFlake ? _type 32 | then maybeFlake._type == "flake" 33 | else maybeFlake ? inputs && maybeFlake ? outputs && maybeFlake ? sourceInfo; 34 | 35 | # Polyfill https://github.com/NixOS/nixpkgs/pull/163617 36 | deferredModuleWith = lib.deferredModuleWith or ( 37 | attrs@{ staticModules ? [ ] }: mkOptionType { 38 | name = "deferredModule"; 39 | description = "module"; 40 | check = x: isAttrs x || isFunction x || path.check x; 41 | merge = loc: defs: staticModules ++ map (def: lib.setDefaultModuleLocation "${def.file}, via option ${showOption loc}" def.value) defs; 42 | inherit (submoduleWith { modules = staticModules; }) 43 | getSubOptions 44 | getSubModules; 45 | substSubModules = m: deferredModuleWith (attrs // { 46 | staticModules = m; 47 | }); 48 | functor = defaultFunctor "deferredModuleWith" // { 49 | type = deferredModuleWith; 50 | payload = { 51 | inherit staticModules; 52 | }; 53 | binOp = lhs: rhs: { 54 | staticModules = lhs.staticModules ++ rhs.staticModules; 55 | }; 56 | }; 57 | } 58 | ); 59 | 60 | errorExample = '' 61 | For example: 62 | 63 | outputs = inputs@{ flake-parts, ... }: 64 | flake-parts.lib.mkFlake { inherit inputs; } { /* module */ }; 65 | 66 | To avoid an infinite recursion, *DO NOT* pass `self.inputs` and 67 | *DO NOT* pass `inherit (self) inputs`, but pass the output function 68 | arguments as `inputs` like above. 69 | ''; 70 | 71 | flake-parts-lib = rec { 72 | evalFlakeModule = 73 | args@ 74 | { inputs ? self.inputs 75 | , specialArgs ? { } 76 | 77 | # legacy 78 | , self ? inputs.self or (throw '' 79 | When invoking flake-parts, you must pass all the flake output arguments, 80 | and not just `self.inputs`. 81 | 82 | ${errorExample} 83 | '') 84 | , moduleLocation ? "${self.outPath}/flake.nix" 85 | }: 86 | let 87 | inputsPos = builtins.unsafeGetAttrPos "inputs" args; 88 | errorLocation = 89 | # Best case: user makes it explicit 90 | args.moduleLocation or ( 91 | # Slightly worse: Nix does not technically commit to unsafeGetAttrPos semantics 92 | if inputsPos != null 93 | then inputsPos.file 94 | # Slightly worse: self may not be valid when an error occurs 95 | else if args?inputs.self.outPath 96 | then args.inputs.self.outPath + "/flake.nix" 97 | # Fallback 98 | else "" 99 | ); 100 | in 101 | throwIf 102 | (!args?self && !args?inputs) '' 103 | When invoking flake-parts, you must pass in the flake output arguments. 104 | 105 | ${errorExample} 106 | '' 107 | warnIf 108 | (!args?inputs) '' 109 | When invoking flake-parts, it is recommended to pass all the flake output 110 | arguments in the `inputs` parameter. If you only pass `self`, it's not 111 | possible to use the `inputs` module argument in the module `imports`. 112 | 113 | Please pass the output function arguments. ${errorExample} 114 | '' 115 | 116 | (module: 117 | lib.evalModules { 118 | specialArgs = { 119 | inherit self flake-parts-lib moduleLocation; 120 | inputs = args.inputs or /* legacy, warned above */ self.inputs; 121 | } // specialArgs; 122 | modules = [ ./all-modules.nix (lib.setDefaultModuleLocation errorLocation module) ]; 123 | class = "flake"; 124 | } 125 | ); 126 | 127 | # Function to extract the default flakeModule from 128 | # what may be a flake, returning the argument unmodified 129 | # if it's not a flake. 130 | # 131 | # Useful to map over an 'imports' list to make it less 132 | # verbose in the common case. 133 | defaultModule = maybeFlake: 134 | if isFlake maybeFlake 135 | then maybeFlake.flakeModules.default or maybeFlake 136 | else maybeFlake; 137 | 138 | mkFlake = args: module: 139 | let 140 | eval = flake-parts-lib.evalFlakeModule args module; 141 | in 142 | eval.config.flake; 143 | 144 | # For extending options in an already declared submodule. 145 | # Workaround for https://github.com/NixOS/nixpkgs/issues/146882 146 | mkSubmoduleOptions = 147 | options: 148 | mkOption { 149 | type = types.submoduleWith { 150 | modules = [{ inherit options; }]; 151 | }; 152 | }; 153 | 154 | mkDeferredModuleType = 155 | module: 156 | deferredModuleWith { 157 | staticModules = [ module ]; 158 | }; 159 | mkPerSystemType = mkDeferredModuleType; 160 | 161 | mkDeferredModuleOption = 162 | module: 163 | mkOption { 164 | type = flake-parts-lib.mkPerSystemType module; 165 | }; 166 | mkPerSystemOption = mkDeferredModuleOption; 167 | 168 | # Helper function for defining a per-system option that 169 | # gets transposed by the usual flake system logic to a 170 | # top-level flake attribute. 171 | mkTransposedPerSystemModule = { name, option, file }: { 172 | _file = file; 173 | 174 | options = { 175 | flake = flake-parts-lib.mkSubmoduleOptions { 176 | ${name} = mkOption { 177 | type = types.lazyAttrsOf option.type; 178 | default = { }; 179 | description = '' 180 | See {option}`perSystem.${name}` for description and examples. 181 | ''; 182 | }; 183 | }; 184 | 185 | perSystem = flake-parts-lib.mkPerSystemOption { 186 | _file = file; 187 | 188 | options.${name} = option; 189 | }; 190 | }; 191 | 192 | config = { 193 | transposition.${name} = { }; 194 | }; 195 | }; 196 | 197 | # Needed pending https://github.com/NixOS/nixpkgs/pull/198450 198 | mkAliasOptionModule = from: to: { config, options, ... }: 199 | let 200 | fromOpt = getAttrFromPath from options; 201 | toOf = attrByPath to 202 | (abort "Renaming error: option `${showOption to}' does not exist."); 203 | toType = let opt = attrByPath to { } options; in opt.type or (types.submodule { }); 204 | in 205 | { 206 | options = setAttrByPath from (mkOption 207 | { 208 | visible = true; 209 | description = "Alias of {option}`${showOption to}`."; 210 | apply = x: (toOf config); 211 | } // optionalAttrs (toType != null) { 212 | type = toType; 213 | }); 214 | config = mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt; 215 | }; 216 | 217 | # Helper function for importing while preserving module location. To be added 218 | # in nixpkgs: https://github.com/NixOS/nixpkgs/pull/230588 219 | # I expect these functions to remain identical. This one will stick around 220 | # for a while to support older nixpkgs-lib. 221 | importApply = 222 | modulePath: staticArgs: 223 | lib.setDefaultModuleLocation modulePath (import modulePath staticArgs); 224 | }; 225 | 226 | # A best effort, lenient estimate. Please use a recent nixpkgs lib if you 227 | # override it at all. 228 | minVersion = "22.05"; 229 | 230 | in 231 | 232 | if builtins.compareVersions lib.version minVersion < 0 233 | then 234 | abort '' 235 | The nixpkgs-lib dependency of flake-parts was overridden but is too old. 236 | The minimum supported version of nixpkgs-lib is ${minVersion}, 237 | but the actual version is ${lib.version}${revInfo}. 238 | '' 239 | else 240 | 241 | flake-parts-lib 242 | -------------------------------------------------------------------------------- /modules/apps.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | inherit (flake-parts-lib) 8 | mkTransposedPerSystemModule 9 | ; 10 | 11 | getExe = lib.getExe or ( 12 | x: 13 | "${lib.getBin x}/bin/${x.meta.mainProgram or (throw ''Package ${x.name or ""} does not have meta.mainProgram set, so I don't know how to find the main executable. You can set meta.mainProgram, or pass the full path to executable, e.g. program = "''${pkg}/bin/foo"'')}" 14 | ); 15 | 16 | programType = lib.types.coercedTo derivationType getExe lib.types.str; 17 | 18 | derivationType = lib.types.package // { 19 | check = lib.isDerivation; 20 | }; 21 | 22 | appType = lib.types.submodule { 23 | options = { 24 | type = mkOption { 25 | type = lib.types.enum [ "app" ]; 26 | default = "app"; 27 | description = '' 28 | A type tag for `apps` consumers. 29 | ''; 30 | }; 31 | program = mkOption { 32 | type = programType; 33 | description = '' 34 | A path to an executable or a derivation with `meta.mainProgram`. 35 | ''; 36 | }; 37 | meta = mkOption { 38 | type = types.lazyAttrsOf lib.types.raw; 39 | default = { }; 40 | # TODO refer to Nix manual 2.25 41 | description = '' 42 | Metadata information about the app. 43 | Standardized in Nix at . 44 | 45 | Note: `nix flake check` is only aware of the `description` attribute in `meta`. 46 | ''; 47 | }; 48 | }; 49 | }; 50 | in 51 | mkTransposedPerSystemModule { 52 | name = "apps"; 53 | option = mkOption { 54 | type = types.lazyAttrsOf appType; 55 | default = { }; 56 | description = '' 57 | Programs runnable with nix run ``. 58 | ''; 59 | example = lib.literalExpression or lib.literalExample '' 60 | { 61 | default.program = "''${config.packages.hello}/bin/hello"; 62 | } 63 | ''; 64 | }; 65 | file = ./apps.nix; 66 | } 67 | -------------------------------------------------------------------------------- /modules/checks.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | inherit (flake-parts-lib) 8 | mkTransposedPerSystemModule 9 | ; 10 | in 11 | mkTransposedPerSystemModule { 12 | name = "checks"; 13 | option = mkOption { 14 | type = types.lazyAttrsOf types.package; 15 | default = { }; 16 | description = '' 17 | Derivations to be built by [`nix flake check`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake-check.html). 18 | ''; 19 | }; 20 | file = ./checks.nix; 21 | } 22 | -------------------------------------------------------------------------------- /modules/debug.nix: -------------------------------------------------------------------------------- 1 | { config, flake-parts-lib, lib, options, getSystem, extendModules, ... }: 2 | let 3 | inherit (lib) 4 | mapAttrs 5 | mkIf 6 | mkOption 7 | optionalAttrs 8 | types 9 | ; 10 | inherit (flake-parts-lib) 11 | mkPerSystemOption 12 | ; 13 | 14 | mkDebugConfig = { config, options, extendModules }: config // { 15 | inherit config; 16 | inherit (config) _module; 17 | inherit options; 18 | inherit extendModules; 19 | }; 20 | in 21 | { 22 | options = { 23 | debug = mkOption { 24 | type = types.bool; 25 | default = false; 26 | description = '' 27 | Whether to add the attributes `debug`, `allSystems` and `currentSystem` 28 | to the flake output. When `true`, this allows inspection of options via 29 | `nix repl`. 30 | 31 | ``` 32 | $ nix repl 33 | nix-repl> :lf . 34 | nix-repl> currentSystem._module.args.pkgs.hello 35 | «derivation /nix/store/7vf0d0j7majv1ch1xymdylyql80cn5fp-hello-2.12.1.drv» 36 | ``` 37 | 38 | Each of `debug`, `allSystems.` and `currentSystem` is an 39 | attribute set consisting of the `config` attributes, plus the extra 40 | attributes `_module`, `config`, `options`, `extendModules`. So note that 41 | these are not part of the `config` parameter, but are merged in for 42 | debugging convenience. 43 | 44 | - `debug`: The top-level options 45 | - `allSystems`: The `perSystem` submodule applied to the configured `systems`. 46 | - `currentSystem`: Shortcut into `allSystems`. Only available in impure mode. 47 | Works for arbitrary system values. 48 | 49 | See [Expore and debug option values](../debug.html) for more examples. 50 | ''; 51 | }; 52 | perSystem = mkPerSystemOption 53 | ({ options, config, extendModules, ... }: { 54 | _file = ./formatter.nix; 55 | options = { 56 | debug = mkOption { 57 | description = '' 58 | Values to return in e.g. `allSystems.` when 59 | [`debug = true`](#opt-debug). 60 | ''; 61 | type = types.lazyAttrsOf types.raw; 62 | }; 63 | }; 64 | config = { 65 | debug = mkDebugConfig { inherit config options extendModules; }; 66 | }; 67 | }); 68 | }; 69 | 70 | config = mkIf config.debug { 71 | flake = { 72 | debug = mkDebugConfig { inherit config options extendModules; }; 73 | allSystems = mapAttrs (_s: c: c.debug) config.allSystems; 74 | } // optionalAttrs (builtins?currentSystem) { 75 | currentSystem = (getSystem builtins.currentSystem).debug; 76 | }; 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /modules/devShells.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | literalExpression 7 | ; 8 | inherit (flake-parts-lib) 9 | mkTransposedPerSystemModule 10 | ; 11 | in 12 | mkTransposedPerSystemModule { 13 | name = "devShells"; 14 | option = mkOption { 15 | type = types.lazyAttrsOf types.package; 16 | default = { }; 17 | description = '' 18 | An attribute set of packages to be used as shells. 19 | [`nix develop .#`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html) will run `devShells.`. 20 | ''; 21 | example = literalExpression '' 22 | { 23 | default = pkgs.mkShell { 24 | nativeBuildInputs = with pkgs; [ wget bat cargo ]; 25 | }; 26 | } 27 | ''; 28 | }; 29 | file = ./devShells.nix; 30 | } 31 | -------------------------------------------------------------------------------- /modules/flake.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | in 8 | { 9 | options = { 10 | flake = mkOption { 11 | type = types.submoduleWith { 12 | modules = [ 13 | { 14 | freeformType = 15 | types.lazyAttrsOf 16 | (types.unique 17 | { 18 | message = '' 19 | No option has been declared for this flake output attribute, so its definitions can't be merged automatically. 20 | Possible solutions: 21 | - Load a module that defines this flake output attribute 22 | Many modules are listed at https://flake.parts 23 | - Declare an option for this flake output attribute 24 | - Make sure the output attribute is spelled correctly 25 | - Define the value only once, with a single definition in a single module 26 | ''; 27 | } 28 | types.raw); 29 | } 30 | ]; 31 | }; 32 | description = '' 33 | Raw flake output attributes. Any attribute can be set here, but some 34 | attributes are represented by options, to provide appropriate 35 | configuration merging. 36 | ''; 37 | }; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /modules/formatter.nix: -------------------------------------------------------------------------------- 1 | { config, lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | filterAttrs 5 | mapAttrs 6 | mkOption 7 | optionalAttrs 8 | types 9 | ; 10 | inherit (flake-parts-lib) 11 | mkSubmoduleOptions 12 | mkPerSystemOption 13 | ; 14 | in 15 | { 16 | options = { 17 | flake = mkSubmoduleOptions { 18 | formatter = mkOption { 19 | type = types.lazyAttrsOf types.package; 20 | default = { }; 21 | description = '' 22 | An attribute set of per system a package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html). 23 | ''; 24 | }; 25 | }; 26 | 27 | perSystem = mkPerSystemOption { 28 | _file = ./formatter.nix; 29 | options = { 30 | formatter = mkOption { 31 | type = types.nullOr types.package; 32 | default = null; 33 | description = '' 34 | A package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html). 35 | ''; 36 | }; 37 | }; 38 | }; 39 | }; 40 | config = { 41 | flake.formatter = 42 | mapAttrs 43 | (k: v: v.formatter) 44 | (filterAttrs 45 | (k: v: v.formatter != null) 46 | config.allSystems 47 | ); 48 | 49 | perInput = system: flake: 50 | optionalAttrs (flake?formatter.${system}) { 51 | formatter = flake.formatter.${system}; 52 | }; 53 | 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /modules/legacyPackages.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | inherit (flake-parts-lib) 8 | mkTransposedPerSystemModule 9 | ; 10 | in 11 | mkTransposedPerSystemModule { 12 | name = "legacyPackages"; 13 | option = mkOption { 14 | type = types.lazyAttrsOf types.raw; 15 | default = { }; 16 | description = '' 17 | An attribute set of unmergeable values. This is also used by [`nix build .#`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-build.html). 18 | ''; 19 | }; 20 | file = ./legacyPackages.nix; 21 | } 22 | -------------------------------------------------------------------------------- /modules/moduleWithSystem.nix: -------------------------------------------------------------------------------- 1 | { withSystem, ... }: 2 | { 3 | config = { 4 | _module.args = { 5 | moduleWithSystem = 6 | module: 7 | 8 | { config, ... }: 9 | let 10 | system = 11 | config._module.args.system or 12 | config._module.args.pkgs.stdenv.hostPlatform.system or 13 | (throw "moduleWithSystem: Could not determine the configuration's system parameter for this module system application."); 14 | 15 | allArgs = withSystem system (args: args); 16 | 17 | lazyArgsPerParameter = f: builtins.mapAttrs 18 | (k: v: allArgs.${k} or (throw "moduleWithSystem: module argument `${k}` does not exist.")) 19 | (builtins.functionArgs f); 20 | 21 | # Use reflection to make the call lazy in the argument. 22 | # Restricts args to the ones declared. 23 | callLazily = f: a: f (lazyArgsPerParameter f); 24 | in 25 | { 26 | imports = [ 27 | (callLazily module allArgs) 28 | ]; 29 | }; 30 | }; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /modules/nixosConfigurations.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | literalExpression 7 | ; 8 | inherit (flake-parts-lib) 9 | mkSubmoduleOptions 10 | ; 11 | in 12 | { 13 | options = { 14 | flake = mkSubmoduleOptions { 15 | nixosConfigurations = mkOption { 16 | type = types.lazyAttrsOf types.raw; 17 | default = { }; 18 | description = '' 19 | Instantiated NixOS configurations. Used by `nixos-rebuild`. 20 | 21 | `nixosConfigurations` is for specific machines. If you want to expose 22 | reusable configurations, add them to [`nixosModules`](#opt-flake.nixosModules) 23 | in the form of modules (no `lib.nixosSystem`), so that you can reference 24 | them in this or another flake's `nixosConfigurations`. 25 | ''; 26 | example = literalExpression '' 27 | { 28 | my-machine = inputs.nixpkgs.lib.nixosSystem { 29 | # system is not needed with freshly generated hardware-configuration.nix 30 | # system = "x86_64-linux"; # or set nixpkgs.hostPlatform in a module. 31 | modules = [ 32 | ./my-machine/nixos-configuration.nix 33 | config.nixosModules.my-module 34 | ]; 35 | }; 36 | } 37 | ''; 38 | }; 39 | }; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /modules/nixosModules.nix: -------------------------------------------------------------------------------- 1 | { self, lib, flake-parts-lib, moduleLocation, ... }: 2 | let 3 | inherit (lib) 4 | mapAttrs 5 | mkOption 6 | types 7 | ; 8 | inherit (flake-parts-lib) 9 | mkSubmoduleOptions 10 | ; 11 | in 12 | { 13 | options = { 14 | flake = mkSubmoduleOptions { 15 | nixosModules = mkOption { 16 | type = types.lazyAttrsOf types.deferredModule; 17 | default = { }; 18 | apply = mapAttrs (k: v: { _file = "${toString moduleLocation}#nixosModules.${k}"; imports = [ v ]; }); 19 | description = '' 20 | NixOS modules. 21 | 22 | You may use this for reusable pieces of configuration, service modules, etc. 23 | ''; 24 | }; 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/nixpkgs.nix: -------------------------------------------------------------------------------- 1 | # 2 | # Nixpkgs module. The only exception to the rule. 3 | # 4 | # Provides a `pkgs` argument in `perSystem`. 5 | # 6 | # Arguably, this shouldn't be in flake-parts, but in nixpkgs. 7 | # Nixpkgs could define its own module that does this, which would be 8 | # a more consistent UX, but for now this will do. 9 | # 10 | # The existence of this module does not mean that other flakes' logic 11 | # will be accepted into flake-parts, because it's against the 12 | # spirit of Flakes. 13 | # 14 | { 15 | config = { 16 | perSystem = { inputs', lib, ... }: { 17 | config = { 18 | _module.args.pkgs = lib.mkOptionDefault ( 19 | builtins.seq 20 | (inputs'.nixpkgs or (throw "flake-parts: The flake does not have a `nixpkgs` input. Please add it, or set `perSystem._module.args.pkgs` yourself.")) 21 | inputs'.nixpkgs.legacyPackages 22 | ); 23 | }; 24 | }; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /modules/overlays.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | inherit (flake-parts-lib) 8 | mkSubmoduleOptions 9 | ; 10 | in 11 | { 12 | options = { 13 | flake = mkSubmoduleOptions { 14 | overlays = mkOption { 15 | # uniq -> ordered: https://github.com/NixOS/nixpkgs/issues/147052 16 | # also update description when done 17 | type = types.lazyAttrsOf (types.uniq (types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified)))); 18 | # This eta expansion exists for the sole purpose of making nix flake check happy. 19 | apply = lib.mapAttrs (_k: f: final: prev: f final prev); 20 | default = { }; 21 | example = lib.literalExpression or lib.literalExample '' 22 | { 23 | default = final: prev: {}; 24 | } 25 | ''; 26 | description = '' 27 | An attribute set of [overlays](https://nixos.org/manual/nixpkgs/stable/#chap-overlays). 28 | 29 | Note that the overlays themselves are not mergeable. While overlays 30 | can be composed, the order of composition is significant, but the 31 | module system does not guarantee sufficiently deterministic 32 | definition ordering, across versions and when changing `imports`. 33 | ''; 34 | }; 35 | }; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /modules/packages.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | inherit (flake-parts-lib) 8 | mkTransposedPerSystemModule 9 | ; 10 | in 11 | mkTransposedPerSystemModule { 12 | name = "packages"; 13 | option = mkOption { 14 | type = types.lazyAttrsOf types.package; 15 | default = { }; 16 | description = '' 17 | An attribute set of packages to be built by [`nix build`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-build.html). 18 | 19 | `nix build .#` will build `packages.`. 20 | ''; 21 | }; 22 | file = ./packages.nix; 23 | } 24 | -------------------------------------------------------------------------------- /modules/perSystem.nix: -------------------------------------------------------------------------------- 1 | { config, lib, flake-parts-lib, self, ... }: 2 | let 3 | inherit (lib) 4 | genAttrs 5 | mapAttrs 6 | mkOption 7 | types 8 | ; 9 | inherit (lib.strings) 10 | escapeNixIdentifier 11 | ; 12 | inherit (flake-parts-lib) 13 | mkPerSystemType 14 | ; 15 | 16 | rootConfig = config; 17 | 18 | # Stubs for self and inputs. While it'd be possible to define aliases 19 | # inside perSystem, that is not a general solution, and it would make 20 | # top.config harder to discover, stretching the learning curve rather 21 | # than flattening it. 22 | 23 | throwAliasError' = param: 24 | throw '' 25 | `${param}` (without `'`) is not a `perSystem` module argument, but a 26 | module argument of the top level config. 27 | 28 | The following is an example usage of `${param}`. Note that its binding 29 | is in the `top` parameter list, which is declared by the top level module 30 | rather than the `perSystem` module. 31 | 32 | top@{ config, lib, ${param}, ... }: { 33 | perSystem = { config, ${param}', ... }: { 34 | # in scope here: 35 | # - ${param} 36 | # - ${param}' 37 | # - config (of perSystem) 38 | # - top.config (note the `top@` pattern) 39 | }; 40 | } 41 | ''; 42 | 43 | throwAliasError = param: 44 | throw '' 45 | `${param}` is not a `perSystem` module argument, but a module argument of 46 | the top level config. 47 | 48 | The following is an example usage of `${param}`. Note that its binding 49 | is in the `top` parameter list, which is declared by the top level module 50 | rather than the `perSystem` module. 51 | 52 | top@{ config, lib, ${param}, ... }: { 53 | perSystem = { config, ... }: { 54 | # in scope here: 55 | # - ${param} 56 | # - config (of perSystem) 57 | # - top.config (note the `top@` pattern) 58 | }; 59 | } 60 | ''; 61 | 62 | in 63 | { 64 | options = { 65 | systems = mkOption { 66 | description = '' 67 | All the system types to enumerate in the flake output subattributes. 68 | 69 | In other words, all valid values for `system` in e.g. `packages..foo`. 70 | ''; 71 | type = types.listOf types.str; 72 | }; 73 | 74 | perInput = mkOption { 75 | description = '' 76 | A function that pre-processes flake inputs. 77 | 78 | It is called for users of `perSystem` such that `inputs'.''${name} = config.perInput system inputs.''${name}`. 79 | 80 | This is used for [`inputs'`](../module-arguments.html#inputs) and [`self'`](../module-arguments.html#self). 81 | 82 | The attributes returned by the `perInput` function definitions are merged into a single namespace (per input), 83 | so each module should return an attribute set with usually only one or two predictable attribute names. Otherwise, 84 | the `inputs'` namespace gets polluted. 85 | ''; 86 | type = types.functionTo (types.functionTo (types.lazyAttrsOf types.unspecified)); 87 | }; 88 | 89 | perSystem = mkOption { 90 | description = '' 91 | A function from system to flake-like attributes omitting the `` attribute. 92 | 93 | Modules defined here have access to the suboptions and [some convenient module arguments](../module-arguments.html). 94 | ''; 95 | type = mkPerSystemType ({ config, system, ... }: { 96 | _file = ./perSystem.nix; 97 | config = { 98 | _module.args.inputs' = 99 | mapAttrs 100 | (inputName: input: 101 | builtins.addErrorContext "while retrieving system-dependent attributes for input ${escapeNixIdentifier inputName}" ( 102 | if input._type or null == "flake" 103 | then rootConfig.perInput system input 104 | else 105 | throw "Trying to retrieve system-dependent attributes for input ${escapeNixIdentifier inputName}, but this input is not a flake. Perhaps flake = false was added to the input declarations by mistake, or you meant to use a different input, or you meant to use plain old inputs, not inputs'." 106 | ) 107 | ) 108 | self.inputs; 109 | _module.args.self' = 110 | builtins.addErrorContext "while retrieving system-dependent attributes for a flake's own outputs" ( 111 | rootConfig.perInput system self 112 | ); 113 | 114 | # Custom error messages 115 | _module.args.self = throwAliasError' "self"; 116 | _module.args.inputs = throwAliasError' "inputs"; 117 | _module.args.getSystem = throwAliasError "getSystem"; 118 | _module.args.withSystem = throwAliasError "withSystem"; 119 | _module.args.moduleWithSystem = throwAliasError "moduleWithSystem"; 120 | }; 121 | }); 122 | apply = modules: system: 123 | (lib.evalModules { 124 | inherit modules; 125 | prefix = [ "perSystem" system ]; 126 | specialArgs = { 127 | inherit system; 128 | }; 129 | class = "perSystem"; 130 | }).config; 131 | }; 132 | 133 | allSystems = mkOption { 134 | type = types.lazyAttrsOf types.unspecified; 135 | description = "The system-specific config for each of systems."; 136 | internal = true; 137 | }; 138 | }; 139 | 140 | config = { 141 | allSystems = genAttrs config.systems config.perSystem; 142 | # TODO: Sub-optimal error message. Get Nix to support a memoization primop, or get Nix Flakes to support systems properly or get Nix Flakes to add a name to flakes. 143 | _module.args.getSystem = system: config.allSystems.${system} or (builtins.trace "using non-memoized system ${system}" config.perSystem system); 144 | 145 | # The warning is there for a reason. Only use this in situations where the 146 | # performance cost has already been incurred, such as in `flakeModules.easyOverlay`, 147 | # where we run in the context of an overlay, and the performance cost of the 148 | # extra `pkgs` makes the cost of running `perSystem` probably negligible. 149 | _module.args.getSystemIgnoreWarning = system: config.allSystems.${system} or (config.perSystem system); 150 | }; 151 | 152 | } 153 | -------------------------------------------------------------------------------- /modules/transposition.nix: -------------------------------------------------------------------------------- 1 | { config, lib, flake-parts-lib, ... }: 2 | 3 | let 4 | inherit (lib) 5 | filterAttrs 6 | mapAttrs 7 | mkOption 8 | types 9 | ; 10 | inherit (lib.strings) 11 | escapeNixIdentifier 12 | ; 13 | 14 | transpositionModule = { 15 | options = { 16 | adHoc = mkOption { 17 | type = types.bool; 18 | default = false; 19 | description = '' 20 | Whether to provide a stub option declaration for {option}`perSystem.`. 21 | 22 | The stub option declaration does not support merging and lacks 23 | documentation, so you are recommended to declare the {option}`perSystem.` 24 | option yourself and avoid {option}`adHoc`. 25 | ''; 26 | }; 27 | }; 28 | }; 29 | 30 | perInputAttributeError = { flake, attrName, system, attrConfig }: 31 | # This uses flake.outPath for lack of a better identifier. 32 | # Consider adding a perInput variation that has a normally-redundant argument for the input name. 33 | # Tested manually with 34 | # perSystem = { inputs', ... }: { 35 | # packages.extra = inputs'.nixpkgs.extra; 36 | # packages.default = inputs'.nixpkgs.packages.default; 37 | # packages.veryWrong = (top.config.perInput "x86_64-linux" inputs'.nixpkgs.legacyPackages.hello).packages.default; 38 | # }; 39 | # transposition.extra = {}; 40 | let 41 | attrPath = "${escapeNixIdentifier attrName}.${escapeNixIdentifier system}"; 42 | flakeIdentifier = 43 | if flake._type or null != "flake" 44 | then 45 | throw "An attempt was made to access attribute ${attrPath} on a value that's supposed to be a flake, but may not be a proper flake." 46 | else 47 | builtins.addErrorContext "while trying to find out how to describe what is supposedly a flake, whose attribute ${attrPath} was accessed but does not exist" ( 48 | toString flake.outPath 49 | ); 50 | # This ought to be generalized by extending attrConfig, but this is the only known and common mistake for now. 51 | alternateAttrNameHint = 52 | if attrName == "packages" && flake?legacyPackages 53 | then # Unfortunately we can't just switch them out, because that will put packages *sets* where single packages are expected in user code, resulting in potentially much worse and more confusing errors down the line. 54 | "\nIt does define legacyPackages; try that instead?" 55 | else ""; 56 | in 57 | if flake?${attrName} 58 | then 59 | throw '' 60 | Attempt to access ${attrPath} of flake ${flakeIdentifier}, but it does not have it. 61 | It does have attribute ${escapeNixIdentifier attrName}, so it appears that it does not support system type ${escapeNixIdentifier system}. 62 | '' 63 | else 64 | throw '' 65 | Attempt to access ${attrPath} of flake ${flakeIdentifier}, but it does not have attribute ${escapeNixIdentifier attrName}.${alternateAttrNameHint} 66 | ''; 67 | 68 | 69 | in 70 | { 71 | options = { 72 | transposition = lib.mkOption { 73 | description = '' 74 | A helper that defines transposed attributes in the flake outputs. 75 | 76 | When you define `transposition.foo = { };`, definitions are added to the effect of (pseudo-code): 77 | 78 | ```nix 79 | flake.foo.''${system} = (perSystem system).foo; 80 | perInput = system: inputFlake: inputFlake.foo.''${system}; 81 | ``` 82 | 83 | Transposition is the operation that swaps the indices of a data structure. 84 | Here it refers specifically to the transposition between 85 | 86 | ```plain 87 | perSystem: .''${system}.''${attribute} 88 | outputs: .''${attribute}.''${system} 89 | ``` 90 | 91 | It also defines the reverse operation in [{option}`perInput`](#opt-perInput). 92 | ''; 93 | type = 94 | types.lazyAttrsOf 95 | (types.submoduleWith { modules = [ transpositionModule ]; }); 96 | }; 97 | }; 98 | 99 | config = { 100 | flake = 101 | lib.mapAttrs 102 | (attrName: attrConfig: 103 | mapAttrs 104 | (system: v: v.${attrName} or ( 105 | abort '' 106 | Could not find option ${attrName} in the perSystem module. It is required to declare such an option whenever transposition. is defined (and in this instance is ${attrName}). 107 | '')) 108 | config.allSystems 109 | ) 110 | config.transposition; 111 | 112 | perInput = 113 | system: flake: 114 | mapAttrs 115 | (attrName: attrConfig: 116 | flake.${attrName}.${system} or ( 117 | throw (perInputAttributeError { inherit system flake attrName attrConfig; }) 118 | ) 119 | ) 120 | config.transposition; 121 | 122 | perSystem = { 123 | options = 124 | mapAttrs 125 | (k: v: lib.mkOption { }) 126 | (filterAttrs 127 | (k: v: v.adHoc) 128 | config.transposition 129 | ); 130 | }; 131 | }; 132 | } 133 | -------------------------------------------------------------------------------- /modules/withSystem.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, getSystem, ... }: 2 | let 3 | inherit (lib) 4 | mkOption 5 | types 6 | ; 7 | inherit (flake-parts-lib) 8 | mkPerSystemOption 9 | ; 10 | in 11 | { 12 | options = { 13 | perSystem = mkPerSystemOption ({ config, options, specialArgs, ... }: { 14 | _file = ./perSystem.nix; 15 | options = { 16 | allModuleArgs = mkOption { 17 | type = types.lazyAttrsOf (types.raw or types.unspecified); 18 | internal = true; 19 | readOnly = true; 20 | description = "Internal option that exposes _module.args, for use by withSystem."; 21 | }; 22 | }; 23 | config = { 24 | allModuleArgs = config._module.args // specialArgs // { inherit config options; }; 25 | }; 26 | }); 27 | }; 28 | 29 | config = { 30 | _module.args = { 31 | withSystem = 32 | system: f: 33 | f 34 | (getSystem system).allModuleArgs; 35 | }; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | (builtins.getFlake ("git+file://" + toString ./.)).devShells.${builtins.currentSystem}.default 2 | -------------------------------------------------------------------------------- /template/default/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Description for the project"; 3 | 4 | inputs = { 5 | flake-parts.url = "github:hercules-ci/flake-parts"; 6 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | imports = [ 12 | # To import a flake module 13 | # 1. Add foo to inputs 14 | # 2. Add foo as a parameter to the outputs function 15 | # 3. Add here: foo.flakeModule 16 | 17 | ]; 18 | systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; 19 | perSystem = { config, self', inputs', pkgs, system, ... }: { 20 | # Per-system attributes can be defined here. The self' and inputs' 21 | # module parameters provide easy access to attributes of the same 22 | # system. 23 | 24 | # Equivalent to inputs'.nixpkgs.legacyPackages.hello; 25 | packages.default = pkgs.hello; 26 | }; 27 | flake = { 28 | # The usual flake attributes can be defined here, including system- 29 | # agnostic ones like nixosModule and system-enumerating ones, although 30 | # those are more easily expressed in perSystem. 31 | 32 | }; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /template/multi-module/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Description for the project"; 3 | 4 | inputs = { 5 | flake-parts.url = "github:hercules-ci/flake-parts"; 6 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | imports = [ 12 | ./hello/flake-module.nix 13 | ]; 14 | systems = [ "x86_64-linux" "aarch64-darwin" ]; 15 | perSystem = { config, self', inputs', ... }: { 16 | # Per-system attributes can be defined here. The self' and inputs' 17 | # module parameters provide easy access to attributes of the same 18 | # system. 19 | 20 | packages.figlet = inputs'.nixpkgs.legacyPackages.figlet; 21 | }; 22 | flake = { 23 | # The usual flake attributes can be defined here, including system- 24 | # agnostic ones like nixosModule and system-enumerating ones, although 25 | # those are more easily expressed in perSystem. 26 | 27 | }; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /template/multi-module/hello/flake-module.nix: -------------------------------------------------------------------------------- 1 | # Definitions can be imported from a separate file like this one 2 | 3 | { self, lib, ... }: { 4 | perSystem = { config, self', inputs', pkgs, ... }: { 5 | # Definitions like this are entirely equivalent to the ones 6 | # you may have directly in flake.nix. 7 | packages.hello = pkgs.hello; 8 | }; 9 | flake = { 10 | nixosModules.hello = { pkgs, ... }: { 11 | environment.systemPackages = [ 12 | # or self.inputs.nixpkgs.legacyPackages.${pkgs.stdenv.hostPlatform.system}.hello 13 | self.packages.${pkgs.stdenv.hostPlatform.system}.hello 14 | ]; 15 | }; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /template/package/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Description for the project"; 3 | 4 | inputs = { 5 | flake-parts.url = "github:hercules-ci/flake-parts"; 6 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; 12 | perSystem = { config, pkgs, ... }: { 13 | packages.default = config.packages.hello; 14 | 15 | packages.hello = pkgs.callPackage ./hello/package.nix { }; 16 | 17 | checks.hello = pkgs.callPackage ./hello/test.nix { 18 | hello = config.packages.hello; 19 | }; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /template/package/hello/hello.sh: -------------------------------------------------------------------------------- 1 | #!@shell@ 2 | 3 | echo Hello world 4 | -------------------------------------------------------------------------------- /template/package/hello/package.nix: -------------------------------------------------------------------------------- 1 | { stdenv, lib, runtimeShell }: 2 | 3 | let 4 | # Bring fileset functions into scope. 5 | # See https://nixos.org/manual/nixpkgs/stable/index.html#sec-functions-library-fileset 6 | inherit (lib.fileset) toSource unions; 7 | in 8 | 9 | # Example package in the style that `mkDerivation`-based packages in Nixpkgs are written. 10 | stdenv.mkDerivation (finalAttrs: { 11 | name = "hello"; 12 | src = toSource { 13 | root = ./.; 14 | fileset = unions [ 15 | ./hello.sh 16 | ]; 17 | }; 18 | buildPhase = '' 19 | # Note that Nixpkgs has builder functions for simple packages 20 | # like this, but this template avoids it to make for a more 21 | # complete example. 22 | substitute hello.sh hello --replace '@shell@' ${runtimeShell} 23 | cat hello 24 | chmod a+x hello 25 | ''; 26 | installPhase = '' 27 | install -D hello $out/bin/hello 28 | ''; 29 | }) 30 | -------------------------------------------------------------------------------- /template/package/hello/test.nix: -------------------------------------------------------------------------------- 1 | { hello, runCommand }: 2 | 3 | runCommand "test-hello" 4 | { 5 | inherit hello; 6 | } '' 7 | ( 8 | set -x 9 | [[ "Hello world" == "$(${hello}/bin/hello)" ]] 10 | ) 11 | touch $out 12 | '' 13 | -------------------------------------------------------------------------------- /template/unfree/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Description for the project"; 3 | 4 | inputs = { 5 | flake-parts.url = "github:hercules-ci/flake-parts"; 6 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, nixpkgs, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-darwin" ]; 12 | perSystem = { pkgs, system, ... }: { 13 | # This sets `pkgs` to a nixpkgs with allowUnfree option set. 14 | _module.args.pkgs = import nixpkgs { 15 | inherit system; 16 | config.allowUnfree = true; 17 | }; 18 | 19 | packages.default = pkgs.hello-unfree; 20 | }; 21 | }; 22 | } 23 | --------------------------------------------------------------------------------