Generate flake.nix from module options. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic nix inputs
at main 3.5 kB view raw
1{ 2 lib, 3 config, 4 inputs, 5 ... 6}: 7let 8 inherit (import ./../dev/modules/_lib lib) inputsExpr isNonEmptyString; 9 10 flake-file = config.flake-file; 11 12 template = '' 13 { 14 <description> 15 <outputs> 16 <nixConfig> 17 <inputs> 18 } 19 ''; 20 21 unformatted = lib.pipe template [ 22 (lib.replaceString "<description>" description) 23 (lib.replaceString "<outputs>" outputs) 24 (lib.replaceString "<nixConfig>" nixConfig) 25 (lib.replaceString "<inputs>" flakeInputs) 26 addHeader 27 ]; 28 29 nixAttr = 30 name: value: 31 let 32 childIsAttr = builtins.isAttrs value; 33 childIsOne = builtins.length (builtins.attrNames value) == 1; 34 nested = lib.head (lib.mapAttrsToList nixAttr value); 35 in 36 if childIsAttr && childIsOne then 37 { 38 name = "${name}.${nested.name}"; 39 value = nested.value; 40 } 41 else 42 { 43 inherit name; 44 value = value; 45 }; 46 47 # expr to code 48 nixCode = 49 x: 50 if lib.isStringLike x then 51 lib.strings.escapeNixString x 52 else if lib.isAttrs x then 53 lib.pipe x [ 54 (lib.mapAttrsToList nixAttr) 55 (map ({ name, value }: ''${name} = ${nixCode value}; '')) 56 (values: ''{ ${lib.concatStringsSep " " values} }'') 57 ] 58 else if lib.isList x then 59 lib.pipe x [ 60 (lib.map nixCode) 61 (values: ''[ ${lib.concatStringsSep " " values} ]'') 62 ] 63 else if x == true then 64 "true" 65 else if x == false then 66 "false" 67 else 68 toString x; 69 70 description = 71 if isNonEmptyString flake-file.description then 72 '' 73 description = ${nixCode flake-file.description}; 74 '' 75 else 76 ""; 77 78 outputs = '' 79 outputs = ${flake-file.outputs}; 80 ''; 81 82 nixConfig = 83 if flake-file.nixConfig != { } then 84 '' 85 nixConfig = ${nixCode flake-file.nixConfig}; 86 '' 87 else 88 ""; 89 90 flakeInputs = '' 91 inputs = ${nixCode (inputsExpr flake-file.inputs)}; 92 ''; 93 94 addHeader = 95 code: if isNonEmptyString flake-file.do-not-edit then flake-file.do-not-edit + code else code; 96 97 formatted = 98 pkgs: 99 pkgs.stdenvNoCC.mkDerivation { 100 name = "flake-formatted"; 101 passAsFile = [ "unformatted" ]; 102 inherit unformatted; 103 phases = [ "format" ]; 104 format = '' 105 cp $unformattedPath flake.nix 106 ${pkgs.lib.getExe (flake-file.formatter pkgs)} flake.nix 107 cp flake.nix $out 108 ''; 109 }; 110 111in 112{ 113 config.perSystem = 114 { pkgs, ... }: 115 { 116 packages.write-flake = 117 let 118 hooks = lib.pipe config.flake-file.write-hooks [ 119 (lib.sortOn (i: i.index)) 120 (map (i: pkgs.lib.getExe (i.program pkgs))) 121 (lib.concatStringsSep "\n") 122 ]; 123 in 124 pkgs.writeShellApplication { 125 name = "write-flake"; 126 text = '' 127 cp ${formatted pkgs} flake.nix 128 ${hooks} 129 ''; 130 }; 131 132 checks.check-flake-file = 133 let 134 hooks = lib.pipe config.flake-file.check-hooks [ 135 (lib.sortOn (i: i.index)) 136 (map (i: pkgs.lib.getExe (i.program pkgs))) 137 (map (p: "${p} ${inputs.self}")) 138 (lib.concatStringsSep "\n") 139 ]; 140 in 141 pkgs.runCommand "check-flake-file" 142 { 143 nativeBuildInputs = [ pkgs.diffutils ]; 144 } 145 '' 146 set -e 147 diff -u ${inputs.self}/flake.nix ${formatted pkgs} 148 ${hooks} 149 touch $out 150 ''; 151 152 }; 153 154}