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

Add default.nix for bootstrapping (#66)

* show npins command on failure to help diagnose

* default.nix

authored by oeiuwq.com and committed by

GitHub cbc6d74f 223a7f3b

+273 -150
+23
.github/workflows/flake-check.yaml
··· 16 16 templates=$(find templates -mindepth 2 -maxdepth 2 -name flake.nix -print0 | xargs -0 dirname | xargs -n 1 basename | jq -R | jq -sc) 17 17 echo "$templates" 18 18 echo "templates=$templates" >> $GITHUB_OUTPUT 19 + bootstrap: 20 + name: Bootstrap ${{matrix.bootstrap}} 21 + runs-on: ubuntu-latest 22 + strategy: 23 + matrix: 24 + bootstrap: [inputs, flake, npins, unflake] 25 + env: 26 + NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" 27 + steps: 28 + - uses: wimpysworld/nothing-but-nix@main 29 + - uses: cachix/install-nix-action@v31 30 + - uses: DeterminateSystems/magic-nix-cache-action@main 31 + - uses: actions/checkout@v4 32 + - run: mkdir bootstrap 33 + - run: cd bootstrap && nix-shell ../default.nix -A flake-file.sh --run write-${{matrix.bootstrap}} --arg modules ../modules/bootstrap.nix 34 + - run: cat bootstrap/inputs.nix 35 + if: ${{ matrix.bootstrap == 'inputs' }} 36 + - run: cat bootstrap/flake.nix 37 + if: ${{ matrix.bootstrap == 'flake' }} 38 + - run: cat bootstrap/unflake.nix 39 + if: ${{ matrix.bootstrap == 'unflake' }} 40 + - run: cat bootstrap/npins/sources.json 41 + if: ${{ matrix.bootstrap == 'npins' }} 19 42 template: 20 43 name: Check template ${{matrix.template}} 21 44 needs: [find-templates]
+14
README.md
··· 403 403 404 404 --- 405 405 406 + ## Bootstrapping 407 + 408 + You can generate `flake.nix`, `inputs.nix`, `unflake.nix` or `npins` by using the following command: 409 + 410 + ```shell 411 + # create a bootstrap module. add any dependencies you want 412 + echo '{ flake-file.inputs.flake-file.url = "github:vic/flake-file"; }' > bootstrap.nix # filename is not important 413 + 414 + # replace write-flake with: write-inputs / write-unflake / write-npins 415 + nix-shell https://github.com/vic/flake-file/archive/refs/heads/main.zip -A flake-file.sh --run write-flake --arg modules ./bootstrap.nix 416 + ``` 417 + 418 + `bootstrap.nix` can also be a `./modules` directory that will be auto-imported using import-tree. 419 + 406 420 ## Development 407 421 408 422 Use `nix develop ./dev` or with direnv: `use flake ./dev`.
+48
default.nix
··· 1 + { 2 + pkgs ? import <nixpkgs> { }, 3 + modules ? [ ], 4 + import-tree ? ( 5 + pkgs.fetchFromGitHub { 6 + owner = "vic"; 7 + repo = "import-tree"; 8 + rev = "c968d3b54d12cf5d9c13f16f7c545a06c9d1fde6"; 9 + hash = "sha256-oYO4poyw0Sb/db2PigqugMlDwsvwLg6CSpFrMUWxA3Q="; 10 + } 11 + ), 12 + ... 13 + }: 14 + let 15 + inherit (pkgs) lib; 16 + 17 + tree = (import import-tree) modules; 18 + 19 + attrsOpt = lib.mkOption { 20 + default = { }; 21 + type = lib.types.submodule { freeformType = lib.types.lazyAttrsOf lib.types.unspecified; }; 22 + }; 23 + 24 + module = { 25 + imports = [ 26 + tree 27 + ./modules 28 + ./modules/options 29 + ./modules/npins.nix 30 + ./modules/unflake.nix 31 + ./modules/write-inputs.nix 32 + ./modules/write-flake.nix 33 + ]; 34 + options = { 35 + lib = attrsOpt; 36 + templates = attrsOpt; 37 + flakeModules = attrsOpt; 38 + }; 39 + }; 40 + 41 + outputs = 42 + (lib.evalModules { 43 + modules = [ module ]; 44 + specialArgs.inputs.self.outPath = ""; 45 + }).config; 46 + 47 + in 48 + outputs
+6
modules/bootstrap.nix
··· 1 + { 2 + flake-file.inputs = { 3 + impor-tree.url = "github:vic/import-tree"; 4 + flake-file.url = "github:vic/flake-file"; 5 + }; 6 + }
+9 -3
modules/default.nix
··· 11 11 ; 12 12 }; 13 13 14 - npins.imports = [ 14 + base.imports = [ 15 15 ./options 16 + ./write-inputs.nix 17 + ]; 18 + 19 + npins.imports = [ 20 + base 16 21 ./npins.nix 17 22 ]; 18 23 19 24 unflake.imports = [ 20 - ./options 25 + base 21 26 ./unflake.nix 22 27 ]; 23 28 24 29 default.imports = [ 25 - ./options 30 + base 26 31 ./write-flake.nix 32 + ./flake-parts.nix 27 33 ]; 28 34 29 35 allfollow.imports = [ ./prune-lock/allfollow.nix ];
+9
modules/flake-parts.nix
··· 1 + { config, lib, ... }: 2 + { 3 + perSystem = 4 + { pkgs, ... }: 5 + { 6 + packages = lib.mapAttrs (_: f: f pkgs) config.flake-file.apps; 7 + checks.check-flake-file = config.flake-file.check-flake-file pkgs; 8 + }; 9 + }
+32 -46
modules/npins.nix
··· 1 1 { lib, config, ... }: 2 2 let 3 - inherit (config.npins) pkgs; 3 + inherit (config) flake-file; 4 + 5 + inherit (import ./../dev/modules/_lib lib) inputsExpr; 6 + 7 + inputs = inputsExpr flake-file.inputs; 4 8 5 9 parseFlakeUrl = 6 10 url: ··· 101 105 acc // (transitiveInputs name input) 102 106 ) { }; 103 107 104 - pinnableInputs = lib.filterAttrs (_: v: v.url or "" != "") config.flake-file.inputs; 108 + pinnableInputs = lib.filterAttrs (_: v: v.url or "" != "") inputs; 105 109 106 - allTransitive = collectTransitive config.flake-file.inputs; 110 + allTransitive = collectTransitive inputs; 107 111 108 112 pinnableTransitive = lib.filterAttrs (_: v: v.url or "" != "") allTransitive; 109 113 ··· 124 128 125 129 pinNames = lib.concatStringsSep " " (lib.attrNames allPins); 126 130 127 - write-npins = pkgs.writeShellApplication { 128 - name = "write-npins"; 129 - runtimeInputs = [ 130 - pkgs.npins 131 - pkgs.jq 132 - ]; 133 - text = '' 134 - npins init --bare 2>/dev/null || true 135 - ${addCommands} 136 - wanted="${pinNames}" 137 - if [ -f npins/sources.json ]; then 138 - for existing in $(jq -r '.pins | keys[]' npins/sources.json); do 139 - keep=false 140 - for w in $wanted; do 141 - if [ "$existing" = "$w" ]; then keep=true; break; fi 131 + write-npins = 132 + pkgs: 133 + pkgs.writeShellApplication { 134 + name = "write-npins"; 135 + runtimeInputs = [ 136 + pkgs.npins 137 + pkgs.jq 138 + ]; 139 + text = '' 140 + npins init --bare 2>/dev/null || true 141 + ${addCommands} 142 + wanted="${pinNames}" 143 + if [ -f npins/sources.json ]; then 144 + for existing in $(jq -r '.pins | keys[]' npins/sources.json); do 145 + keep=false 146 + for w in $wanted; do 147 + if [ "$existing" = "$w" ]; then keep=true; break; fi 148 + done 149 + if [ "$keep" = false ]; then 150 + npins remove "$existing" 151 + fi 142 152 done 143 - if [ "$keep" = false ]; then 144 - npins remove "$existing" 145 - fi 146 - done 147 - fi 148 - ''; 149 - }; 150 - 151 - env = pkgs.mkShell { 152 - buildInputs = [ 153 - pkgs.npins 154 - write-npins 155 - ]; 156 - }; 153 + fi 154 + ''; 155 + }; 157 156 in 158 157 { 159 - options.npins = { 160 - pkgs = lib.mkOption { 161 - type = lib.types.raw; 162 - description = "nixpkgs instance for npins generator"; 163 - default = import <nixpkgs> { }; 164 - }; 165 - 166 - env = lib.mkOption { 167 - type = lib.types.raw; 168 - readOnly = true; 169 - internal = true; 170 - default = env; 171 - }; 172 - }; 158 + config.flake-file.apps = { inherit write-npins; }; 173 159 }
+11 -53
modules/unflake.nix
··· 1 1 { lib, config, ... }: 2 2 let 3 - inherit (config.unflake) pkgs; 4 - inherit (import ./../dev/modules/_lib lib) inputsExpr nixCode; 5 - 6 - inputsString = '' 7 - # DO-NOT-EDIT: Generated by github:vic/flake-file for unflake. 8 - # To re-generate use: nix-shell . -A unflake.env --run write-inputs 9 - '' 10 - + (nixCode (inputsExpr config.flake-file.inputs)); 11 - 12 - inputsFile = pkgs.stdenvNoCC.mkDerivation { 13 - name = "inputs"; 14 - passAsFile = [ "inputsString" ]; 15 - inherit inputsString; 16 - phases = [ "copy" ]; 17 - copy = '' 18 - cp $inputsStringPath $out 19 - ''; 20 - }; 21 - 22 - write-inputs = pkgs.writeShellApplication { 23 - name = "write-inputs"; 24 - text = '' 25 - cp ${inputsFile} "''${1:-inputs.nix}" 26 - ${lib.getExe pkgs.nixfmt} "''${1:-inputs.nix}" 27 - ''; 28 - }; 29 - 30 - write-unflake = pkgs.writeShellApplication { 31 - name = "write-unflake"; 32 - text = '' 33 - nix-shell "${config.unflake.url}" -A unflake-shell --run "unflake -i ${inputsFile} $*" 34 - ''; 35 - }; 3 + inherit (config) flake-file; 36 4 37 - env = pkgs.mkShell { 38 - buildInputs = [ 39 - write-inputs 40 - write-unflake 41 - ]; 42 - }; 5 + write-unflake = 6 + pkgs: 7 + pkgs.writeShellApplication { 8 + name = "write-unflake"; 9 + text = '' 10 + nix-shell "${flake-file.unflake.url}" -A unflake-shell --run "unflake -i ${flake-file.inputsFile pkgs} $*" 11 + ''; 12 + }; 43 13 in 44 14 { 45 - options.unflake = { 15 + config.flake-file.apps = { inherit write-unflake; }; 16 + options.flake-file.unflake = { 46 17 url = lib.mkOption { 47 18 type = lib.types.str; 48 19 description = "unflake archive url"; 49 20 default = "https://codeberg.org/goldstein/unflake/archive/main.tar.gz"; 50 - }; 51 - 52 - pkgs = lib.mkOption { 53 - type = lib.types.raw; 54 - description = "nixpkgs instance for unflake generator"; 55 - default = import <nixpkgs> { }; 56 - }; 57 - 58 - env = lib.mkOption { 59 - type = lib.types.raw; 60 - readOnly = true; 61 - internal = true; 62 - default = env; 63 21 }; 64 22 }; 65 23 }
+45 -43
modules/write-flake.nix
··· 2 2 lib, 3 3 options, 4 4 config, 5 - inputs, 6 5 ... 7 - }: 6 + }@top: 8 7 let 9 8 inherit (import ./../dev/modules/_lib lib) inputsExpr isNonEmptyString nixCode; 10 9 ··· 75 74 ''; 76 75 }; 77 76 77 + write-flake = 78 + pkgs: 79 + let 80 + hooks = lib.pipe config.flake-file.write-hooks [ 81 + (lib.sortOn (i: i.index)) 82 + (map (i: pkgs.lib.getExe (i.program pkgs))) 83 + (lib.concatStringsSep "\n") 84 + ]; 85 + in 86 + pkgs.writeShellApplication { 87 + name = "write-flake"; 88 + text = '' 89 + cp ${formatted pkgs} flake.nix 90 + ${hooks} 91 + ''; 92 + }; 93 + 94 + check-flake-file = 95 + pkgs: 96 + let 97 + hooks = lib.pipe config.flake-file.check-hooks [ 98 + (lib.sortOn (i: i.index)) 99 + (map (i: pkgs.lib.getExe (i.program pkgs))) 100 + (map (p: "${p} ${top.inputs.self}")) 101 + (lib.concatStringsSep "\n") 102 + ]; 103 + in 104 + pkgs.runCommand "check-flake-file" 105 + { 106 + nativeBuildInputs = [ pkgs.diffutils ]; 107 + } 108 + '' 109 + set -e 110 + diff -u ${top.inputs.self}/flake.nix ${formatted pkgs} 111 + ${hooks} 112 + touch $out 113 + ''; 78 114 in 79 115 { 80 - config.perSystem = 81 - { pkgs, ... }: 82 - { 83 - packages.write-flake = 84 - let 85 - hooks = lib.pipe config.flake-file.write-hooks [ 86 - (lib.sortOn (i: i.index)) 87 - (map (i: pkgs.lib.getExe (i.program pkgs))) 88 - (lib.concatStringsSep "\n") 89 - ]; 90 - in 91 - pkgs.writeShellApplication { 92 - name = "write-flake"; 93 - text = '' 94 - cp ${formatted pkgs} flake.nix 95 - ${hooks} 96 - ''; 97 - }; 98 - 99 - checks.check-flake-file = 100 - let 101 - hooks = lib.pipe config.flake-file.check-hooks [ 102 - (lib.sortOn (i: i.index)) 103 - (map (i: pkgs.lib.getExe (i.program pkgs))) 104 - (map (p: "${p} ${inputs.self}")) 105 - (lib.concatStringsSep "\n") 106 - ]; 107 - in 108 - pkgs.runCommand "check-flake-file" 109 - { 110 - nativeBuildInputs = [ pkgs.diffutils ]; 111 - } 112 - '' 113 - set -e 114 - diff -u ${inputs.self}/flake.nix ${formatted pkgs} 115 - ${hooks} 116 - touch $out 117 - ''; 118 - 119 - }; 120 - 116 + config.flake-file.apps = { inherit write-flake; }; 117 + options.flake-file.check-flake-file = lib.mkOption { 118 + default = check-flake-file; 119 + readOnly = true; 120 + visible = false; 121 + internal = true; 122 + }; 121 123 }
+71
modules/write-inputs.nix
··· 1 + { lib, config, ... }: 2 + let 3 + inherit (config) flake-file; 4 + 5 + inherit (import ./../dev/modules/_lib lib) inputsExpr nixCode; 6 + 7 + inputsString = '' 8 + # DO-NOT-EDIT: Generated by github:vic/flake-file. 9 + # To re-generate use: nix-shell . -A flake-file.sh --run write-inputs 10 + '' 11 + + (nixCode (inputsExpr flake-file.inputs)); 12 + 13 + inputsFile = 14 + pkgs: 15 + pkgs.stdenvNoCC.mkDerivation { 16 + name = "inputs"; 17 + passAsFile = [ "inputsString" ]; 18 + inherit inputsString; 19 + phases = [ "copy" ]; 20 + copy = '' 21 + cp $inputsStringPath $out 22 + ''; 23 + }; 24 + 25 + write-inputs = 26 + pkgs: 27 + pkgs.writeShellApplication { 28 + name = "write-inputs"; 29 + text = '' 30 + cp ${inputsFile pkgs} "''${1:-inputs.nix}" 31 + ${lib.getExe pkgs.nixfmt} "''${1:-inputs.nix}" 32 + ''; 33 + }; 34 + 35 + shell = 36 + pkgs: 37 + pkgs.mkShell { 38 + buildInputs = map (f: f pkgs) (lib.attrValues flake-file.apps); 39 + }; 40 + in 41 + { 42 + config.flake-file.apps = { inherit write-inputs; }; 43 + 44 + options.flake-file = { 45 + pkgs = lib.mkOption { 46 + type = lib.types.raw; 47 + description = "nixpkgs instance for unflake generator"; 48 + default = import <nixpkgs> { }; 49 + }; 50 + 51 + apps = lib.mkOption { 52 + type = lib.types.lazyAttrsOf (lib.types.functionTo lib.types.package); 53 + default = { }; 54 + description = "Attrs of (pkgs -> app) to include in shell"; 55 + }; 56 + 57 + inputsFile = lib.mkOption { 58 + type = lib.types.raw; 59 + readOnly = true; 60 + internal = true; 61 + default = inputsFile; 62 + }; 63 + 64 + sh = lib.mkOption { 65 + type = lib.types.raw; 66 + readOnly = true; 67 + internal = true; 68 + default = shell flake-file.pkgs; 69 + }; 70 + }; 71 + }
+1 -1
templates/npins/README.md
··· 10 10 Update the `npins/` directory from your declared inputs: 11 11 12 12 ```shell 13 - nix-shell . -A npins.env --run write-npins 13 + nix-shell . -A flake-file.sh --run write-npins 14 14 ``` 15 15 16 16 This will run `npins add` for
+4 -4
templates/unflake/README.md
··· 11 11 running unflake on it. 12 12 13 13 ```shell 14 - nix-shell . -A unflake.env --run write-unflake 14 + nix-shell . -A flake-file.sh --run write-unflake 15 15 ``` 16 16 17 17 You can also pass any unflake option: 18 18 19 19 ```shell 20 - nix-shell . -A unflake.env --run 'write-unflake --verbose --backend nix' 20 + nix-shell . -A flake-file.sh --run 'write-unflake --verbose --backend nix' 21 21 ``` 22 22 23 23 If you need to see the file that is being passed as `--inputs inputs.nix` ··· 25 25 26 26 ```shell 27 27 # (only recommended for debugging) 28 - nix-shell . -A unflake.env --run write-inputs 28 + nix-shell . -A flake-file.sh --run write-inputs 29 29 30 30 # then, you can run unflake yourself: 31 31 nix-shell https://ln-s.sh/unflake -A unflake-shell --run unflake ··· 36 36 Unflake has an npins backend to use it run: 37 37 38 38 ```shell 39 - nix-shell . -A unflake.env --run 'write-unflake --backend npins' 39 + nix-shell . -A flake-file.sh --run 'write-unflake --backend npins' 40 40 ```