Generate flake.nix from module options. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic nix inputs

nixlock (#76)

authored by oeiuwq.com and committed by

GitHub e54fbd42 8a5c8771

+339 -73
+22 -3
.github/workflows/flake-check.yaml
··· 25 25 - test-inputs 26 26 - test-flake 27 27 - test-unflake 28 + - test-nixlock 28 29 - test-npins 29 30 - test-npins-follows 30 31 - test-npins-transitive ··· 82 83 cd templates/npins 83 84 sed -i 's/# flake-file = import/flake-file = import/' default.nix 84 85 echo "{ inputs, ... }: { npins.pkgs = import inputs.nixpkgs {}; }" | tee modules/pkgs.nix 85 - nix-shell . -A npins.env --run write-npins 86 + nix-shell . -A flake-file.sh --run write-npins 86 87 unflake: 87 88 needs: [dev] 88 89 name: Check unflake 89 90 runs-on: ubuntu-latest 90 91 if: ${{ contains(github.event.pull_request.labels.*.name, 'unflake') }} 92 + env: 93 + NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" 91 94 steps: 92 95 - uses: actions/checkout@v4 93 96 - uses: wimpysworld/nothing-but-nix@main ··· 97 100 set -e -o pipefail 98 101 cd templates/unflake 99 102 sed -i 's/# flake-file = import/flake-file = import/' default.nix 100 - echo "{ inputs, ... }: { unflake.pkgs = import inputs.nixpkgs {}; }" | tee modules/pkgs.nix 101 - nix-shell . -A unflake.env --run 'write-unflake --verbose' 103 + nix-shell . -A flake-file.sh --run 'write-unflake --verbose' 104 + nixlock: 105 + needs: [dev] 106 + name: Check nixlock 107 + runs-on: ubuntu-latest 108 + # if: ${{ contains(github.event.pull_request.labels.*.name, 'unflake') }} 109 + env: 110 + NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" 111 + steps: 112 + - uses: actions/checkout@v4 113 + - uses: wimpysworld/nothing-but-nix@main 114 + - uses: cachix/install-nix-action@v31 115 + - uses: DeterminateSystems/magic-nix-cache-action@main 116 + - run: | 117 + set -e -o pipefail 118 + cd templates/nixlock 119 + sed -i 's/# flake-file = import/flake-file = import/' default.nix 120 + nix-shell . -A flake-file.sh --run write-nixlock 102 121 dev: 103 122 needs: [bootstrap] 104 123 name: Check flake dev
+4 -4
README.md
··· 9 9 <a href="LICENSE"> <img src="https://img.shields.io/github/license/vic/flake-file" alt="License"/> </a> 10 10 </p> 11 11 12 - # Generate `flake.nix`/`unflake.nix`/`npins` from inputs defined as module options. 12 + ### Generate `flake.nix`/`unflake.nix`/`npins`/`nixlock` from inputs defined as module options. 13 13 14 14 > `flake-file` and [vic](https://bsky.app/profile/oeiuwq.bsky.social)'s [dendritic libs](https://dendritic.oeiuwq.com) made for you with Love++ and AI--. If you like my work, consider [sponsoring](https://dendritic.oeiuwq.com/sponsor) 15 15 ··· 23 23 - Your inputs follow a **typed Input Schema**. 24 24 - Your outputs can be defined on a **typed Output Schema**. 25 25 26 - > Despite the original flake-oriented name, it NOW also works on _stable Nix_, non-flakes environments via [npins](templates/npins) or [unflake](templates/unflake). 26 + > Despite the original flake-oriented name, it NOW also works on _stable Nix_, non-flakes environments via [npins](templates/npins), [unflake](templates/unflake), [nixlock](https://codeberg.org/FrdrCkII/nixlock) 27 27 28 28 <table><tr><td> 29 29 30 - ## Features 30 + ### Features 31 31 32 32 - Flake definition aggregated from Nix modules. 33 33 - [Input](https://github.com/vic/flake-file/blob/main/modules/options/default.nix) and Output schemas based on Nix types. ··· 39 39 - Incrementally add [flake-parts-builder](#parts_templates) templates. 40 40 - Pick flakeModules for different feature sets. 41 41 - [Dendritic](https://vic.github.io/dendrix/Dendritic.html) flake template. 42 - - Works on stable Nix, [npins](templates/npins) and [unflake](templates/unflake) environments. 42 + - Works on stable Nix, [npins](templates/npins), [unflake](templates/unflake), [nixlock](templates/nixlock) environments. 43 43 44 44 </td><td> 45 45
+12
dev/_bootstrap-tests.nix
··· 106 106 ''; 107 107 }; 108 108 109 + test-nixlock = pkgs.writeShellApplication { 110 + name = "test-nixlock"; 111 + runtimeInputs = [ 112 + (empty.flake-file.apps.write-nixlock pkgs) 113 + ]; 114 + text = '' 115 + write-nixlock 116 + grep vic/empty-flake/archive ${outdir}/nixlock.lock.nix 117 + ''; 118 + }; 119 + 109 120 in 110 121 pkgs.mkShell { 111 122 buildInputs = [ ··· 115 126 test-npins 116 127 test-npins-follows 117 128 test-npins-transitive 129 + test-nixlock 118 130 ]; 119 131 }
+2 -2
docs/src/content/docs/explanation/what-is-flake-file.mdx
··· 36 36 Even if some people use unstable flakes, others should not be forced out of stable Nix. 37 37 38 38 Each module defines inputs and flake-file can extract to whatever input-locking backend you need. 39 - Be it `flake.nix`, `unflake.nix`, `npins`. 39 + Be it `flake.nix`, `unflake.nix`, `nixlock`, `npins`. 40 40 41 41 ## Everybody `.follows` 42 42 ··· 66 66 67 67 - **Modular:** Each module declares only its own dependencies. 68 68 - **Composable:** Modules can be shared across projects — including their input declarations. 69 - - **Backend-agnostic:** The same module options generate `flake.nix`, `unflake.nix`, or `npins/` depending on the chosen backend. 69 + - **Backend-agnostic:** The same module options generate `flake.nix`, `unflake.nix`, `nixlock` or `npins/` depending on the chosen backend. 70 70 - **Standard Nix:** Uses the Nix module system — `lib.mkDefault`, priority overrides, conditional inputs — all work as expected. 71 71 72 72 ## Real-world Usage
+8 -2
docs/src/content/docs/guides/flake-modules.mdx
··· 78 78 79 79 Defines `flake-file` options for [npins](https://github.com/andir/npins)-based environments. Exposes `write-npins`. Supports `github`, `gitlab`, `channel`, `tarball`, and `git` schemes. Respects `follows` for deduplication. Prunes stale pins automatically. 80 80 81 - Source: [`modules/npins.nix`](https://github.com/vic/flake-file/tree/main/modules/npins.nix) 81 + Source: [`modules/npins`](https://github.com/vic/flake-file/tree/main/modules/npins) 82 82 83 83 ## `flakeModules.unflake` 84 84 85 85 Defines `flake-file` options for [unflake](https://codeberg.org/goldstein/unflake)-based environments. Exposes `write-unflake`. 86 86 87 - Source: [`modules/unflake.nix`](https://github.com/vic/flake-file/tree/main/modules/unflake.nix) 87 + Source: [`modules/unflake`](https://github.com/vic/flake-file/tree/main/modules/unflake) 88 + 89 + ## `flakeModules.nixlock` 90 + 91 + Defines `flake-file` options for [nixlock](https://codeberg.org/FrdrCkII/nixlock)-based environments. Exposes `write-nixlock`. 92 + 93 + Source: [`modules/nixlock`](https://github.com/vic/flake-file/tree/main/modules/nixlock)
+8
docs/src/content/docs/guides/templates.mdx
··· 60 60 nix flake init -t github:vic/flake-file#unflake 61 61 ``` 62 62 63 + ## `nixlock` 64 + 65 + For **non-flake** (stable Nix) environments. Uses [FrdrCkII/nixlock](https://codeberg.org/FrdrCkII/nixlock) to pin inputs. 66 + 67 + ```shell 68 + nix flake init -t github:vic/flake-file#unflake 69 + ``` 70 + 63 71 ## Tips 64 72 65 73 > **Tip:** You can use the `write-flake` app as part of a devshell command or a git pre-commit hook to keep `flake.nix` always up to date.
+1 -1
docs/src/content/docs/index.mdx
··· 55 55 Built-in support for automatic `flake.lock` flattening via `allfollow` or `nix-auto-follow`. 56 56 </Card> 57 57 <Card title="Multiple Backends" icon="setting"> 58 - Generate `flake.nix`, `unflake.nix`, or `npins/` from the same module options. Switch backends without rewriting your modules. 58 + Generate `flake.nix`, `unflake.nix`, `nixlock`, or `npins/` from the same module options. Switch backends without rewriting your modules. 59 59 </Card> 60 60 </CardGrid>
+1 -1
docs/src/content/docs/overview.mdx
··· 44 44 <LinkButton href="/tutorials/migrate-traditional-flake" variant="minimal" icon="right-arrow">Learn More</LinkButton> 45 45 </Card> 46 46 <Card title="Migrate without flakes" icon="pencil"> 47 - Adopt flake-file in a non-flake project using npins or unflake. 47 + Adopt flake-file in a non-flake project using npins, nixlock or unflake. 48 48 <LinkButton href="/tutorials/migrate-no-flakes" variant="minimal" icon="right-arrow">Learn More</LinkButton> 49 49 </Card> 50 50 </CardGrid>
+2 -1
docs/src/content/docs/reference/bootstrap.mdx
··· 5 5 6 6 import { Aside } from '@astrojs/starlight/components'; 7 7 8 - The bootstrap command lets you generate `flake.nix`, `unflake.nix`, or `npins/` from scratch — without being inside an existing flake. 8 + The bootstrap command lets you generate `flake.nix`, `unflake.nix`, `nixlock.lock.nix`, or `npins/` from scratch — without being inside an existing flake. 9 9 10 10 ```shell 11 11 nix-shell https://github.com/vic/flake-file/archive/refs/heads/main.zip \ ··· 21 21 | `write-flake` | Generate a `flake.nix` file | 22 22 | `write-inputs` | Generate an `inputs.nix` expression (for debugging) | 23 23 | `write-unflake` | Generate `unflake.nix` via [unflake](https://codeberg.org/goldstein/unflake) | 24 + | `write-nixlock` | Generate `nixlock.lock.nix` via [nixlock](https://codeberg.org/FrdrCkII/nixlock) | 24 25 | `write-npins` | Generate/update `npins/` directory via [npins](https://github.com/andir/npins) | 25 26 26 27 ## Arguments
+2 -2
docs/src/content/docs/tutorials/bootstrap.mdx
··· 21 21 # Write a minimal flake-file.nix file (or copy a flake.nix of yours) 22 22 echo '{ inputs.flake-file.url = "github:vic/flake-file"; }' > flake-file.nix 23 23 24 - # Generate flake.nix or unflake.nix or npins from flake-file.nix 24 + # Generate flake.nix or unflake.nix or npins or nixlock from flake-file.nix 25 25 nix-shell https://github.com/vic/flake-file/archive/refs/heads/main.zip \ 26 26 -A flake-file.sh --run write-flake --arg modules ./flake-file.nix 27 27 ``` 28 28 29 29 > <small>See also: all [bootstrap command args](/reference/bootstrap)</small> 30 30 31 - Replace `write-flake` with `write-inputs`, `write-unflake`, or `write-npins` to target a different backend. 31 + Replace `write-flake` with `write-inputs`, `write-unflake`, `write-nixlock`, or `write-npins` to target a different backend. 32 32 33 33 34 34 ## Using a modules directory
+1
docs/src/content/docs/tutorials/migrate-no-flakes.mdx
··· 12 12 13 13 flake-file has support 14 14 for [`unflake`](https://codeberg.org/goldstein/unflake) 15 + and [`nixlock`](https://codeberg.org/FrdrCkII/nixlock) 15 16 and [`npins`](https://github.com/andir/npins) 16 17 send PR for others. 17 18
+1
modules/bootstrap/default.nix
··· 40 40 ./../options 41 41 ./../npins 42 42 ./../unflake 43 + ./../nixlock 43 44 ./../write-inputs.nix 44 45 ./../write-flake.nix 45 46 ./../flake-options.nix
+11
modules/default.nix
··· 8 8 import-tree 9 9 npins 10 10 unflake 11 + nixlock 11 12 flake-options 12 13 ; 13 14 }; ··· 27 28 unflake.imports = [ 28 29 base 29 30 ./unflake 31 + ]; 32 + 33 + nixlock.imports = [ 34 + base 35 + ./nixlock 30 36 ]; 31 37 32 38 default.imports = [ ··· 65 71 templates.unflake = { 66 72 description = "unflake template"; 67 73 path = ./../templates/unflake; 74 + }; 75 + 76 + templates.nixlock = { 77 + description = "nixlock template"; 78 + path = ./../templates/nixlock; 68 79 }; 69 80 70 81 templates.dendritic = {
+155
modules/nixlock/default.nix
··· 1 + { lib, config, ... }: 2 + let 3 + inherit (config) flake-file; 4 + inherit (import ../lib.nix lib) inputsExpr; 5 + 6 + inputs = inputsExpr flake-file.inputs; 7 + 8 + nixlock-source = fetchTarball { 9 + url = flake-file.nixlock.url; 10 + sha256 = flake-file.nixlock.sha256; 11 + }; 12 + 13 + nlLibs = (import "${nixlock-source}/${flake-file.nixlock.version}").libs; 14 + 15 + parseGithub = 16 + path: 17 + let 18 + parts = lib.splitString "/" path; 19 + owner = builtins.elemAt parts 0; 20 + repo = builtins.elemAt parts 1; 21 + ref = if builtins.length parts > 2 then builtins.elemAt parts 2 else "HEAD"; 22 + in 23 + { 24 + type = "gitArchive"; 25 + url = "https://github.com/${owner}/${repo}"; 26 + inherit ref; 27 + }; 28 + 29 + parseGitlab = 30 + path: 31 + let 32 + parts = lib.splitString "/" path; 33 + owner = builtins.elemAt parts 0; 34 + repo = builtins.elemAt parts 1; 35 + ref = if builtins.length parts > 2 then builtins.elemAt parts 2 else "HEAD"; 36 + in 37 + { 38 + type = "gitArchive"; 39 + url = "https://gitlab.com/${owner}/${repo}"; 40 + inherit ref; 41 + }; 42 + 43 + flakeUrlToNixlock = 44 + url: 45 + let 46 + scheme = builtins.head (lib.splitString ":" url); 47 + rest = lib.concatStringsSep ":" (builtins.tail (lib.splitString ":" url)); 48 + in 49 + if scheme == "github" then 50 + parseGithub rest 51 + else if scheme == "gitlab" then 52 + parseGitlab rest 53 + else if lib.hasPrefix "git+" url then 54 + { 55 + type = "git"; 56 + url = lib.removePrefix "git+" url; 57 + ref = "HEAD"; 58 + } 59 + else if lib.hasPrefix "http" url then 60 + { 61 + type = "archive"; 62 + inherit url; 63 + } 64 + else 65 + null; 66 + 67 + toNixlockInput = _name: input: if input ? url then flakeUrlToNixlock input.url else null; 68 + 69 + inputsFile = lib.filterAttrs (_: v: v != null) (lib.mapAttrs toNixlockInput inputs); 70 + 71 + lockListFor = 72 + upType: lockFile: 73 + lib.filterAttrs ( 74 + name: value: 75 + !(lockFile ? ${name}) 76 + || value != lockFile.${name}.meta or { } 77 + || (if upType == "update" then !(value.isFreeze or false) else false) 78 + ) inputsFile; 79 + 80 + shellFor = 81 + upType: lockFile: lockFileName: 82 + let 83 + entries = lockListFor upType lockFile; 84 + in 85 + nlLibs.toLockShell { 86 + inherit lockFile lockFileName; 87 + inputsFile = entries; 88 + cmds = lib.concatStringsSep "\n" ( 89 + lib.mapAttrsToList (n: v: nlLibs.types.${v.type}.fresh n v) entries 90 + ); 91 + }; 92 + 93 + write-nixlock = 94 + pkgs: 95 + let 96 + rootPath = flake-file.intoPath; 97 + lockFileName = flake-file.nixlock.lockFileName; 98 + lockScript = shellFor "lock" { } lockFileName; 99 + updateScript = shellFor "update" { } lockFileName; 100 + in 101 + pkgs.writeShellApplication { 102 + name = "write-nixlock"; 103 + excludeShellChecks = [ 104 + "SC2016" 105 + "SC2086" 106 + "SC2089" 107 + "SC2090" 108 + ]; 109 + runtimeInputs = with pkgs; [ 110 + nix 111 + nixfmt 112 + git 113 + nix-prefetch-git 114 + curl 115 + coreutils 116 + gnugrep 117 + gnused 118 + gawk 119 + jq 120 + ]; 121 + text = '' 122 + cd ${rootPath} 123 + case "''${1:-lock}" in 124 + lock) ${lockScript} ;; 125 + update) ${updateScript} ;; 126 + *) echo "usage: write-nixlock [lock|update]" >&2; exit 1 ;; 127 + esac 128 + ''; 129 + }; 130 + in 131 + { 132 + config.flake-file.apps = { inherit write-nixlock; }; 133 + options.flake-file.nixlock = { 134 + url = lib.mkOption { 135 + type = lib.types.str; 136 + description = "nixlock archive url"; 137 + default = "https://codeberg.org/FrdrCkII/nixlock/archive/dad9155634ce5d5183429daaeef2bbf6de9afcbf.tar.gz"; 138 + }; 139 + sha256 = lib.mkOption { 140 + type = lib.types.str; 141 + description = "nixlock archive sha256"; 142 + default = "sha256:0bycgfdar1xcxgbp75r7bpmfvm2qh8206q2h2vsx5qn8fr39x0li"; 143 + }; 144 + version = lib.mkOption { 145 + type = lib.types.str; 146 + description = "nixlock version to load"; 147 + default = "v3"; 148 + }; 149 + lockFileName = lib.mkOption { 150 + type = lib.types.str; 151 + description = "nixlock lockfile name"; 152 + default = "nixlock.lock.nix"; 153 + }; 154 + }; 155 + }
+19
templates/nixlock/README.md
··· 1 + # Nixlock 2 + 3 + This template is an example of using `flake-file.inputs` in a non-flakes project. 4 + 5 + It uses [nixlock](https://codeberg.org/FrdrCkII/nixlock) to pin and fetch inputs defined as options inside `./modules`. 6 + 7 + ## Generate nixlock 8 + 9 + The following command is a convenience for generating `nixlock.lock.nix`: 10 + 11 + ```shell 12 + nix-shell . -A flake-file.sh --run write-nixlock 13 + ``` 14 + 15 + You can also the `update` command. 16 + 17 + ```shell 18 + nix-shell . -A flake-file.sh --run 'write-nixlock update' 19 + ```
+30
templates/nixlock/default.nix
··· 1 + let 2 + outputs = 3 + inputs: 4 + (inputs.nixpkgs.lib.evalModules { 5 + modules = [ (inputs.import-tree ./modules) ]; 6 + specialArgs = { inherit inputs; }; 7 + }).config; 8 + 9 + input-overrides = { 10 + # uncomment for local checkout on CI 11 + # flake-file = import ./../../modules; 12 + }; 13 + 14 + with-inputs = import (fetchTarball { 15 + url = "https://github.com/vic/with-inputs/archive/f19ccc093928f4987ab56534e0de37b25d8f5817.zip"; 16 + sha256 = "sha256:0bcfic6myy2qmyj40kxpxv04hp925l9b0wkd507v69d070qsg285"; 17 + }); 18 + 19 + nixlock-inputs = builtins.mapAttrs ( 20 + _n: v: 21 + v 22 + // { 23 + outPath = fetchTarball { 24 + url = v.lock.url; 25 + sha256 = v.lock.hash; 26 + }; 27 + } 28 + ) (import ./nixlock.lock.nix); 29 + in 30 + with-inputs nixlock-inputs input-overrides outputs
+10
templates/nixlock/modules/default.nix
··· 1 + { inputs, ... }: 2 + { 3 + imports = [ inputs.flake-file.flakeModules.nixlock ]; 4 + 5 + flake-file.inputs = { 6 + flake-file.url = "github:vic/flake-file"; 7 + import-tree.url = "github:vic/import-tree"; 8 + nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 9 + }; 10 + }
+35
templates/nixlock/nixlock.lock.nix
··· 1 + { 2 + "flake-file" = { 3 + "lock" = { 4 + "hash" = "sha256-qIpm5BtK3EkqlGXBG0jCZ3sg3gdxyPxI10iubZwMGFk="; 5 + "url" = "https://github.com/vic/flake-file/archive/8a5c8771ac5be1af11192bcd88e6a1cdabd038a5.tar.gz"; 6 + }; 7 + "meta" = { 8 + "ref" = "HEAD"; 9 + "type" = "gitArchive"; 10 + "url" = "https://github.com/vic/flake-file"; 11 + }; 12 + }; 13 + "import-tree" = { 14 + "lock" = { 15 + "hash" = "sha256-AkfVgWWxt1pa1SlfKzcL1oQpMzgP70U3fBtzXqEGOms="; 16 + "url" = 17 + "https://github.com/vic/import-tree/archive/78c35e32f2b499c25e0671e41662537a6b1edbf0.tar.gz"; 18 + }; 19 + "meta" = { 20 + "ref" = "HEAD"; 21 + "type" = "gitArchive"; 22 + "url" = "https://github.com/vic/import-tree"; 23 + }; 24 + }; 25 + "nixpkgs" = { 26 + "lock" = { 27 + "hash" = "sha256-OgUF+EoJ36hz3jo8qBuizb8suT0mu1n7mzmcGdeOjWE="; 28 + "url" = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 29 + }; 30 + "meta" = { 31 + "type" = "archive"; 32 + "url" = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 33 + }; 34 + }; 35 + }
+15 -17
templates/npins/default.nix
··· 1 1 let 2 2 outputs = 3 3 inputs: 4 - let 5 - nixpkgs = inputs.nixpkgs or (import <nixpkgs> { }); 6 - import-tree = inputs.import-tree or (import <import-tree>); 7 - in 8 - (nixpkgs.lib.evalModules { 9 - modules = [ (import-tree ./modules) ]; 4 + (inputs.nixpkgs.lib.evalModules { 5 + modules = [ (inputs.import-tree ./modules) ]; 10 6 specialArgs = { 11 7 inherit inputs; 12 - self = inputs.self or { }; 8 + self = inputs.self; 13 9 }; 14 10 }).config; 15 11 16 - withInputs = 17 - inputs: outputs: 18 - outputs ( 19 - inputs 20 - // { 21 - # uncomment on CI for local checkout 22 - # flake-file = import ./../../modules; 23 - } 24 - ); 12 + with-inputs = import (builtins.fetchTarball { 13 + url = "https://github.com/vic/with-inputs/archive/f19ccc093928f4987ab56534e0de37b25d8f5817.zip"; 14 + sha256 = "sha256:0bcfic6myy2qmyj40kxpxv04hp925l9b0wkd507v69d070qsg285"; 15 + }); 16 + 17 + inputs-overrides ={ 18 + # uncomment on CI for local checkout 19 + # flake-file = import ./../../modules; 20 + }; 21 + 22 + sources = import ./npins; 25 23 in 26 - import ./with-inputs.nix withInputs outputs 24 + with-inputs sources inputs-overrides outputs
-40
templates/npins/with-inputs.nix
··· 1 - let 2 - hasSources = builtins.pathExists ./npins; 3 - sources = if hasSources then import ./npins else { }; 4 - selfInputs = builtins.mapAttrs (name: value: mkInputs name value) sources; 5 - # from Nixlock: https://codeberg.org/FrdrCkII/nixlock/src/branch/main/default.nix 6 - mkInputs = 7 - name: sourceInfo: 8 - let 9 - flakePath = sourceInfo.outPath + "/flake.nix"; 10 - isFlake = sources.${name}.flake or true; 11 - in 12 - if isFlake && builtins.pathExists flakePath then 13 - let 14 - flake = import (sourceInfo.outPath + "/flake.nix"); 15 - inputs = builtins.mapAttrs (name: _value: selfInputs.${name}) (flake.inputs or { }); 16 - outputs = flake.outputs (inputs // { inherit self; }); 17 - self = 18 - sourceInfo 19 - // outputs 20 - // { 21 - _type = "flake"; 22 - inherit inputs outputs sourceInfo; 23 - }; 24 - in 25 - self 26 - else 27 - sourceInfo 28 - // { 29 - inherit sourceInfo; 30 - }; 31 - in 32 - selfInputs 33 - // { 34 - __functor = 35 - selfInputs: outputs: 36 - let 37 - self = outputs (selfInputs // { inherit self; }); 38 - in 39 - self; 40 - }